/*
 * Copyright (c) 2024, Ambiq Micro Inc. <www.ambiq.com>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT ambiq_mspi_controller

#include <zephyr/logging/log.h>
#include <zephyr/logging/log_instance.h>
LOG_MODULE_REGISTER(mspi_ambiq_ap3);
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#include <zephyr/pm/device.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/mspi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/sys_clock.h>
#include <zephyr/irq.h>

#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 struct mspi_driver_api 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)
