drivers: spi: Add support for Apollo3 SoCs SPI
This commit adds support for the SPI which can be found in Apollo3 SoCs, it can work in both DMA and non-DMA modes Signed-off-by: Hao Luo <hluo@ambiq.com>
This commit is contained in:
parent
ccc570f0c1
commit
524ea22952
8 changed files with 429 additions and 67 deletions
|
@ -101,6 +101,14 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
compatible = "ambiq,spi";
|
||||
pinctrl-0 = <&spi0_default>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <DT_FREQ_M(1)>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c3 {
|
||||
compatible = "ambiq,i2c";
|
||||
pinctrl-0 = <&i2c3_default>;
|
||||
|
|
|
@ -12,6 +12,7 @@ supported:
|
|||
- watchdog
|
||||
- counter
|
||||
- gpio
|
||||
- spi
|
||||
- i2c
|
||||
testing:
|
||||
ignore_tags:
|
||||
|
|
|
@ -101,6 +101,14 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
compatible = "ambiq,spi";
|
||||
pinctrl-0 = <&spi0_default>;
|
||||
pinctrl-names = "default";
|
||||
clock-frequency = <DT_FREQ_M(1)>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c3 {
|
||||
compatible = "ambiq,i2c";
|
||||
pinctrl-0 = <&i2c3_default>;
|
||||
|
|
|
@ -12,6 +12,7 @@ supported:
|
|||
- watchdog
|
||||
- counter
|
||||
- gpio
|
||||
- spi
|
||||
- i2c
|
||||
testing:
|
||||
ignore_tags:
|
||||
|
|
|
@ -15,6 +15,19 @@ config SPI_AMBIQ
|
|||
help
|
||||
Enable driver for Ambiq SPI.
|
||||
|
||||
config SPI_AMBIQ_DMA
|
||||
bool "AMBIQ APOLLO SPI DMA Support"
|
||||
depends on SPI_AMBIQ
|
||||
help
|
||||
Enable DMA for Ambiq SPI.
|
||||
|
||||
config SPI_DMA_TCB_BUFFER_SIZE
|
||||
int "DMA Transfer Control Buffer size in words."
|
||||
default 1024
|
||||
depends on SPI_AMBIQ_DMA
|
||||
help
|
||||
DMA Transfer Control Buffer size in words
|
||||
|
||||
config MSPI_AMBIQ
|
||||
bool "AMBIQ MSPI driver"
|
||||
default y
|
||||
|
|
|
@ -28,20 +28,62 @@ struct spi_ambiq_config {
|
|||
uint32_t clock_freq;
|
||||
const struct pinctrl_dev_config *pcfg;
|
||||
ambiq_spi_pwr_func_t pwr_func;
|
||||
void (*irq_config_func)(void);
|
||||
};
|
||||
|
||||
struct spi_ambiq_data {
|
||||
struct spi_context ctx;
|
||||
am_hal_iom_config_t iom_cfg;
|
||||
void *IOMHandle;
|
||||
void *iom_handler;
|
||||
int inst_idx;
|
||||
};
|
||||
|
||||
#define SPI_BASE (((const struct spi_ambiq_config *)(dev)->config)->base)
|
||||
#define REG_STAT 0x248
|
||||
#define IDLE_STAT 0x4
|
||||
#define SPI_STAT(dev) (SPI_BASE + REG_STAT)
|
||||
typedef void (*spi_context_update_trx)(struct spi_context *ctx, uint8_t dfs, uint32_t len);
|
||||
|
||||
#define SPI_WORD_SIZE 8
|
||||
|
||||
#define SPI_CS_INDEX 3
|
||||
|
||||
#ifdef CONFIG_SPI_AMBIQ_DMA
|
||||
static __aligned(32) struct {
|
||||
__aligned(32) uint32_t buf[CONFIG_SPI_DMA_TCB_BUFFER_SIZE];
|
||||
} spi_dma_tcb_buf[DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)] __attribute__((__section__(".nocache")));
|
||||
|
||||
static void spi_ambiq_callback(void *callback_ctxt, uint32_t status)
|
||||
{
|
||||
const struct device *dev = callback_ctxt;
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
|
||||
spi_context_complete(ctx, dev, (status == AM_HAL_STATUS_SUCCESS) ? 0 : -EIO);
|
||||
}
|
||||
|
||||
static void spi_ambiq_reset(const struct device *dev)
|
||||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
|
||||
/* cancel timed out transaction */
|
||||
am_hal_iom_disable(data->iom_handler);
|
||||
/* NULL config to trigger reconfigure on next xfer */
|
||||
ctx->config = NULL;
|
||||
/* signal any thread waiting on sync semaphore */
|
||||
spi_context_complete(ctx, dev, -ETIMEDOUT);
|
||||
/* clean up for next xfer */
|
||||
k_sem_reset(&ctx->sync);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void spi_ambiq_isr(const struct device *dev)
|
||||
{
|
||||
uint32_t ui32Status;
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
|
||||
am_hal_iom_interrupt_status_get(data->iom_handler, false, &ui32Status);
|
||||
am_hal_iom_interrupt_clear(data->iom_handler, ui32Status);
|
||||
am_hal_iom_interrupt_service(data->iom_handler, ui32Status);
|
||||
}
|
||||
|
||||
static int spi_config(const struct device *dev, const struct spi_config *config)
|
||||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
|
@ -57,12 +99,7 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (config->operation & SPI_HALF_DUPLEX) {
|
||||
LOG_ERR("Half-duplex not supported");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (SPI_WORD_SIZE_GET(config->operation) != 8) {
|
||||
if (SPI_WORD_SIZE_GET(config->operation) != SPI_WORD_SIZE) {
|
||||
LOG_ERR("Word size must be %d", SPI_WORD_SIZE);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
@ -110,75 +147,224 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
|
|||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
data->iom_cfg.ui32ClockFreq = cfg->clock_freq;
|
||||
/* Select slower of two: SPI bus frequency for SPI device or SPI master clock frequency */
|
||||
data->iom_cfg.ui32ClockFreq =
|
||||
(config->frequency ? MIN(config->frequency, cfg->clock_freq) : cfg->clock_freq);
|
||||
ctx->config = config;
|
||||
|
||||
#ifdef CONFIG_SPI_AMBIQ_DMA
|
||||
data->iom_cfg.pNBTxnBuf = spi_dma_tcb_buf[data->inst_idx].buf;
|
||||
data->iom_cfg.ui32NBTxnBufLength = CONFIG_SPI_DMA_TCB_BUFFER_SIZE;
|
||||
#endif
|
||||
|
||||
/* Disable IOM instance as it cannot be configured when enabled*/
|
||||
ret = am_hal_iom_disable(data->IOMHandle);
|
||||
ret = am_hal_iom_disable(data->iom_handler);
|
||||
|
||||
ret = am_hal_iom_configure(data->IOMHandle, &data->iom_cfg);
|
||||
ret = am_hal_iom_configure(data->iom_handler, &data->iom_cfg);
|
||||
|
||||
ret = am_hal_iom_enable(data->IOMHandle);
|
||||
ret = am_hal_iom_enable(data->iom_handler);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_ambiq_xfer_half_duplex(const struct device *dev, am_hal_iom_dir_e dir,
|
||||
am_hal_iom_transfer_t trans, bool cont)
|
||||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
bool is_last = false;
|
||||
uint32_t rem_num, cur_num = 0;
|
||||
size_t count = 0;
|
||||
int ret = 0;
|
||||
spi_context_update_trx ctx_update;
|
||||
|
||||
if (dir == AM_HAL_IOM_FULLDUPLEX) {
|
||||
return -EINVAL;
|
||||
} else if (dir == AM_HAL_IOM_RX) {
|
||||
trans.eDirection = AM_HAL_IOM_RX;
|
||||
count = ctx->rx_count;
|
||||
ctx_update = spi_context_update_rx;
|
||||
} else if (dir == AM_HAL_IOM_TX) {
|
||||
trans.eDirection = AM_HAL_IOM_TX;
|
||||
count = ctx->tx_count;
|
||||
ctx_update = spi_context_update_tx;
|
||||
}
|
||||
/* Only instruction */
|
||||
if ((!count) && (trans.ui32InstrLen)) {
|
||||
trans.bContinue = cont;
|
||||
#ifdef CONFIG_SPI_AMBIQ_DMA
|
||||
if (AM_HAL_STATUS_SUCCESS !=
|
||||
am_hal_iom_nonblocking_transfer(data->iom_handler, &trans, spi_ambiq_callback,
|
||||
(void *)dev)) {
|
||||
spi_ambiq_reset(dev);
|
||||
return -EIO;
|
||||
}
|
||||
ret = spi_context_wait_for_completion(ctx);
|
||||
#else
|
||||
ret = am_hal_iom_blocking_transfer(data->iom_handler, &trans);
|
||||
#endif
|
||||
} else {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (dir == AM_HAL_IOM_RX) {
|
||||
rem_num = ctx->rx_len;
|
||||
} else {
|
||||
rem_num = ctx->tx_len;
|
||||
}
|
||||
while (rem_num) {
|
||||
cur_num = (rem_num > AM_HAL_IOM_MAX_TXNSIZE_SPI)
|
||||
? AM_HAL_IOM_MAX_TXNSIZE_SPI
|
||||
: rem_num;
|
||||
if ((i == (count - 1)) && (cur_num == rem_num)) {
|
||||
is_last = true;
|
||||
}
|
||||
trans.bContinue = (is_last == true) ? cont : true;
|
||||
trans.ui32NumBytes = cur_num;
|
||||
trans.pui32TxBuffer = (uint32_t *)ctx->tx_buf;
|
||||
trans.pui32RxBuffer = (uint32_t *)ctx->rx_buf;
|
||||
#ifdef CONFIG_SPI_AMBIQ_DMA
|
||||
if (AM_HAL_STATUS_SUCCESS !=
|
||||
am_hal_iom_nonblocking_transfer(
|
||||
data->iom_handler, &trans,
|
||||
((is_last == true) ? spi_ambiq_callback : NULL),
|
||||
(void *)dev)) {
|
||||
spi_ambiq_reset(dev);
|
||||
return -EIO;
|
||||
}
|
||||
if (is_last) {
|
||||
ret = spi_context_wait_for_completion(ctx);
|
||||
}
|
||||
#else
|
||||
ret = am_hal_iom_blocking_transfer(data->iom_handler, &trans);
|
||||
#endif
|
||||
rem_num -= cur_num;
|
||||
ctx_update(ctx, 1, cur_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_ambiq_xfer_full_duplex(const struct device *dev, am_hal_iom_dir_e dir,
|
||||
am_hal_iom_transfer_t trans, bool cont)
|
||||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
bool trx_once = (ctx->tx_len == ctx->rx_len);
|
||||
int ret = 0;
|
||||
|
||||
if (dir != AM_HAL_IOM_FULLDUPLEX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Tx and Rx length must be the same for am_hal_iom_spi_blocking_fullduplex */
|
||||
trans.eDirection = dir;
|
||||
trans.ui32NumBytes = MIN(ctx->rx_len, ctx->tx_len);
|
||||
trans.pui32RxBuffer = (uint32_t *)ctx->rx_buf;
|
||||
trans.pui32TxBuffer = (uint32_t *)ctx->tx_buf;
|
||||
trans.bContinue = (trx_once) ? cont : true;
|
||||
spi_context_update_tx(ctx, 1, trans.ui32NumBytes);
|
||||
spi_context_update_rx(ctx, 1, trans.ui32NumBytes);
|
||||
|
||||
ret = am_hal_iom_spi_blocking_fullduplex(data->iom_handler, &trans);
|
||||
|
||||
/* Transfer the remaining bytes */
|
||||
if (!trx_once) {
|
||||
if (ctx->tx_len) {
|
||||
trans.eDirection = AM_HAL_IOM_TX;
|
||||
trans.ui32NumBytes = ctx->tx_len;
|
||||
trans.pui32TxBuffer = (uint32_t *)ctx->tx_buf;
|
||||
} else if (ctx->rx_len) {
|
||||
trans.eDirection = AM_HAL_IOM_RX;
|
||||
trans.ui32NumBytes = ctx->rx_len;
|
||||
trans.pui32RxBuffer = (uint32_t *)ctx->rx_buf;
|
||||
}
|
||||
trans.bContinue = cont;
|
||||
ret = am_hal_iom_blocking_transfer(data->iom_handler, &trans);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_ambiq_fill_instruction(const struct device *dev, am_hal_iom_transfer_t *trans,
|
||||
uint32_t len)
|
||||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* The instruction length can only be:
|
||||
* 0~AM_HAL_IOM_MAX_OFFSETSIZE.
|
||||
* split transaction if oversize
|
||||
*/
|
||||
if (trans->ui32InstrLen + len > AM_HAL_IOM_MAX_OFFSETSIZE) {
|
||||
ret = spi_ambiq_xfer_half_duplex(dev, AM_HAL_IOM_TX, *trans, true);
|
||||
} else {
|
||||
trans->ui32InstrLen += len;
|
||||
for (int i = 0; i < len; i++) {
|
||||
#if defined(CONFIG_SOC_SERIES_APOLLO3X)
|
||||
trans->ui32Instr = (trans->ui32Instr << 8) | (*ctx->tx_buf);
|
||||
#else
|
||||
trans->ui64Instr = (trans->ui64Instr << 8) | (*ctx->tx_buf);
|
||||
#endif
|
||||
spi_context_update_tx(ctx, 1, 1);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_ambiq_xfer(const struct device *dev, const struct spi_config *config)
|
||||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
const struct spi_ambiq_config *cfg = dev->config;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
int ret = 0;
|
||||
bool cont = (config->operation & SPI_HOLD_ON_CS) ? true : false;
|
||||
|
||||
am_hal_iom_transfer_t trans = {0};
|
||||
|
||||
if (ctx->tx_len) {
|
||||
trans.ui64Instr = *ctx->tx_buf;
|
||||
trans.ui32InstrLen = 1;
|
||||
spi_context_update_tx(ctx, 1, 1);
|
||||
/* TODO Need to get iom_nce from different nodes of spi */
|
||||
#if defined(CONFIG_SOC_SERIES_APOLLO3X)
|
||||
trans.uPeerInfo.ui32SpiChipSelect = cfg->pcfg->states->pins[SPI_CS_INDEX].iom_nce;
|
||||
#else
|
||||
trans.uPeerInfo.ui32SpiChipSelect = cfg->pcfg->states->pins[SPI_CS_INDEX].iom_nce % 4;
|
||||
#endif
|
||||
|
||||
if (ctx->rx_buf != NULL) {
|
||||
if (ctx->tx_len > 0) {
|
||||
/* The instruction length can only be 0~5. */
|
||||
if (ctx->tx_len > 4) {
|
||||
spi_context_complete(ctx, dev, 0);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Put the remaining TX data in instruction. */
|
||||
trans.ui32InstrLen += ctx->tx_len;
|
||||
for (int i = 0; i < trans.ui32InstrLen - 1; i++) {
|
||||
trans.ui64Instr = (trans.ui64Instr << 8) | (*ctx->tx_buf);
|
||||
spi_context_update_tx(ctx, 1, 1);
|
||||
}
|
||||
/* There's data to send */
|
||||
if (spi_context_tx_on(ctx)) {
|
||||
/* Always put the first byte to instuction */
|
||||
ret = spi_ambiq_fill_instruction(dev, &trans, 1);
|
||||
/* There's data to Receive */
|
||||
if (spi_context_rx_on(ctx)) {
|
||||
/* Regard the first tx_buf as cmd if there are more than one buffer */
|
||||
if (ctx->rx_count > 1) {
|
||||
ret = spi_ambiq_fill_instruction(dev, &trans, ctx->tx_len);
|
||||
/* Skip the cmd buffer for rx. */
|
||||
spi_context_update_rx(ctx, 1, ctx->rx_len);
|
||||
}
|
||||
|
||||
/* Set RX direction and hold CS to continue to receive data. */
|
||||
trans.eDirection = AM_HAL_IOM_RX;
|
||||
trans.bContinue = true;
|
||||
trans.pui32RxBuffer = (uint32_t *)ctx->rx_buf;
|
||||
trans.ui32NumBytes = ctx->rx_len;
|
||||
ret = am_hal_iom_blocking_transfer(data->IOMHandle, &trans);
|
||||
} else if (ctx->tx_buf != NULL) {
|
||||
/* Set TX direction to send data and release CS after transmission. */
|
||||
trans.eDirection = AM_HAL_IOM_TX;
|
||||
trans.bContinue = false;
|
||||
trans.ui32NumBytes = ctx->tx_len;
|
||||
trans.pui32TxBuffer = (uint32_t *)ctx->tx_buf;
|
||||
ret = am_hal_iom_blocking_transfer(data->IOMHandle, &trans);
|
||||
if ((!(config->operation & SPI_HALF_DUPLEX)) && (spi_context_tx_on(ctx))) {
|
||||
ret = spi_ambiq_xfer_full_duplex(dev, AM_HAL_IOM_FULLDUPLEX, trans,
|
||||
cont);
|
||||
} else {
|
||||
ret = spi_ambiq_xfer_half_duplex(dev, AM_HAL_IOM_RX, trans,
|
||||
cont);
|
||||
}
|
||||
} else { /* There's no data to Receive */
|
||||
/* Regard the first tx_buf as cmd if there are more than one buffer */
|
||||
if (ctx->tx_count > 1) {
|
||||
ret = spi_ambiq_fill_instruction(dev, &trans, ctx->tx_len);
|
||||
}
|
||||
ret = spi_ambiq_xfer_half_duplex(dev, AM_HAL_IOM_TX, trans, cont);
|
||||
}
|
||||
} else {
|
||||
/* Set RX direction to receive data and release CS after transmission. */
|
||||
trans.ui64Instr = 0;
|
||||
trans.ui32InstrLen = 0;
|
||||
trans.eDirection = AM_HAL_IOM_RX;
|
||||
trans.bContinue = false;
|
||||
trans.pui32RxBuffer = (uint32_t *)ctx->rx_buf;
|
||||
trans.ui32NumBytes = ctx->rx_len;
|
||||
ret = am_hal_iom_blocking_transfer(data->IOMHandle, &trans);
|
||||
} else { /* There's no data to send */
|
||||
ret = spi_ambiq_xfer_half_duplex(dev, AM_HAL_IOM_RX, trans, cont);
|
||||
}
|
||||
|
||||
spi_context_complete(ctx, dev, 0);
|
||||
|
||||
#ifndef CONFIG_SPI_AMBIQ_DMA
|
||||
if (!cont) {
|
||||
spi_context_complete(ctx, dev, ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -189,28 +375,39 @@ static int spi_ambiq_transceive(const struct device *dev, const struct spi_confi
|
|||
struct spi_ambiq_data *data = dev->data;
|
||||
int ret;
|
||||
|
||||
if (!tx_bufs && !rx_bufs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* context setup */
|
||||
spi_context_lock(&data->ctx, false, NULL, NULL, config);
|
||||
|
||||
ret = spi_config(dev, config);
|
||||
|
||||
if (ret) {
|
||||
spi_context_release(&data->ctx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!tx_bufs && !rx_bufs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);
|
||||
|
||||
ret = spi_ambiq_xfer(dev, config);
|
||||
|
||||
spi_context_release(&data->ctx, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_ambiq_release(const struct device *dev, const struct spi_config *config)
|
||||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
am_hal_iom_status_t iom_status;
|
||||
|
||||
if (!sys_read32(SPI_STAT(dev))) {
|
||||
am_hal_iom_status_get(data->iom_handler, &iom_status);
|
||||
|
||||
if ((iom_status.bStatIdle != IOM0_STATUS_IDLEST_IDLE) ||
|
||||
(iom_status.bStatCmdAct == IOM0_STATUS_CMDACT_ACTIVE) ||
|
||||
(iom_status.ui32NumPendTransactions)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -228,14 +425,33 @@ static int spi_ambiq_init(const struct device *dev)
|
|||
{
|
||||
struct spi_ambiq_data *data = dev->data;
|
||||
const struct spi_ambiq_config *cfg = dev->config;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
ret = am_hal_iom_initialize((cfg->base - REG_IOM_BASEADDR) / cfg->size, &data->IOMHandle);
|
||||
if (AM_HAL_STATUS_SUCCESS !=
|
||||
am_hal_iom_initialize((cfg->base - REG_IOM_BASEADDR) / cfg->size, &data->iom_handler)) {
|
||||
LOG_ERR("Fail to initialize SPI\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = cfg->pwr_func();
|
||||
|
||||
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
||||
ret |= pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Fail to config SPI pins\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_AMBIQ_DMA
|
||||
am_hal_iom_interrupt_clear(data->iom_handler, AM_HAL_IOM_INT_CQUPD | AM_HAL_IOM_INT_ERR);
|
||||
am_hal_iom_interrupt_enable(data->iom_handler, AM_HAL_IOM_INT_CQUPD | AM_HAL_IOM_INT_ERR);
|
||||
cfg->irq_config_func();
|
||||
#endif
|
||||
end:
|
||||
if (ret < 0) {
|
||||
am_hal_iom_uninitialize(data->iom_handler);
|
||||
} else {
|
||||
spi_context_unlock_unconditionally(&data->ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -249,14 +465,21 @@ static int spi_ambiq_init(const struct device *dev)
|
|||
k_busy_wait(PWRCTRL_MAX_WAIT_US); \
|
||||
return 0; \
|
||||
} \
|
||||
static void spi_irq_config_func_##n(void) \
|
||||
{ \
|
||||
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), spi_ambiq_isr, \
|
||||
DEVICE_DT_INST_GET(n), 0); \
|
||||
irq_enable(DT_INST_IRQN(n)); \
|
||||
}; \
|
||||
static struct spi_ambiq_data spi_ambiq_data##n = { \
|
||||
SPI_CONTEXT_INIT_LOCK(spi_ambiq_data##n, ctx), \
|
||||
SPI_CONTEXT_INIT_SYNC(spi_ambiq_data##n, ctx)}; \
|
||||
SPI_CONTEXT_INIT_SYNC(spi_ambiq_data##n, ctx), .inst_idx = n}; \
|
||||
static const struct spi_ambiq_config spi_ambiq_config##n = { \
|
||||
.base = DT_INST_REG_ADDR(n), \
|
||||
.size = DT_INST_REG_SIZE(n), \
|
||||
.clock_freq = DT_INST_PROP(n, clock_frequency), \
|
||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
||||
.irq_config_func = spi_irq_config_func_##n, \
|
||||
.pwr_func = pwr_on_ambiq_spi_##n}; \
|
||||
DEVICE_DT_INST_DEFINE(n, spi_ambiq_init, NULL, &spi_ambiq_data##n, &spi_ambiq_config##n, \
|
||||
POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, &spi_ambiq_driver_api);
|
||||
|
|
|
@ -160,6 +160,60 @@
|
|||
ambiq,pwrcfg = <&pwrcfg 0x8 0x100>;
|
||||
};
|
||||
|
||||
spi0: spi@50004000 {
|
||||
reg = <0x50004000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <6 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x2>;
|
||||
};
|
||||
|
||||
spi1: spi@50005000 {
|
||||
reg = <0x50005000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <7 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x4>;
|
||||
};
|
||||
|
||||
spi2: spi@50006000 {
|
||||
reg = <0x50006000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <8 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x8>;
|
||||
};
|
||||
|
||||
spi3: spi@50007000 {
|
||||
reg = <0x50007000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <9 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x10>;
|
||||
};
|
||||
|
||||
spi4: spi@50008000 {
|
||||
reg = <0x50008000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <10 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x20>;
|
||||
};
|
||||
|
||||
spi5: spi@50009000 {
|
||||
reg = <0x50009000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <11 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x40>;
|
||||
};
|
||||
|
||||
i2c0: i2c@50004000 {
|
||||
reg = <0x50004000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -160,6 +160,60 @@
|
|||
ambiq,pwrcfg = <&pwrcfg 0x8 0x100>;
|
||||
};
|
||||
|
||||
spi0: spi@50004000 {
|
||||
reg = <0x50004000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <6 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x2>;
|
||||
};
|
||||
|
||||
spi1: spi@50005000 {
|
||||
reg = <0x50005000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <7 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x4>;
|
||||
};
|
||||
|
||||
spi2: spi@50006000 {
|
||||
reg = <0x50006000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <8 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x8>;
|
||||
};
|
||||
|
||||
spi3: spi@50007000 {
|
||||
reg = <0x50007000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <9 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x10>;
|
||||
};
|
||||
|
||||
spi4: spi@50008000 {
|
||||
reg = <0x50008000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <10 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x20>;
|
||||
};
|
||||
|
||||
spi5: spi@50009000 {
|
||||
reg = <0x50009000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <11 0>;
|
||||
status = "disabled";
|
||||
ambiq,pwrcfg = <&pwrcfg 0x8 0x40>;
|
||||
};
|
||||
|
||||
i2c0: i2c@50004000 {
|
||||
reg = <0x50004000 0x1000>;
|
||||
#address-cells = <1>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue