From 8db11e6a0a22d6344d87f01536c60c527ca28200 Mon Sep 17 00:00:00 2001 From: Mateusz Sierszulski Date: Wed, 30 Aug 2023 12:34:56 +0200 Subject: [PATCH] drivers: spi: Add Ambiq MSPI driver This commit adds MSPI driver for Apollo4 SoCs. Signed-off-by: Mateusz Sierszulski --- drivers/spi/CMakeLists.txt | 1 + drivers/spi/Kconfig.ambiq | 9 ++ drivers/spi/mspi_ambiq.c | 253 +++++++++++++++++++++++++++++++ dts/bindings/spi/ambiq,mspi.yaml | 18 +++ modules/hal_ambiq/Kconfig | 5 + west.yml | 2 +- 6 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 drivers/spi/mspi_ambiq.c create mode 100644 dts/bindings/spi/ambiq,mspi.yaml diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index b9b2cd814f..0eaea3714b 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -43,6 +43,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_OPENTITAN spi_opentitan.c) zephyr_library_sources_ifdef(CONFIG_SPI_NUMAKER spi_numaker.c) zephyr_library_sources_ifdef(CONFIG_SPI_AMBIQ spi_ambiq.c) zephyr_library_sources_ifdef(CONFIG_SPI_RPI_PICO_PIO spi_rpi_pico_pio.c) +zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ mspi_ambiq.c) zephyr_library_sources_ifdef(CONFIG_SPI_RTIO spi_rtio.c) zephyr_library_sources_ifdef(CONFIG_SPI_ASYNC spi_signal.c) diff --git a/drivers/spi/Kconfig.ambiq b/drivers/spi/Kconfig.ambiq index 130b657513..15eaf7463a 100644 --- a/drivers/spi/Kconfig.ambiq +++ b/drivers/spi/Kconfig.ambiq @@ -13,3 +13,12 @@ config SPI_AMBIQ select AMBIQ_HAL_USE_SPI help Enable driver for Ambiq SPI. + +config MSPI_AMBIQ + bool "AMBIQ MSPI driver" + default y + depends on DT_HAS_AMBIQ_MSPI_ENABLED + select AMBIQ_HAL + select AMBIQ_HAL_USE_MSPI + help + Enable driver for Ambiq MSPI. diff --git a/drivers/spi/mspi_ambiq.c b/drivers/spi/mspi_ambiq.c new file mode 100644 index 0000000000..03ad8b2c0a --- /dev/null +++ b/drivers/spi/mspi_ambiq.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2023 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ambiq_mspi + +#include +LOG_MODULE_REGISTER(mspi_ambiq); + +#include +#include +#include + +#include "spi_context.h" +#include + +#define SPI_WORD_SIZE 8 +#define MSPI_MAX_FREQ 96000000 +#define MSPI_TIMEOUT_US 1000000 +#define PWRCTRL_MAX_WAIT_US 5 +#define MSPI_BUSY BIT(2) + +typedef int (*ambiq_mspi_pwr_func_t)(void); + +struct mspi_ambiq_config { + uint32_t base; + int size; + uint32_t clock_freq; + const struct pinctrl_dev_config *pcfg; + ambiq_mspi_pwr_func_t pwr_func; +}; + +struct mspi_ambiq_data { + struct spi_context ctx; + void *mspiHandle; + am_hal_mspi_dev_config_t mspicfg; +}; + +static int mspi_set_freq(uint32_t freq) +{ + uint32_t d = MSPI_MAX_FREQ / freq; + + switch (d) { + case AM_HAL_MSPI_CLK_96MHZ: + case AM_HAL_MSPI_CLK_48MHZ: + case AM_HAL_MSPI_CLK_32MHZ: + case AM_HAL_MSPI_CLK_24MHZ: + case AM_HAL_MSPI_CLK_16MHZ: + case AM_HAL_MSPI_CLK_12MHZ: + case AM_HAL_MSPI_CLK_8MHZ: + case AM_HAL_MSPI_CLK_6MHZ: + case AM_HAL_MSPI_CLK_4MHZ: + case AM_HAL_MSPI_CLK_3MHZ: + break; + default: + LOG_ERR("Frequency not supported!"); + d = AM_HAL_MSPI_CLK_INVALID; + break; + } + + return d; +} + +static int mspi_config(const struct device *dev, const struct spi_config *config) +{ + struct mspi_ambiq_data *data = dev->data; + int ret; + am_hal_mspi_dev_config_t mspicfg = {0}; + + if (config->operation & SPI_HALF_DUPLEX) { + LOG_ERR("Half-duplex not supported"); + return -ENOTSUP; + } + + if (SPI_WORD_SIZE_GET(config->operation) != 8) { + LOG_ERR("Word size must be %d", SPI_WORD_SIZE); + return -ENOTSUP; + } + + if ((config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_ERR("Only single mode is currently supported"); + return -ENOTSUP; + } + + if (config->operation & SPI_LOCK_ON) { + LOG_ERR("Lock On not supported"); + return -ENOTSUP; + } + + if (config->operation & SPI_TRANSFER_LSB) { + LOG_ERR("LSB first not supported"); + return -ENOTSUP; + } + + if (config->operation & (SPI_MODE_CPOL | SPI_MODE_CPHA)) { + if (config->operation & (SPI_MODE_CPOL && SPI_MODE_CPHA)) { + mspicfg.eSpiMode = AM_HAL_MSPI_SPI_MODE_3; + } else if (config->operation & SPI_MODE_CPOL) { + mspicfg.eSpiMode = AM_HAL_MSPI_SPI_MODE_2; + } else if (config->operation & SPI_MODE_CPHA) { + mspicfg.eSpiMode = AM_HAL_MSPI_SPI_MODE_1; + } else { + mspicfg.eSpiMode = AM_HAL_MSPI_SPI_MODE_0; + } + } + + mspicfg.eClockFreq = mspi_set_freq(config->frequency); + if (mspicfg.eClockFreq == AM_HAL_MSPI_CLK_INVALID) { + return -ENOTSUP; + } + + mspicfg.eDeviceConfig = AM_HAL_MSPI_FLASH_SERIAL_CE0; + + ret = am_hal_mspi_disable(data->mspiHandle); + if (ret) { + return ret; + } + + ret = am_hal_mspi_device_configure(data->mspiHandle, &mspicfg); + if (ret) { + return ret; + } + + ret = am_hal_mspi_enable(data->mspiHandle); + + + return ret; +} + +static int mspi_ambiq_xfer(const struct device *dev, const struct spi_config *config) +{ + struct mspi_ambiq_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + int ret; + + am_hal_mspi_pio_transfer_t trans = {0}; + + trans.bSendAddr = true; + trans.bSendInstr = true; + trans.ui16DeviceInstr = *ctx->tx_buf; + spi_context_update_tx(ctx, 1, 1); + trans.ui32DeviceAddr = *ctx->tx_buf; + + if (ctx->rx_buf != NULL) { + spi_context_update_rx(ctx, 1, ctx->rx_len); + trans.eDirection = AM_HAL_MSPI_RX; + trans.pui32Buffer = (uint32_t *)ctx->rx_buf; + trans.ui32NumBytes = ctx->rx_len; + + } else if (ctx->tx_buf != NULL) { + spi_context_update_tx(ctx, 1, 1); + trans.eDirection = AM_HAL_MSPI_TX; + trans.pui32Buffer = (uint32_t *)ctx->tx_buf; + trans.ui32NumBytes = ctx->tx_len; + } + + ret = am_hal_mspi_blocking_transfer(data->mspiHandle, &trans, MSPI_TIMEOUT_US); + + spi_context_complete(ctx, dev, 0); + + return ret; +} + +static int mspi_ambiq_transceive(const struct device *dev, const struct spi_config *config, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + struct mspi_ambiq_data *data = dev->data; + + int ret = mspi_config(dev, config); + + if (ret) { + return ret; + } + + if (!tx_bufs && !rx_bufs) { + return 0; + } + + spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1); + + ret = mspi_ambiq_xfer(dev, config); + + return ret; +} + +static int mspi_ambiq_release(const struct device *dev, const struct spi_config *config) +{ + const struct mspi_ambiq_config *cfg = dev->config; + + if (sys_read32(cfg->base) & MSPI_BUSY) { + return -EBUSY; + } + + return 0; +} + +static struct spi_driver_api mspi_ambiq_driver_api = { + .transceive = mspi_ambiq_transceive, + .release = mspi_ambiq_release, +}; + +static int mspi_ambiq_init(const struct device *dev) +{ + struct mspi_ambiq_data *data = dev->data; + const struct mspi_ambiq_config *cfg = dev->config; + am_hal_mspi_config_t mspiCfg = {0}; + + mspiCfg.pTCB = NULL; + + int ret = am_hal_mspi_initialize((cfg->base - REG_MSPI_BASEADDR) / (cfg->size * 4), + &data->mspiHandle); + if (ret) { + return ret; + } + + ret = cfg->pwr_func(); + + ret = am_hal_mspi_configure(data->mspiHandle, &mspiCfg); + if (ret) { + return ret; + } + + ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + + return ret; +} + +#define AMBIQ_MSPI_DEFINE(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + static int pwr_on_ambiq_mspi_##n(void) \ + { \ + uint32_t addr = DT_REG_ADDR(DT_INST_PHANDLE(n, ambiq_pwrcfg)) + \ + DT_INST_PHA(n, ambiq_pwrcfg, offset); \ + sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \ + k_busy_wait(PWRCTRL_MAX_WAIT_US); \ + return 0; \ + } \ + static struct mspi_ambiq_data mspi_ambiq_data##n = { \ + SPI_CONTEXT_INIT_SYNC(mspi_ambiq_data##n, ctx)}; \ + static const struct mspi_ambiq_config mspi_ambiq_config##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .size = DT_INST_REG_SIZE(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .pwr_func = pwr_on_ambiq_mspi_##n, \ + }; \ + DEVICE_DT_INST_DEFINE(n, mspi_ambiq_init, NULL, &mspi_ambiq_data##n, \ + &mspi_ambiq_config##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ + &mspi_ambiq_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(AMBIQ_MSPI_DEFINE) diff --git a/dts/bindings/spi/ambiq,mspi.yaml b/dts/bindings/spi/ambiq,mspi.yaml new file mode 100644 index 0000000000..0c48f6605e --- /dev/null +++ b/dts/bindings/spi/ambiq,mspi.yaml @@ -0,0 +1,18 @@ +# Copyright (c) 2023 Antmicro +# SPDX-License-Identifier: Apache-2.0 + +description: Ambiq MSPI + +compatible: "ambiq,mspi" + +include: [spi-controller.yaml, pinctrl-device.yaml, ambiq-pwrcfg.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + ambiq,pwrcfg: + required: true diff --git a/modules/hal_ambiq/Kconfig b/modules/hal_ambiq/Kconfig index b6029f0592..28c19e9a58 100644 --- a/modules/hal_ambiq/Kconfig +++ b/modules/hal_ambiq/Kconfig @@ -40,4 +40,9 @@ config AMBIQ_HAL_USE_SPI help Use the SPI driver from Ambiq HAL +config AMBIQ_HAL_USE_MSPI + bool + help + Use the MSPI driver from Ambiq HAL + endif # AMBIQ_HAL diff --git a/west.yml b/west.yml index 71f54a88d0..da27a1bc4d 100644 --- a/west.yml +++ b/west.yml @@ -142,7 +142,7 @@ manifest: groups: - hal - name: hal_ambiq - revision: fbb1618df8b0946cc2abea817309dc85fe051c21 + revision: 0e15e4becd49c40cb054672d9525eccfe98b440f path: modules/hal/ambiq groups: - hal