/* * Copyright (c) 2024, Ambiq Micro Inc. * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT ambiq_mspi_controller #include #include LOG_MODULE_REGISTER(mspi_ambiq_ap3); #include #include #include #include #include #include #include #include #include "mspi_ambiq.h" #define MSPI_MAX_FREQ 48000000 #define MSPI_MAX_DEVICE 2 #define MSPI_TIMEOUT_US 1000000 #define PWRCTRL_MAX_WAIT_US 5 #define MSPI_BUSY BIT(2) typedef int (*mspi_ambiq_pwr_func_t)(void); typedef void (*irq_config_func_t)(void); struct mspi_context { const struct mspi_dev_id *owner; struct mspi_xfer xfer; int packets_left; int packets_done; mspi_callback_handler_t callback; struct mspi_callback_context *callback_ctx; bool asynchronous; struct k_sem lock; }; struct mspi_ambiq_config { uint32_t reg_base; uint32_t reg_size; struct mspi_cfg mspicfg; const struct pinctrl_dev_config *pcfg; irq_config_func_t irq_cfg_func; LOG_INSTANCE_PTR_DECLARE(log); }; struct mspi_ambiq_data { void *mspiHandle; am_hal_mspi_dev_config_t hal_dev_cfg; struct mspi_dev_id *dev_id; struct k_mutex lock; struct mspi_dev_cfg dev_cfg; struct mspi_xip_cfg xip_cfg; struct mspi_scramble_cfg scramble_cfg; mspi_callback_handler_t cbs[MSPI_BUS_EVENT_MAX]; struct mspi_callback_context *cb_ctxs[MSPI_BUS_EVENT_MAX]; struct mspi_context ctx; }; static int mspi_set_freq(const struct mspi_ambiq_config *cfg, uint32_t freq) { uint32_t d = MSPI_MAX_FREQ / freq; switch (d) { case AM_HAL_MSPI_CLK_48MHZ: 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_INST_ERR(cfg->log, "%u,Frequency not supported!", __LINE__); d = 0; break; } return d; } static am_hal_mspi_device_e mspi_set_line(const struct mspi_ambiq_config *cfg, enum mspi_io_mode io_mode, enum mspi_data_rate data_rate, uint8_t ce_num) { if (data_rate != MSPI_DATA_RATE_SINGLE) { LOG_INST_ERR(cfg->log, "%u, incorrect data rate, only SDR is supported.", __LINE__); return AM_HAL_MSPI_FLASH_MAX; } if (ce_num == 0) { switch (io_mode) { case MSPI_IO_MODE_SINGLE: return AM_HAL_MSPI_FLASH_SERIAL_CE0; case MSPI_IO_MODE_DUAL: return AM_HAL_MSPI_FLASH_DUAL_CE0; case MSPI_IO_MODE_DUAL_1_1_2: return AM_HAL_MSPI_FLASH_DUAL_CE0_1_1_2; case MSPI_IO_MODE_DUAL_1_2_2: return AM_HAL_MSPI_FLASH_DUAL_CE0_1_2_2; case MSPI_IO_MODE_QUAD: return AM_HAL_MSPI_FLASH_QUAD_CE0; case MSPI_IO_MODE_QUAD_1_1_4: return AM_HAL_MSPI_FLASH_QUAD_CE0_1_1_4; case MSPI_IO_MODE_QUAD_1_4_4: return AM_HAL_MSPI_FLASH_QUAD_CE0_1_4_4; case MSPI_IO_MODE_OCTAL: return AM_HAL_MSPI_FLASH_OCTAL_CE0; default: return AM_HAL_MSPI_FLASH_MAX; } } else if (ce_num == 1) { switch (io_mode) { case MSPI_IO_MODE_SINGLE: return AM_HAL_MSPI_FLASH_SERIAL_CE1; case MSPI_IO_MODE_DUAL: return AM_HAL_MSPI_FLASH_DUAL_CE1; case MSPI_IO_MODE_DUAL_1_1_2: return AM_HAL_MSPI_FLASH_DUAL_CE1_1_1_2; case MSPI_IO_MODE_DUAL_1_2_2: return AM_HAL_MSPI_FLASH_DUAL_CE1_1_2_2; case MSPI_IO_MODE_QUAD: return AM_HAL_MSPI_FLASH_QUAD_CE1; case MSPI_IO_MODE_QUAD_1_1_4: return AM_HAL_MSPI_FLASH_QUAD_CE1_1_1_4; case MSPI_IO_MODE_QUAD_1_4_4: return AM_HAL_MSPI_FLASH_QUAD_CE1_1_4_4; case MSPI_IO_MODE_OCTAL: return AM_HAL_MSPI_FLASH_OCTAL_CE1; default: return AM_HAL_MSPI_FLASH_MAX; } } else { return AM_HAL_MSPI_FLASH_MAX; } } static am_hal_mspi_dma_boundary_e mspi_set_mem_boundary(uint32_t mem_boundary) { switch (mem_boundary) { case 0: return AM_HAL_MSPI_BOUNDARY_NONE; case 32: return AM_HAL_MSPI_BOUNDARY_BREAK32; case 64: return AM_HAL_MSPI_BOUNDARY_BREAK64; case 128: return AM_HAL_MSPI_BOUNDARY_BREAK128; case 256: return AM_HAL_MSPI_BOUNDARY_BREAK256; case 512: return AM_HAL_MSPI_BOUNDARY_BREAK512; case 1024: return AM_HAL_MSPI_BOUNDARY_BREAK1K; case 2048: return AM_HAL_MSPI_BOUNDARY_BREAK2K; case 4096: return AM_HAL_MSPI_BOUNDARY_BREAK4K; case 8192: return AM_HAL_MSPI_BOUNDARY_BREAK8K; case 16384: return AM_HAL_MSPI_BOUNDARY_BREAK16K; default: return AM_HAL_MSPI_BOUNDARY_MAX; } } static inline void mspi_context_ce_control(struct mspi_context *ctx, bool on) { if (ctx->owner) { if (ctx->xfer.hold_ce && ctx->xfer.ce_sw_ctrl.gpio.port != NULL) { if (on) { gpio_pin_set_dt(&ctx->xfer.ce_sw_ctrl.gpio, 1); k_busy_wait(ctx->xfer.ce_sw_ctrl.delay); } else { k_busy_wait(ctx->xfer.ce_sw_ctrl.delay); gpio_pin_set_dt(&ctx->xfer.ce_sw_ctrl.gpio, 0); } } } } static inline void mspi_context_release(struct mspi_context *ctx) { ctx->owner = NULL; k_sem_give(&ctx->lock); } static inline void mspi_context_unlock_unconditionally(struct mspi_context *ctx) { mspi_context_ce_control(ctx, false); if (!k_sem_count_get(&ctx->lock)) { ctx->owner = NULL; k_sem_give(&ctx->lock); } } static inline int mspi_context_lock(struct mspi_context *ctx, const struct mspi_dev_id *req, const struct mspi_xfer *xfer, mspi_callback_handler_t callback, struct mspi_callback_context *callback_ctx, bool lockon) { int ret = 1; if ((k_sem_count_get(&ctx->lock) == 0) && !lockon && (ctx->owner == req)) { return 0; } if (k_sem_take(&ctx->lock, K_MSEC(xfer->timeout))) { return -EBUSY; } if (ctx->xfer.async) { if ((xfer->tx_dummy == ctx->xfer.tx_dummy) && (xfer->rx_dummy == ctx->xfer.rx_dummy) && (xfer->cmd_length == ctx->xfer.cmd_length) && (xfer->addr_length == ctx->xfer.addr_length)) { ret = 0; } else if (ctx->packets_left == 0) { if (ctx->callback_ctx) { volatile struct mspi_event_data *evt_data; evt_data = &ctx->callback_ctx->mspi_evt.evt_data; while (evt_data->status != 0) { } ret = 1; } else { ret = 0; } } else { return -EIO; } } ctx->owner = req; ctx->xfer = *xfer; ctx->packets_done = 0; ctx->packets_left = ctx->xfer.num_packet; ctx->callback = callback; ctx->callback_ctx = callback_ctx; return ret; } static inline bool mspi_is_inp(const struct device *controller) { struct mspi_ambiq_data *data = controller->data; return (k_sem_count_get(&data->ctx.lock) == 0); } static inline int mspi_verify_device(const struct device *controller, const struct mspi_dev_id *dev_id) { const struct mspi_ambiq_config *cfg = controller->config; int device_index = cfg->mspicfg.num_periph; int ret = 0; for (int i = 0; i < cfg->mspicfg.num_periph; i++) { if (dev_id->ce.port == cfg->mspicfg.ce_group[i].port && dev_id->ce.pin == cfg->mspicfg.ce_group[i].pin && dev_id->ce.dt_flags == cfg->mspicfg.ce_group[i].dt_flags) { device_index = i; } } if (device_index >= cfg->mspicfg.num_periph || device_index != dev_id->dev_idx) { LOG_INST_ERR(cfg->log, "%u, invalid device ID.", __LINE__); return -ENODEV; } return ret; } static int mspi_ambiq_deinit(const struct device *controller) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; int ret = 0; if (!data->mspiHandle) { LOG_INST_ERR(cfg->log, "%u, the mspi not yet initialized.", __LINE__); return -ENODEV; } if (k_mutex_lock(&data->lock, K_MSEC(CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE))) { LOG_INST_ERR(cfg->log, "%u, fail to gain controller access.", __LINE__); return -EBUSY; } ret = am_hal_mspi_interrupt_disable(data->mspiHandle, 0xFFFFFFFF); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to disable interrupt, code:%d.", __LINE__, ret); ret = -EHOSTDOWN; goto e_deinit_return; } ret = am_hal_mspi_interrupt_clear(data->mspiHandle, 0xFFFFFFFF); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to clear interrupt, code:%d.", __LINE__, ret); ret = -EHOSTDOWN; goto e_deinit_return; } ret = am_hal_mspi_disable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to disable MSPI, code:%d.", __LINE__, ret); ret = -EHOSTDOWN; goto e_deinit_return; } ret = am_hal_mspi_power_control(data->mspiHandle, AM_HAL_SYSCTRL_DEEPSLEEP, false); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to power off MSPI, code:%d.", __LINE__, ret); ret = -EHOSTDOWN; goto e_deinit_return; } ret = am_hal_mspi_deinitialize(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to deinit MSPI.", __LINE__); ret = -ENODEV; goto e_deinit_return; } return ret; e_deinit_return: k_mutex_unlock(&data->lock); return ret; } /** DMA specific config */ static int mspi_xfer_config(const struct device *controller, const struct mspi_xfer *xfer) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; am_hal_mspi_dev_config_t hal_dev_cfg = data->hal_dev_cfg; am_hal_mspi_request_e eRequest; int ret = 0; if (data->scramble_cfg.enable) { eRequest = AM_HAL_MSPI_REQ_SCRAMB_EN; } else { eRequest = AM_HAL_MSPI_REQ_SCRAMB_DIS; } ret = am_hal_mspi_disable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to disable MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } ret = am_hal_mspi_control(data->mspiHandle, eRequest, NULL); if (ret) { LOG_INST_ERR(cfg->log, "%u,Unable to complete scramble config:%d.", __LINE__, data->scramble_cfg.enable); return -EHOSTDOWN; } if (xfer->cmd_length > AM_HAL_MSPI_INSTR_2_BYTE + 1) { LOG_INST_ERR(cfg->log, "%u, cmd_length is too large.", __LINE__); return -ENOTSUP; } if (xfer->cmd_length == 0) { hal_dev_cfg.bSendInstr = false; } else { hal_dev_cfg.bSendInstr = true; hal_dev_cfg.eInstrCfg = xfer->cmd_length - 1; } if (xfer->addr_length > AM_HAL_MSPI_ADDR_4_BYTE + 1) { LOG_INST_ERR(cfg->log, "%u, addr_length is too large.", __LINE__); return -ENOTSUP; } if (xfer->addr_length == 0) { hal_dev_cfg.bSendAddr = false; } else { hal_dev_cfg.bSendAddr = true; hal_dev_cfg.eAddrCfg = xfer->addr_length - 1; } hal_dev_cfg.bTurnaround = (xfer->rx_dummy != 0); hal_dev_cfg.ui8TurnAround = (uint8_t)xfer->rx_dummy; hal_dev_cfg.bEnWriteLatency = (xfer->tx_dummy != 0); hal_dev_cfg.ui8WriteLatency = (uint8_t)xfer->tx_dummy; ret = am_hal_mspi_device_configure(data->mspiHandle, &hal_dev_cfg); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to configure MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } ret = am_hal_mspi_enable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to enable MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } data->hal_dev_cfg = hal_dev_cfg; return ret; } static int mspi_ambiq_config(const struct mspi_dt_spec *spec) { const struct mspi_cfg *config = &spec->config; const struct mspi_ambiq_config *cfg = spec->bus->config; struct mspi_ambiq_data *data = spec->bus->data; int ret = 0; if (config->op_mode != MSPI_OP_MODE_CONTROLLER) { LOG_INST_ERR(cfg->log, "%u, only support MSPI controller mode.", __LINE__); return -ENOTSUP; } if (config->max_freq > MSPI_MAX_FREQ) { LOG_INST_ERR(cfg->log, "%u, max_freq too large.", __LINE__); return -ENOTSUP; } if (config->duplex != MSPI_HALF_DUPLEX) { LOG_INST_ERR(cfg->log, "%u, only support half duplex mode.", __LINE__); return -ENOTSUP; } if (config->dqs_support) { LOG_INST_ERR(cfg->log, "%u, only support non-DQS mode.", __LINE__); return -ENOTSUP; } if (config->re_init) { ret = mspi_ambiq_deinit(spec->bus); if (ret) { return ret; } } ret = am_hal_mspi_initialize(config->channel_num, &data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to initialize MSPI, code:%d.", __LINE__, ret); return -EPERM; } ret = am_hal_mspi_power_control(data->mspiHandle, AM_HAL_SYSCTRL_WAKE, false); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to power on MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } ret = am_hal_mspi_enable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to Enable MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); if (ret) { return ret; } ret = am_hal_mspi_interrupt_clear(data->mspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to clear interrupt, code:%d.", __LINE__, ret); return -EHOSTDOWN; } ret = am_hal_mspi_interrupt_enable(data->mspiHandle, AM_HAL_MSPI_INT_CQUPD | AM_HAL_MSPI_INT_ERR); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to turn on interrupt, code:%d.", __LINE__, ret); return -EHOSTDOWN; } cfg->irq_cfg_func(); mspi_context_unlock_unconditionally(&data->ctx); if (config->re_init) { k_mutex_unlock(&data->lock); } return ret; } static int mspi_ambiq_dev_config(const struct device *controller, const struct mspi_dev_id *dev_id, const enum mspi_dev_cfg_mask param_mask, const struct mspi_dev_cfg *dev_cfg) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; am_hal_mspi_dev_config_t hal_dev_cfg = data->hal_dev_cfg; int ret = 0; if (data->dev_id != dev_id) { if (k_mutex_lock(&data->lock, K_MSEC(CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE))) { LOG_INST_ERR(cfg->log, "%u, fail to gain controller access.", __LINE__); return -EBUSY; } ret = mspi_verify_device(controller, dev_id); if (ret) { goto e_return; } } if (mspi_is_inp(controller)) { ret = -EBUSY; goto e_return; } if (param_mask == MSPI_DEVICE_CONFIG_NONE && !cfg->mspicfg.sw_multi_periph) { /* Do nothing except obtaining the controller lock */ data->dev_id = (struct mspi_dev_id *)dev_id; return ret; } else if (param_mask != MSPI_DEVICE_CONFIG_ALL) { if (data->dev_id != dev_id) { LOG_INST_ERR(cfg->log, "%u, config failed, must be the same device.", __LINE__); ret = -ENOTSUP; goto e_return; } if ((param_mask & (~(MSPI_DEVICE_CONFIG_FREQUENCY | MSPI_DEVICE_CONFIG_IO_MODE | MSPI_DEVICE_CONFIG_CE_NUM | MSPI_DEVICE_CONFIG_DATA_RATE | MSPI_DEVICE_CONFIG_CMD_LEN | MSPI_DEVICE_CONFIG_ADDR_LEN)))) { LOG_INST_ERR(cfg->log, "%u, config type not supported.", __LINE__); ret = -ENOTSUP; goto e_return; } if (param_mask & MSPI_DEVICE_CONFIG_FREQUENCY) { hal_dev_cfg.eClockFreq = mspi_set_freq(cfg, dev_cfg->freq); if (hal_dev_cfg.eClockFreq == 0) { ret = -ENOTSUP; goto e_return; } ret = am_hal_mspi_control(data->mspiHandle, AM_HAL_MSPI_REQ_CLOCK_CONFIG, &hal_dev_cfg.eClockFreq); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to configure eClockFreq.", __LINE__); ret = -EHOSTDOWN; goto e_return; } data->dev_cfg.freq = dev_cfg->freq; } if ((param_mask & MSPI_DEVICE_CONFIG_IO_MODE) || (param_mask & MSPI_DEVICE_CONFIG_CE_NUM) || (param_mask & MSPI_DEVICE_CONFIG_DATA_RATE)) { hal_dev_cfg.eDeviceConfig = mspi_set_line(cfg, dev_cfg->io_mode, dev_cfg->data_rate, dev_cfg->ce_num); if (hal_dev_cfg.eDeviceConfig == AM_HAL_MSPI_FLASH_MAX) { ret = -ENOTSUP; goto e_return; } ret = am_hal_mspi_control(data->mspiHandle, AM_HAL_MSPI_REQ_DEVICE_CONFIG, &hal_dev_cfg.eDeviceConfig); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to configure device.", __LINE__); ret = -EHOSTDOWN; goto e_return; } data->dev_cfg.freq = dev_cfg->io_mode; data->dev_cfg.data_rate = dev_cfg->data_rate; data->dev_cfg.ce_num = dev_cfg->ce_num; } if (param_mask & MSPI_DEVICE_CONFIG_CMD_LEN) { if (dev_cfg->cmd_length > AM_HAL_MSPI_INSTR_2_BYTE + 1 || dev_cfg->cmd_length == 0) { LOG_INST_ERR(cfg->log, "%u, invalid cmd_length.", __LINE__); ret = -ENOTSUP; goto e_return; } hal_dev_cfg.eInstrCfg = dev_cfg->cmd_length - 1; ret = am_hal_mspi_control(data->mspiHandle, AM_HAL_MSPI_REQ_ISIZE_SET, &hal_dev_cfg.eInstrCfg); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to configure cmd_length.", __LINE__); ret = -EHOSTDOWN; goto e_return; } data->dev_cfg.cmd_length = dev_cfg->cmd_length; } if (param_mask & MSPI_DEVICE_CONFIG_ADDR_LEN) { if (dev_cfg->addr_length > AM_HAL_MSPI_ADDR_4_BYTE + 1 || dev_cfg->addr_length == 0) { LOG_INST_ERR(cfg->log, "%u, invalid addr_length.", __LINE__); ret = -ENOTSUP; goto e_return; } hal_dev_cfg.eAddrCfg = dev_cfg->addr_length - 1; ret = am_hal_mspi_control(data->mspiHandle, AM_HAL_MSPI_REQ_ASIZE_SET, &hal_dev_cfg.eAddrCfg); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to configure addr_length.", __LINE__); ret = -EHOSTDOWN; goto e_return; } data->dev_cfg.addr_length = dev_cfg->addr_length; } } else { if (data->dev_id != dev_id) { ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_PRIV_START + dev_id->dev_idx); if (ret) { goto e_return; } } if (memcmp(&data->dev_cfg, dev_cfg, sizeof(struct mspi_dev_cfg)) == 0) { /** Nothing to config */ data->dev_id = (struct mspi_dev_id *)dev_id; return ret; } if (dev_cfg->endian != MSPI_XFER_LITTLE_ENDIAN) { LOG_INST_ERR(cfg->log, "%u, only support MSB first.", __LINE__); ret = -ENOTSUP; goto e_return; } if (dev_cfg->dqs_enable && !cfg->mspicfg.dqs_support) { LOG_INST_ERR(cfg->log, "%u, only support non-DQS mode.", __LINE__); ret = -ENOTSUP; goto e_return; } hal_dev_cfg.eSpiMode = dev_cfg->cpp; hal_dev_cfg.bEnWriteLatency = (dev_cfg->tx_dummy != 0); hal_dev_cfg.ui8WriteLatency = dev_cfg->tx_dummy; hal_dev_cfg.bTurnaround = (dev_cfg->rx_dummy != 0); hal_dev_cfg.ui8TurnAround = dev_cfg->rx_dummy; hal_dev_cfg.eClockFreq = mspi_set_freq(cfg, dev_cfg->freq); if (hal_dev_cfg.eClockFreq == 0) { ret = -ENOTSUP; goto e_return; } hal_dev_cfg.eDeviceConfig = mspi_set_line(cfg, dev_cfg->io_mode, dev_cfg->data_rate, dev_cfg->ce_num); if (hal_dev_cfg.eDeviceConfig == AM_HAL_MSPI_FLASH_MAX) { ret = -ENOTSUP; goto e_return; } if (dev_cfg->cmd_length > AM_HAL_MSPI_INSTR_2_BYTE + 1) { LOG_INST_ERR(cfg->log, "%u, cmd_length too large.", __LINE__); ret = -ENOTSUP; goto e_return; } if (dev_cfg->cmd_length == 0) { hal_dev_cfg.bSendInstr = false; } else { hal_dev_cfg.bSendInstr = true; hal_dev_cfg.eInstrCfg = dev_cfg->cmd_length - 1; } if (dev_cfg->addr_length > AM_HAL_MSPI_ADDR_4_BYTE + 1) { LOG_INST_ERR(cfg->log, "%u, addr_length too large.", __LINE__); ret = -ENOTSUP; goto e_return; } if (dev_cfg->addr_length == 0) { hal_dev_cfg.bSendAddr = false; } else { hal_dev_cfg.bSendAddr = true; hal_dev_cfg.eAddrCfg = dev_cfg->addr_length - 1; } hal_dev_cfg.ui8ReadInstr = (uint8_t)dev_cfg->read_cmd; hal_dev_cfg.ui8WriteInstr = (uint8_t)dev_cfg->write_cmd; hal_dev_cfg.eDMABoundary = mspi_set_mem_boundary(dev_cfg->mem_boundary); if (hal_dev_cfg.eDMABoundary >= AM_HAL_MSPI_BOUNDARY_MAX) { LOG_INST_ERR(cfg->log, "%u, mem_boundary too large.", __LINE__); ret = -ENOTSUP; goto e_return; } /** ui16DMATimeLimit unit is in 0.1us */ hal_dev_cfg.ui16DMATimeLimit = dev_cfg->time_to_break * 10; ret = am_hal_mspi_disable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to disable MSPI, code:%d.", __LINE__, ret); ret = -EHOSTDOWN; goto e_return; } ret = am_hal_mspi_device_configure(data->mspiHandle, &hal_dev_cfg); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to configure MSPI, code:%d.", __LINE__, ret); ret = -EHOSTDOWN; goto e_return; } ret = am_hal_mspi_enable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to enable MSPI, code:%d.", __LINE__, ret); ret = -EHOSTDOWN; goto e_return; } data->dev_cfg = *dev_cfg; data->dev_id = (struct mspi_dev_id *)dev_id; } data->hal_dev_cfg = hal_dev_cfg; return ret; e_return: k_mutex_unlock(&data->lock); return ret; } static int mspi_ambiq_xip_config(const struct device *controller, const struct mspi_dev_id *dev_id, const struct mspi_xip_cfg *xip_cfg) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; am_hal_mspi_request_e eRequest; int ret = 0; if (dev_id != data->dev_id) { LOG_INST_ERR(cfg->log, "%u, dev_id don't match.", __LINE__); return -ESTALE; } if (xip_cfg->enable) { eRequest = AM_HAL_MSPI_REQ_XIP_EN; } else { eRequest = AM_HAL_MSPI_REQ_XIP_DIS; } ret = am_hal_mspi_control(data->mspiHandle, eRequest, NULL); if (ret) { LOG_INST_ERR(cfg->log, "%u,Unable to complete xip config:%d.", __LINE__, xip_cfg->enable); return -EHOSTDOWN; } data->xip_cfg = *xip_cfg; return ret; } static int mspi_ambiq_scramble_config(const struct device *controller, const struct mspi_dev_id *dev_id, const struct mspi_scramble_cfg *scramble_cfg) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; am_hal_mspi_dev_config_t hal_dev_cfg = data->hal_dev_cfg; am_hal_mspi_request_e eRequest; int ret = 0; if (mspi_is_inp(controller)) { return -EBUSY; } if (dev_id != data->dev_id) { LOG_INST_ERR(cfg->log, "%u, dev_id don't match.", __LINE__); return -ESTALE; } if (scramble_cfg->enable) { eRequest = AM_HAL_MSPI_REQ_SCRAMB_EN; } else { eRequest = AM_HAL_MSPI_REQ_SCRAMB_DIS; } ret = am_hal_mspi_disable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to disable MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } ret = am_hal_mspi_control(data->mspiHandle, eRequest, NULL); if (ret) { LOG_INST_ERR(cfg->log, "%u,Unable to complete scramble config:%d.", __LINE__, scramble_cfg->enable); return -EHOSTDOWN; } hal_dev_cfg.scramblingStartAddr = 0 + scramble_cfg->address_offset; hal_dev_cfg.scramblingEndAddr = hal_dev_cfg.scramblingStartAddr + scramble_cfg->size; ret = am_hal_mspi_device_configure(data->mspiHandle, &hal_dev_cfg); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to configure MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } ret = am_hal_mspi_enable(data->mspiHandle); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to enable MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } data->scramble_cfg = *scramble_cfg; data->hal_dev_cfg = hal_dev_cfg; return ret; } static int mspi_ambiq_timing_config(const struct device *controller, const struct mspi_dev_id *dev_id, const uint32_t param_mask, void *timing_cfg) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; am_hal_mspi_dev_config_t hal_dev_cfg = data->hal_dev_cfg; struct mspi_ambiq_timing_cfg *time_cfg = timing_cfg; am_hal_mspi_timing_scan_t timing; int ret = 0; if (mspi_is_inp(controller)) { return -EBUSY; } if (dev_id != data->dev_id) { LOG_INST_ERR(cfg->log, "%u, dev_id don't match.", __LINE__); return -ESTALE; } if (param_mask & (~(MSPI_AMBIQ_SET_WLC | MSPI_AMBIQ_SET_RLC))) { LOG_INST_ERR(cfg->log, "%u, config type not supported.", __LINE__); return -ENOTSUP; } if (param_mask & MSPI_AMBIQ_SET_WLC) { if (time_cfg->ui8WriteLatency) { hal_dev_cfg.bEnWriteLatency = true; } else { hal_dev_cfg.bEnWriteLatency = false; } hal_dev_cfg.ui8WriteLatency = time_cfg->ui8WriteLatency; } if (param_mask & MSPI_AMBIQ_SET_RLC) { if (time_cfg->ui8TurnAround) { hal_dev_cfg.bTurnaround = true; } else { hal_dev_cfg.bTurnaround = false; } hal_dev_cfg.ui8TurnAround = time_cfg->ui8TurnAround; } timing.ui8Turnaround = hal_dev_cfg.ui8TurnAround; timing.ui8WriteLatency = hal_dev_cfg.ui8WriteLatency; ret = am_hal_mspi_control(data->mspiHandle, AM_HAL_MSPI_REQ_TIMING_SCAN, &timing); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to configure timing.", __LINE__); return -EHOSTDOWN; } data->hal_dev_cfg = hal_dev_cfg; return ret; } static int mspi_ambiq_get_channel_status(const struct device *controller, uint8_t ch) { ARG_UNUSED(ch); const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; int ret = 0; if (sys_read32(cfg->reg_base) & MSPI_BUSY) { ret = -EBUSY; } if (mspi_is_inp(controller)) { return -EBUSY; } data->dev_id = NULL; k_mutex_unlock(&data->lock); return ret; } static void mspi_ambiq_isr(const struct device *dev) { struct mspi_ambiq_data *data = dev->data; uint32_t ui32Status; am_hal_mspi_interrupt_status_get(data->mspiHandle, &ui32Status, false); am_hal_mspi_interrupt_clear(data->mspiHandle, ui32Status); am_hal_mspi_interrupt_service(data->mspiHandle, ui32Status); } /** Manage sync dma transceive */ static void hal_mspi_callback(void *pCallbackCtxt, uint32_t status) { const struct device *controller = pCallbackCtxt; struct mspi_ambiq_data *data = controller->data; data->ctx.packets_done++; } static int mspi_pio_prepare(const struct device *controller, am_hal_mspi_pio_transfer_t *trans) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; const struct mspi_xfer *xfer = &data->ctx.xfer; int ret = 0; trans->bScrambling = false; trans->bSendAddr = (xfer->addr_length != 0); trans->bSendInstr = (xfer->cmd_length != 0); trans->bTurnaround = (xfer->rx_dummy != 0); trans->bEnWRLatency = (xfer->tx_dummy != 0); trans->bDCX = false; trans->bQuadCmd = false; trans->bContinue = false; if (xfer->cmd_length > AM_HAL_MSPI_INSTR_2_BYTE + 1) { LOG_INST_ERR(cfg->log, "%u, invalid cmd_length.", __LINE__); return -ENOTSUP; } if (xfer->cmd_length != 0) { am_hal_mspi_instr_e eInstrCfg = xfer->cmd_length - 1; ret = am_hal_mspi_control(data->mspiHandle, AM_HAL_MSPI_REQ_ISIZE_SET, &eInstrCfg); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to configure cmd_length.", __LINE__); return -EHOSTDOWN; } data->hal_dev_cfg.eInstrCfg = eInstrCfg; } data->dev_cfg.cmd_length = xfer->cmd_length; if (xfer->addr_length > AM_HAL_MSPI_ADDR_4_BYTE + 1) { LOG_INST_ERR(cfg->log, "%u, invalid addr_length.", __LINE__); return -ENOTSUP; } if (xfer->addr_length != 0) { am_hal_mspi_addr_e eAddrCfg = xfer->addr_length - 1; ret = am_hal_mspi_control(data->mspiHandle, AM_HAL_MSPI_REQ_ASIZE_SET, &eAddrCfg); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to configure addr_length.", __LINE__); return -EHOSTDOWN; } data->hal_dev_cfg.eAddrCfg = eAddrCfg; } data->dev_cfg.addr_length = xfer->addr_length; return ret; } static int mspi_pio_transceive(const struct device *controller, const struct mspi_xfer *xfer, mspi_callback_handler_t cb, struct mspi_callback_context *cb_ctx) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; struct mspi_context *ctx = &data->ctx; const struct mspi_xfer_packet *packet; uint32_t packet_idx; am_hal_mspi_pio_transfer_t trans; int ret = 0; int cfg_flag = 0; if (xfer->num_packet == 0 || !xfer->packets || xfer->timeout > CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE) { return -EFAULT; } cfg_flag = mspi_context_lock(ctx, data->dev_id, xfer, cb, cb_ctx, true); /** For async, user must make sure when cfg_flag = 0 the dummy and instr addr length * in mspi_xfer of the two calls are the same if the first one has not finished yet. */ if (cfg_flag) { if (cfg_flag == 1) { ret = mspi_pio_prepare(controller, &trans); if (ret) { goto pio_err; } } else { ret = cfg_flag; goto pio_err; } } if (!ctx->xfer.async) { while (ctx->packets_left > 0) { packet_idx = ctx->xfer.num_packet - ctx->packets_left; packet = &ctx->xfer.packets[packet_idx]; trans.eDirection = packet->dir; trans.ui16DeviceInstr = (uint16_t)packet->cmd; trans.ui32DeviceAddr = packet->address; trans.ui32NumBytes = packet->num_bytes; trans.pui32Buffer = (uint32_t *)packet->data_buf; ret = am_hal_mspi_blocking_transfer(data->mspiHandle, &trans, MSPI_TIMEOUT_US); ctx->packets_left--; if (ret) { ret = -EIO; goto pio_err; } } } else { ret = am_hal_mspi_interrupt_enable(data->mspiHandle, AM_HAL_MSPI_INT_DMACMP); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to enable interrupt.", __LINE__); ret = -EHOSTDOWN; goto pio_err; } while (ctx->packets_left > 0) { packet_idx = ctx->xfer.num_packet - ctx->packets_left; packet = &ctx->xfer.packets[packet_idx]; trans.eDirection = packet->dir; trans.ui16DeviceInstr = (uint16_t)packet->cmd; trans.ui32DeviceAddr = packet->address; trans.ui32NumBytes = packet->num_bytes; trans.pui32Buffer = (uint32_t *)packet->data_buf; if (ctx->callback && packet->cb_mask == MSPI_BUS_XFER_COMPLETE_CB) { ctx->callback_ctx->mspi_evt.evt_type = MSPI_BUS_XFER_COMPLETE; ctx->callback_ctx->mspi_evt.evt_data.controller = controller; ctx->callback_ctx->mspi_evt.evt_data.dev_id = data->ctx.owner; ctx->callback_ctx->mspi_evt.evt_data.packet = packet; ctx->callback_ctx->mspi_evt.evt_data.packet_idx = packet_idx; ctx->callback_ctx->mspi_evt.evt_data.status = ~0; } am_hal_mspi_callback_t callback = NULL; if (packet->cb_mask == MSPI_BUS_XFER_COMPLETE_CB) { callback = (am_hal_mspi_callback_t)ctx->callback; } ret = am_hal_mspi_nonblocking_transfer(data->mspiHandle, &trans, MSPI_PIO, callback, (void *)ctx->callback_ctx); ctx->packets_left--; if (ret) { if (ret == AM_HAL_STATUS_OUT_OF_RANGE) { ret = -ENOMEM; } else { ret = -EIO; } goto pio_err; } } } pio_err: mspi_context_release(ctx); return ret; } static int mspi_dma_transceive(const struct device *controller, const struct mspi_xfer *xfer, mspi_callback_handler_t cb, struct mspi_callback_context *cb_ctx) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; struct mspi_context *ctx = &data->ctx; am_hal_mspi_dma_transfer_t trans; int ret = 0; int cfg_flag = 0; if (xfer->num_packet == 0 || !xfer->packets || xfer->timeout > CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE) { return -EFAULT; } cfg_flag = mspi_context_lock(ctx, data->dev_id, xfer, cb, cb_ctx, true); /** For async, user must make sure when cfg_flag = 0 the dummy and instr addr length * in mspi_xfer of the two calls are the same if the first one has not finished yet. */ if (cfg_flag) { if (cfg_flag == 1) { ret = mspi_xfer_config(controller, xfer); if (ret) { goto dma_err; } } else { ret = cfg_flag; goto dma_err; } } ret = am_hal_mspi_interrupt_enable(data->mspiHandle, AM_HAL_MSPI_INT_DMACMP); if (ret) { LOG_INST_ERR(cfg->log, "%u, failed to enable interrupt.", __LINE__); ret = -EHOSTDOWN; goto dma_err; } while (ctx->packets_left > 0) { uint32_t packet_idx = ctx->xfer.num_packet - ctx->packets_left; const struct mspi_xfer_packet *packet; packet = &ctx->xfer.packets[packet_idx]; trans.ui8Priority = ctx->xfer.priority; trans.eDirection = packet->dir; trans.ui32TransferCount = packet->num_bytes; trans.ui32DeviceAddress = packet->address; trans.ui32SRAMAddress = (uint32_t)packet->data_buf; trans.ui32PauseCondition = 0; trans.ui32StatusSetClr = 0; if (ctx->xfer.async) { if (ctx->callback && packet->cb_mask == MSPI_BUS_XFER_COMPLETE_CB) { ctx->callback_ctx->mspi_evt.evt_type = MSPI_BUS_XFER_COMPLETE; ctx->callback_ctx->mspi_evt.evt_data.controller = controller; ctx->callback_ctx->mspi_evt.evt_data.dev_id = data->ctx.owner; ctx->callback_ctx->mspi_evt.evt_data.packet = packet; ctx->callback_ctx->mspi_evt.evt_data.packet_idx = packet_idx; ctx->callback_ctx->mspi_evt.evt_data.status = ~0; } am_hal_mspi_callback_t callback = NULL; if (packet->cb_mask == MSPI_BUS_XFER_COMPLETE_CB) { callback = (am_hal_mspi_callback_t)ctx->callback; } ret = am_hal_mspi_nonblocking_transfer(data->mspiHandle, &trans, MSPI_DMA, callback, (void *)ctx->callback_ctx); } else { ret = am_hal_mspi_nonblocking_transfer(data->mspiHandle, &trans, MSPI_DMA, hal_mspi_callback, (void *)controller); } ctx->packets_left--; if (ret) { if (ret == AM_HAL_STATUS_OUT_OF_RANGE) { ret = -ENOMEM; } else { ret = -EIO; } goto dma_err; } } if (!ctx->xfer.async) { while (ctx->packets_done < ctx->xfer.num_packet) { k_busy_wait(10); } } dma_err: mspi_context_release(ctx); return ret; } static int mspi_ambiq_transceive(const struct device *controller, const struct mspi_dev_id *dev_id, const struct mspi_xfer *xfer) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; mspi_callback_handler_t cb = NULL; struct mspi_callback_context *cb_ctx = NULL; if (dev_id != data->dev_id) { LOG_INST_ERR(cfg->log, "%u, dev_id don't match.", __LINE__); return -ESTALE; } if (xfer->async) { cb = data->cbs[MSPI_BUS_XFER_COMPLETE]; cb_ctx = data->cb_ctxs[MSPI_BUS_XFER_COMPLETE]; } if (xfer->xfer_mode == MSPI_PIO) { return mspi_pio_transceive(controller, xfer, cb, cb_ctx); } else if (xfer->xfer_mode == MSPI_DMA) { return mspi_dma_transceive(controller, xfer, cb, cb_ctx); } else { return -EIO; } } static int mspi_ambiq_register_callback(const struct device *controller, const struct mspi_dev_id *dev_id, const enum mspi_bus_event evt_type, mspi_callback_handler_t cb, struct mspi_callback_context *ctx) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; if (mspi_is_inp(controller)) { return -EBUSY; } if (dev_id != data->dev_id) { LOG_INST_ERR(cfg->log, "%u, dev_id don't match.", __LINE__); return -ESTALE; } if (evt_type != MSPI_BUS_XFER_COMPLETE) { LOG_INST_ERR(cfg->log, "%u, callback types not supported.", __LINE__); return -ENOTSUP; } data->cbs[evt_type] = cb; data->cb_ctxs[evt_type] = ctx; return 0; } #if CONFIG_PM_DEVICE static int mspi_ambiq_pm_action(const struct device *controller, enum pm_device_action action) { const struct mspi_ambiq_config *cfg = controller->config; struct mspi_ambiq_data *data = controller->data; int ret = 0; if (mspi_is_inp(controller)) { return -EBUSY; } switch (action) { case PM_DEVICE_ACTION_TURN_ON: ret = am_hal_mspi_power_control(data->mspiHandle, AM_HAL_SYSCTRL_WAKE, true); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to power on MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } break; case PM_DEVICE_ACTION_TURN_OFF: ret = am_hal_mspi_power_control(data->mspiHandle, AM_HAL_SYSCTRL_DEEPSLEEP, true); if (ret) { LOG_INST_ERR(cfg->log, "%u, fail to power off MSPI, code:%d.", __LINE__, ret); return -EHOSTDOWN; } break; default: return -ENOTSUP; } return 0; } #endif static int mspi_ambiq_init(const struct device *controller) { const struct mspi_ambiq_config *cfg = controller->config; const struct mspi_dt_spec spec = { .bus = controller, .config = cfg->mspicfg, }; return mspi_ambiq_config(&spec); } static DEVICE_API(mspi, mspi_ambiq_driver_api) = { .config = mspi_ambiq_config, .dev_config = mspi_ambiq_dev_config, .xip_config = mspi_ambiq_xip_config, .scramble_config = mspi_ambiq_scramble_config, .timing_config = mspi_ambiq_timing_config, .get_channel_status = mspi_ambiq_get_channel_status, .register_callback = mspi_ambiq_register_callback, .transceive = mspi_ambiq_transceive, }; #define MSPI_PINCTRL_STATE_INIT(state_idx, node_id) \ COND_CODE_1(Z_PINCTRL_SKIP_STATE(state_idx, node_id), (), \ ({ \ .id = state_idx, \ .pins = Z_PINCTRL_STATE_PINS_NAME(state_idx, node_id), \ .pin_cnt = ARRAY_SIZE(Z_PINCTRL_STATE_PINS_NAME(state_idx, node_id)) \ })) #define MSPI_PINCTRL_STATES_DEFINE(node_id) \ static const struct pinctrl_state \ Z_PINCTRL_STATES_NAME(node_id)[] = { \ LISTIFY(DT_NUM_PINCTRL_STATES(node_id), \ MSPI_PINCTRL_STATE_INIT, (,), node_id) \ }; #define MSPI_PINCTRL_DT_DEFINE(node_id) \ LISTIFY(DT_NUM_PINCTRL_STATES(node_id), \ Z_PINCTRL_STATE_PINS_DEFINE, (;), node_id); \ MSPI_PINCTRL_STATES_DEFINE(node_id) \ Z_PINCTRL_DEV_CONFIG_STATIC Z_PINCTRL_DEV_CONFIG_CONST \ struct pinctrl_dev_config Z_PINCTRL_DEV_CONFIG_NAME(node_id) = \ Z_PINCTRL_DEV_CONFIG_INIT(node_id) #define MSPI_CONFIG(n) \ { \ .channel_num = (DT_INST_REG_ADDR(n) - MSPI0_BASE) / \ (DT_INST_REG_SIZE(n) * 4), \ .op_mode = MSPI_OP_MODE_CONTROLLER, \ .duplex = MSPI_HALF_DUPLEX, \ .max_freq = MSPI_MAX_FREQ, \ .dqs_support = false, \ .num_periph = DT_INST_CHILD_NUM(n), \ .sw_multi_periph = DT_INST_PROP(n, software_multiperipheral), \ } #define MSPI_HAL_DEVICE_CONFIG(n, cmdq, cmdq_size) \ { \ .ui8WriteLatency = 0, \ .ui8TurnAround = 0, \ .eAddrCfg = 0, \ .eInstrCfg = 0, \ .ui8ReadInstr = 0, \ .ui8WriteInstr = 0, \ .eDeviceConfig = AM_HAL_MSPI_FLASH_SERIAL_CE0, \ .eSpiMode = AM_HAL_MSPI_SPI_MODE_0, \ .eClockFreq = MSPI_MAX_FREQ / DT_INST_PROP_OR(n, \ clock_frequency, \ MSPI_MAX_FREQ), \ .bEnWriteLatency = false, \ .bSendAddr = false, \ .bSendInstr = false, \ .bTurnaround = false, \ .bEmulateDDR = false, \ .ui16DMATimeLimit = 0, \ .eDMABoundary = AM_HAL_MSPI_BOUNDARY_NONE, \ .ui32TCBSize = cmdq_size, \ .pTCB = cmdq, \ .scramblingStartAddr = 0, \ .scramblingEndAddr = 0, \ } #define AMBIQ_MSPI_DEFINE(n) \ LOG_INSTANCE_REGISTER(DT_DRV_INST(n), mspi##n, CONFIG_MSPI_LOG_LEVEL); \ MSPI_PINCTRL_DT_DEFINE(DT_DRV_INST(n)); \ static void mspi_ambiq_irq_cfg_func_##n(void) \ { \ IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ mspi_ambiq_isr, DEVICE_DT_INST_GET(n), 0); \ irq_enable(DT_INST_IRQN(n)); \ } \ static uint32_t mspi_ambiq_cmdq##n[DT_INST_PROP_OR(n, cmdq_buffer_size, 1024) / 4] \ __attribute__((section(DT_INST_PROP_OR(n, cmdq_buffer_location, ".mspi_buff")))); \ static struct gpio_dt_spec ce_gpios##n[] = MSPI_CE_GPIOS_DT_SPEC_INST_GET(n); \ static struct mspi_ambiq_data mspi_ambiq_data##n = { \ .mspiHandle = NULL, \ .hal_dev_cfg = MSPI_HAL_DEVICE_CONFIG(n, mspi_ambiq_cmdq##n, \ DT_INST_PROP_OR(n, cmdq_buffer_size, 1024)), \ .dev_id = 0, \ .lock = Z_MUTEX_INITIALIZER(mspi_ambiq_data##n.lock), \ .dev_cfg = {0}, \ .xip_cfg = {0}, \ .scramble_cfg = {0}, \ .cbs = {0}, \ .cb_ctxs = {0}, \ .ctx.lock = Z_SEM_INITIALIZER(mspi_ambiq_data##n.ctx.lock, 0, 1), \ .ctx.callback = 0, \ .ctx.callback_ctx = 0, \ }; \ static const struct mspi_ambiq_config mspi_ambiq_config##n = { \ .reg_base = DT_INST_REG_ADDR(n), \ .reg_size = DT_INST_REG_SIZE(n), \ .mspicfg = MSPI_CONFIG(n), \ .mspicfg.ce_group = (struct gpio_dt_spec *)ce_gpios##n, \ .mspicfg.num_ce_gpios = ARRAY_SIZE(ce_gpios##n), \ .mspicfg.re_init = false, \ .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .irq_cfg_func = mspi_ambiq_irq_cfg_func_##n, \ LOG_INSTANCE_PTR_INIT(log, DT_DRV_INST(n), mspi##n) \ }; \ PM_DEVICE_DT_INST_DEFINE(n, mspi_ambiq_pm_action); \ DEVICE_DT_INST_DEFINE(n, \ mspi_ambiq_init, \ PM_DEVICE_DT_INST_GET(n), \ &mspi_ambiq_data##n, \ &mspi_ambiq_config##n, \ POST_KERNEL, \ CONFIG_MSPI_INIT_PRIORITY, \ &mspi_ambiq_driver_api); DT_INST_FOREACH_STATUS_OKAY(AMBIQ_MSPI_DEFINE)