/* * Copyright (c) 2024 Renesas Electronics Corporation * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT renesas_rz_rspi #include #include #include #include #include #include "r_rspi.h" #ifdef CONFIG_SPI_RENESAS_RZ_RSPI_DMAC #include "r_dmac_b.h" #endif #ifdef CONFIG_SPI_RTIO #include #include #endif #include LOG_MODULE_REGISTER(rz_spi); #define LOG_DEV_ERR(dev, format, ...) LOG_ERR("%s:" #format, (dev)->name, ##__VA_ARGS__) #include "spi_context.h" struct spi_rz_rspi_config { const struct pinctrl_dev_config *pinctrl_dev; const spi_api_t *fsp_api; }; struct spi_rz_rspi_data { struct spi_context ctx; uint8_t dfs; uint32_t data_len; spi_cfg_t *fsp_config; rspi_instance_ctrl_t *fsp_ctrl; rspi_extended_cfg_t fsp_extend_config; #ifdef CONFIG_SPI_RTIO struct spi_rtio *rtio_ctx; int rtio_buf_remain; int rtio_tiny_buf_idx; #endif /* CONFIG_SPI_RTIO */ }; #ifdef CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT void rspi_rxi_isr(void); void rspi_txi_isr(void); void rspi_eri_isr(void); #elif defined(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC) void dmac_b_int_isr(void); void rspi_tx_dmac_callback(rspi_instance_ctrl_t *p_ctrl); void rspi_rx_dmac_callback(rspi_instance_ctrl_t *p_ctrl); #endif /* CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT */ #ifdef CONFIG_SPI_RTIO static void spi_rz_rspi_iodev_complete(const struct device *dev, int status); #else static bool spi_rz_rspi_transfer_ongoing(struct spi_rz_rspi_data *data) { #if defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) return (spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx)); #else if (spi_context_total_tx_len(&data->ctx) < spi_context_total_rx_len(&data->ctx)) { return (spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx)); } else { return (spi_context_tx_on(&data->ctx) && spi_context_rx_on(&data->ctx)); } #endif } #endif /* CONFIG_SPI_RTIO */ #ifdef CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT static void spi_rz_rspi_rxi_isr(const struct device *dev) { ARG_UNUSED(dev); rspi_rxi_isr(); } static void spi_rz_rspi_txi_isr(const struct device *dev) { ARG_UNUSED(dev); rspi_txi_isr(); } static void spi_rz_rspi_eri_isr(const struct device *dev) { ARG_UNUSED(dev); rspi_eri_isr(); } #endif /* CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT */ static void spi_rz_rspi_retransmit(struct spi_rz_rspi_data *data) { const uint8_t *tx = NULL; uint8_t *rx = NULL; #ifdef CONFIG_SPI_RTIO struct spi_rtio *rtio_ctx = data->rtio_ctx; struct rtio_sqe *sqe = &rtio_ctx->txn_curr->sqe; switch (sqe->op) { case RTIO_OP_RX: rx = sqe->rx.buf++; break; case RTIO_OP_TX: tx = sqe->tx.buf++; break; case RTIO_OP_TINY_TX: data->rtio_tiny_buf_idx++; tx = &sqe->tiny_tx.buf[data->rtio_tiny_buf_idx]; break; case RTIO_OP_TXRX: rx = sqe->txrx.rx_buf++; tx = sqe->txrx.tx_buf++; break; default: LOG_ERR("Invalid op %d for sqe %p\n", sqe->op, (void *)sqe); return; } #else tx = data->ctx.tx_buf; rx = data->ctx.rx_buf; #endif if (tx == NULL) { /* If there is only the rx buffer */ R_RSPI_Read(data->fsp_ctrl, rx, 1, data->fsp_ctrl->bit_width); } else if (rx == NULL) { /* If there is only the tx buffer */ R_RSPI_Write(data->fsp_ctrl, tx, 1, data->fsp_ctrl->bit_width); } else { R_RSPI_WriteRead(data->fsp_ctrl, tx, rx, 1, data->fsp_ctrl->bit_width); } } static void spi_callbacks(spi_callback_args_t *p_args) { struct device *dev = (struct device *)p_args->p_context; struct spi_rz_rspi_data *data = dev->data; switch (p_args->event) { case SPI_EVENT_TRANSFER_COMPLETE: #ifndef CONFIG_SPI_RTIO spi_context_update_tx(&data->ctx, data->dfs, 1); spi_context_update_rx(&data->ctx, data->dfs, 1); if (spi_rz_rspi_transfer_ongoing(data)) { spi_rz_rspi_retransmit(data); } else { spi_context_complete(&data->ctx, dev, 0); return; } #else if (data->rtio_buf_remain-- > 0) { spi_rz_rspi_retransmit(data); } else { struct spi_rtio *rtio_ctx = data->rtio_ctx; if (rtio_ctx->txn_head != NULL) { spi_rz_rspi_iodev_complete(dev, 0); } } #endif /* CONFIG_SPI_RTIO */ spi_context_complete(&data->ctx, dev, 0); break; case SPI_EVENT_ERR_MODE_FAULT: /* Mode fault error */ case SPI_EVENT_ERR_READ_OVERFLOW: /* Read overflow error */ case SPI_EVENT_ERR_PARITY: /* Parity error */ case SPI_EVENT_ERR_OVERRUN: /* Overrun error */ case SPI_EVENT_ERR_FRAMING: /* Framing error */ case SPI_EVENT_ERR_MODE_UNDERRUN: /* Underrun error */ spi_context_complete(&data->ctx, dev, -EIO); break; default: break; } } static int spi_rz_rspi_configure(const struct device *dev, const struct spi_config *config) { struct spi_rz_rspi_data *data = dev->data; spi_bit_width_t spi_width; fsp_err_t err; if (spi_context_configured(&data->ctx, config)) { /* This configuration is already in use */ return 0; } if (data->fsp_ctrl->open != 0) { R_RSPI_Close(data->fsp_ctrl); } if (config->operation & SPI_FRAME_FORMAT_TI) { LOG_ERR("TI frame not supported"); return -ENOTSUP; } if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && (config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { LOG_DEV_ERR(dev, "Only single line mode is supported"); return -ENOTSUP; } /* SPI mode */ if (config->operation & SPI_OP_MODE_SLAVE) { data->fsp_config->operating_mode = SPI_MODE_SLAVE; } else { data->fsp_config->operating_mode = SPI_MODE_MASTER; } /* SPI POLARITY */ if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) { data->fsp_config->clk_polarity = SPI_CLK_POLARITY_HIGH; } else { data->fsp_config->clk_polarity = SPI_CLK_POLARITY_LOW; } /* SPI PHASE */ if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) { data->fsp_config->clk_phase = SPI_CLK_PHASE_EDGE_EVEN; } else { data->fsp_config->clk_phase = SPI_CLK_PHASE_EDGE_ODD; } /* SPI bit order */ if (config->operation & SPI_TRANSFER_LSB) { data->fsp_config->bit_order = SPI_BIT_ORDER_LSB_FIRST; } else { data->fsp_config->bit_order = SPI_BIT_ORDER_MSB_FIRST; } /* SPI bit width */ spi_width = (spi_bit_width_t)(SPI_WORD_SIZE_GET(config->operation) - 1); if (spi_width > SPI_BIT_WIDTH_16_BITS) { data->dfs = 4; data->fsp_ctrl->bit_width = SPI_BIT_WIDTH_32_BITS; } else if (spi_width > SPI_BIT_WIDTH_8_BITS) { data->dfs = 2; data->fsp_ctrl->bit_width = SPI_BIT_WIDTH_16_BITS; } else { data->dfs = 1; data->fsp_ctrl->bit_width = SPI_BIT_WIDTH_8_BITS; } /* SPI slave select polarity */ if (config->operation & SPI_CS_ACTIVE_HIGH) { data->fsp_extend_config.ssl_polarity = RSPI_SSLP_HIGH; } else { data->fsp_extend_config.ssl_polarity = RSPI_SSLP_LOW; } /* Calculate bitrate */ if (config->frequency > 0) { err = R_RSPI_CalculateBitrate(config->frequency, &data->fsp_extend_config.spck_div); if (err != FSP_SUCCESS) { LOG_DEV_ERR(dev, "rspi: bitrate calculate error: %d", err); return -ENOSYS; } } data->fsp_extend_config.tx_trigger_level = RSPI_TX_TRIGGER_0; data->fsp_extend_config.rx_trigger_level = RSPI_RX_TRIGGER_1; data->fsp_config->p_extend = &data->fsp_extend_config; /* Add callback, which will be called when transfer completed or error occur. */ data->fsp_config->p_callback = spi_callbacks; /* Data is passed into spi_callbacks. */ data->fsp_config->p_context = dev; /* Open module RSPI. */ err = R_RSPI_Open(data->fsp_ctrl, data->fsp_config); if (err != FSP_SUCCESS) { LOG_ERR("R_RSPI_Open error: %d", err); return -EINVAL; } data->ctx.config = config; return 0; } #if !defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) && !defined(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC) static int spi_rz_rspi_transceive_data(struct spi_rz_rspi_data *data) { R_RSPI0_Type *p_spi_reg = (R_RSPI0_Type *)data->fsp_ctrl->p_regs; uint32_t data_count = (p_spi_reg->SPBFDR & R_RSPI0_SPBFDR_T_Msk) >> R_RSPI0_SPBFDR_T_Pos; data_count = 8 - data_count; while (!p_spi_reg->SPSR_b.SPTEF) { } /* TX transfer */ if (data_count) { if (data->dfs > 2) { if (spi_context_tx_buf_on(&data->ctx)) { p_spi_reg->SPDR = *(uint32_t *)(data->ctx.tx_buf); } else { p_spi_reg->SPDR = 0; } } else if (data->dfs > 1) { if (spi_context_tx_buf_on(&data->ctx)) { p_spi_reg->SPDR_hword.L = *(uint16_t *)(data->ctx.tx_buf); } else { p_spi_reg->SPDR_hword.L = 0; } } else { if (spi_context_tx_buf_on(&data->ctx)) { p_spi_reg->SPDR_byte.LL = *(uint8_t *)(data->ctx.tx_buf); } else { p_spi_reg->SPDR_byte.LL = 0; } } } /* Clear Transmit Buffer Empty Flags */ p_spi_reg->SPBFCR = R_RSPI0_SPBFCR_TXRST_Msk; spi_context_update_tx(&data->ctx, data->dfs, 1); /* RX transfer */ if (spi_context_rx_on(&data->ctx)) { while (!p_spi_reg->SPSR_b.SPRF) { } /* Read data from Data Register */ if (data->dfs > 2) { UNALIGNED_PUT(p_spi_reg->SPDR, (uint32_t *)data->ctx.rx_buf); } else if (data->dfs > 1) { UNALIGNED_PUT(p_spi_reg->SPDR_hword.L, (uint16_t *)data->ctx.rx_buf); } else { UNALIGNED_PUT(p_spi_reg->SPDR_byte.LL, (uint8_t *)data->ctx.rx_buf); } /* Clear Receive Buffer Full Flag */ p_spi_reg->SPBFCR = R_RSPI0_SPBFCR_RXRST_Msk; spi_context_update_rx(&data->ctx, data->dfs, 1); } return 0; } #endif /* #if !defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) */ /* && !defined(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC) */ static int transceive(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, bool asynchronous, spi_callback_t cb, void *userdata) { struct spi_rz_rspi_data *data = dev->data; struct spi_context *spi_ctx = &data->ctx; int ret = 0; if (!tx_bufs && !rx_bufs) { return 0; } #ifndef CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT if (asynchronous) { return -ENOTSUP; } #endif spi_context_lock(spi_ctx, asynchronous, cb, userdata, config); #ifndef CONFIG_SPI_RTIO /* Configure module RSPI. */ ret = spi_rz_rspi_configure(dev, config); if (ret) { spi_context_release(spi_ctx, ret); return -EIO; } /* Setup tx buffer and rx buffer info. */ spi_context_buffers_setup(spi_ctx, tx_bufs, rx_bufs, data->dfs); spi_context_cs_control(spi_ctx, true); #if (defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) || defined(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC)) if (data->ctx.tx_buf == NULL) { /* If there is only the rx buffer */ ret = R_RSPI_Read(data->fsp_ctrl, data->ctx.rx_buf, 1, data->fsp_ctrl->bit_width); } else if (data->ctx.rx_buf == NULL) { /* If there is only the tx buffer */ ret = R_RSPI_Write(data->fsp_ctrl, data->ctx.tx_buf, 1, data->fsp_ctrl->bit_width); } else { ret = R_RSPI_WriteRead(data->fsp_ctrl, data->ctx.tx_buf, data->ctx.rx_buf, 1, data->fsp_ctrl->bit_width); } if (ret) { LOG_ERR("Async transmit fail: %d", ret); return -EIO; } ret = spi_context_wait_for_completion(spi_ctx); #else spi_bit_width_t spi_width = (spi_bit_width_t)(SPI_WORD_SIZE_GET(data->ctx.config->operation) - 1); /* Enable the SPI transfer */ data->fsp_ctrl->p_regs->SPCR_b.SPE = 1; data->fsp_ctrl->p_regs->SPBFCR = (3 << R_RSPI0_SPBFCR_TXTRG_Pos); data->fsp_ctrl->p_regs->SPBFCR |= R_RSPI0_SPBFCR_TXRST_Msk | R_RSPI0_SPBFCR_RXRST_Msk; if (spi_width > SPI_BIT_WIDTH_16_BITS) { data->fsp_ctrl->p_regs->SPDCR |= (3 << R_RSPI0_SPDCR_SPLW_Pos); data->fsp_ctrl->p_regs->SPCMD0 |= (3 << R_RSPI0_SPCMD0_SPB_Pos); } else if (spi_width > SPI_BIT_WIDTH_8_BITS) { data->fsp_ctrl->p_regs->SPDCR |= (2 << R_RSPI0_SPDCR_SPLW_Pos); data->fsp_ctrl->p_regs->SPCMD0 |= (15 << R_RSPI0_SPCMD0_SPB_Pos); } else { data->fsp_ctrl->p_regs->SPDCR |= (1 << R_RSPI0_SPDCR_SPLW_Pos); data->fsp_ctrl->p_regs->SPCMD0 |= (7 << R_RSPI0_SPCMD0_SPB_Pos); } do { spi_rz_rspi_transceive_data(data); } while (spi_rz_rspi_transfer_ongoing(data)); /* Wait for transmit complete */ while (!data->fsp_ctrl->p_regs->SPSR_b.TEND) { } /* Disable the SPI Transfer. */ data->fsp_ctrl->p_regs->SPCR_b.SPE = 0; #endif /* #if (defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) */ /* || defined(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC)) */ #ifdef CONFIG_SPI_SLAVE if (spi_context_is_slave(spi_ctx) && !ret) { ret = spi_ctx->recv_frames; } #endif /* CONFIG_SPI_SLAVE */ spi_context_cs_control(spi_ctx, false); #else struct spi_rtio *rtio_ctx = data->rtio_ctx; ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs); #endif /* CONFIG_SPI_RTIO */ spi_context_release(spi_ctx, ret); return ret; } static int spi_rz_rspi_transceive_sync(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs) { return transceive(dev, config, tx_bufs, rx_bufs, false, NULL, NULL); } static int spi_rz_rspi_release(const struct device *dev, const struct spi_config *config) { struct spi_rz_rspi_data *data = dev->data; spi_context_unlock_unconditionally(&data->ctx); return 0; } #ifdef CONFIG_SPI_ASYNC static int spi_rz_rspi_transceive_async(const struct device *dev, const struct spi_config *config, const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs, spi_callback_t cb, void *userdata) { return transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata); } #endif /* CONFIG_SPI_ASYNC */ #ifdef CONFIG_SPI_RTIO static inline void spi_rz_rspi_iodev_prepare_start(const struct device *dev) { struct spi_rz_rspi_data *data = dev->data; struct spi_rtio *rtio_ctx = data->rtio_ctx; struct spi_dt_spec *spi_dt_spec = rtio_ctx->txn_curr->sqe.iodev->data; struct spi_config *config = &spi_dt_spec->config; int err; err = spi_rz_rspi_configure(dev, config); if (err != 0) { LOG_ERR("RTIO config spi error: %d", err); } spi_context_cs_control(&data->ctx, true); } static void spi_rz_rspi_iodev_start(const struct device *dev) { struct spi_rz_rspi_data *data = dev->data; struct spi_rtio *rtio_ctx = data->rtio_ctx; struct rtio_sqe *sqe = &rtio_ctx->txn_curr->sqe; int ret = 0; switch (sqe->op) { case RTIO_OP_RX: data->rtio_buf_remain = sqe->rx.buf_len; ret = R_RSPI_Read(data->fsp_ctrl, sqe->rx.buf, 1, data->fsp_ctrl->bit_width); break; case RTIO_OP_TX: data->rtio_buf_remain = sqe->tx.buf_len; ret = R_RSPI_Write(data->fsp_ctrl, sqe->tx.buf, 1, data->fsp_ctrl->bit_width); break; case RTIO_OP_TINY_TX: data->rtio_buf_remain = sqe->tiny_tx.buf_len; data->rtio_tiny_buf_idx = 0; ret = R_RSPI_Write(data->fsp_ctrl, sqe->tiny_tx.buf, 1, data->fsp_ctrl->bit_width); break; case RTIO_OP_TXRX: data->rtio_buf_remain = sqe->txrx.buf_len; ret = R_RSPI_WriteRead(data->fsp_ctrl, sqe->txrx.tx_buf, sqe->txrx.rx_buf, 1, data->fsp_ctrl->bit_width); break; default: spi_rz_rspi_iodev_complete(dev, -EINVAL); break; } if (ret != 0) { spi_rz_rspi_iodev_complete(dev, ret); } } static void spi_rz_rspi_iodev_complete(const struct device *dev, int status) { struct spi_rz_rspi_data *data = dev->data; struct spi_rtio *rtio_ctx = data->rtio_ctx; if (!status && rtio_ctx->txn_curr->sqe.flags & RTIO_SQE_TRANSACTION) { rtio_ctx->txn_curr = rtio_txn_next(rtio_ctx->txn_curr); spi_rz_rspi_iodev_start(dev); } else { spi_context_cs_control(&data->ctx, false); /* * Submit the result of the operation to the completion queue * This may start the next asynchronous request if one is available */ if (spi_rtio_complete(rtio_ctx, status)) { spi_rz_rspi_iodev_prepare_start(dev); spi_rz_rspi_iodev_start(dev); } } } static void spi_rz_rspi_iodev_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe) { struct spi_rz_rspi_data *data = dev->data; struct spi_rtio *rtio_ctx = data->rtio_ctx; /* Submit sqe to the queue */ if (spi_rtio_submit(rtio_ctx, iodev_sqe)) { spi_rz_rspi_iodev_prepare_start(dev); spi_rz_rspi_iodev_start(dev); } } #endif /* CONFIG_SPI_RTIO */ static DEVICE_API(spi, spi_rz_rspi_driver_api) = { .transceive = spi_rz_rspi_transceive_sync, .release = spi_rz_rspi_release, #ifdef CONFIG_SPI_ASYNC .transceive_async = spi_rz_rspi_transceive_async, #endif /* CONFIG_SPI_ASYNC */ #ifdef CONFIG_SPI_RTIO .iodev_submit = spi_rz_rspi_iodev_submit, #endif /* CONFIG_SPI_RTIO */ }; static int spi_rz_rspi_init(const struct device *dev) { const struct spi_rz_rspi_config *config = dev->config; struct spi_rz_rspi_data *data = dev->data; uint32_t rate; int ret; ret = pinctrl_apply_state(config->pinctrl_dev, PINCTRL_STATE_DEFAULT); if (ret < 0) { LOG_ERR("pinctrl_apply_state fail: %d", ret); return ret; } ret = spi_context_cs_configure_all(&data->ctx); if (ret < 0) { LOG_ERR("spi_context_cs_configure_all fail: %d", ret); return ret; } rate = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_P0CLK); if (rate < 0) { LOG_ERR("Failed to get clk, rate: %d", rate); return ret; } #if CONFIG_SPI_RTIO spi_rtio_init(data->rtio_ctx, dev); #endif /* CONFIG_SPI_RTIO */ spi_context_unlock_unconditionally(&data->ctx); return 0; } #ifdef CONFIG_SPI_RENESAS_RZ_RSPI_DMAC #define RZ_DMA_CHANNEL_CONFIG(id, dir) DT_INST_DMAS_CELL_BY_NAME(id, dir, config) #define RZ_DMA_MODE(config) ((config) & 0x1) #define RZ_DMA_SRC_DATA_SIZE(config) ((config >> 1) & 0x7) #define RZ_DMA_DEST_DATA_SIZE(config) ((config >> 4) & 0x7) #define RZ_DMA_SRC_ADDR_MODE(config) ((config >> 7) & 0x1) #define RZ_DMA_DEST_ADDR_MODE(config) ((config >> 8) & 0x1) #define RSPI_DMA_RZG_DEFINE(n, dir, TRIG, spi_channel) \ static dmac_b_instance_ctrl_t g_transfer##n##_##dir##_ctrl; \ static void g_spi##n##_##dir##_transfer_callback(dmac_b_callback_args_t *p_args) \ { \ FSP_PARAMETER_NOT_USED(p_args); \ rspi_##dir##_dmac_callback(&g_spi##n##_ctrl); \ } \ transfer_info_t g_transfer##n##_##dir##_info = { \ .dest_addr_mode = RZ_DMA_DEST_ADDR_MODE(RZ_DMA_CHANNEL_CONFIG(n, dir)), \ .src_addr_mode = RZ_DMA_SRC_ADDR_MODE(RZ_DMA_CHANNEL_CONFIG(n, dir)), \ .mode = RZ_DMA_MODE(RZ_DMA_CHANNEL_CONFIG(n, dir)), \ .p_dest = (void *)NULL, \ .p_src = (void const *)NULL, \ .length = 0, \ .src_size = RZ_DMA_SRC_DATA_SIZE(RZ_DMA_CHANNEL_CONFIG(n, dir)), \ .dest_size = RZ_DMA_DEST_DATA_SIZE(RZ_DMA_CHANNEL_CONFIG(n, dir)), \ .p_next1_src = NULL, \ .p_next1_dest = NULL, \ .next1_length = 1, \ }; \ const dmac_b_extended_cfg_t g_transfer##n##_##dir##_extend = { \ .unit = 0, \ .channel = DT_INST_DMAS_CELL_BY_NAME(n, dir, channel), \ .dmac_int_irq = DT_IRQ_BY_NAME( \ DT_INST_DMAS_CTLR_BY_NAME(n, dir), \ UTIL_CAT(ch, DT_INST_DMAS_CELL_BY_NAME(n, dir, channel)), irq), \ .dmac_int_ipl = DT_IRQ_BY_NAME( \ DT_INST_DMAS_CTLR_BY_NAME(n, dir), \ UTIL_CAT(ch, DT_INST_DMAS_CELL_BY_NAME(n, dir, channel)), priority), \ .activation_source = UTIL_CAT(DMAC_TRIGGER_EVENT_RSPI_SP##TRIG, spi_channel), \ .ack_mode = DMAC_B_ACK_MODE_MASK_DACK_OUTPUT, \ .external_detection_mode = DMAC_B_EXTERNAL_DETECTION_NO_DETECTION, \ .internal_detection_mode = DMAC_B_INTERNAL_DETECTION_NO_DETECTION, \ .activation_request_source_select = DMAC_B_REQUEST_DIRECTION_SOURCE_MODULE, \ .dmac_mode = DMAC_B_MODE_SELECT_REGISTER, \ .continuous_setting = DMAC_B_CONTINUOUS_SETTING_TRANSFER_ONCE, \ .transfer_interval = 0, \ .channel_scheduling = DMAC_B_CHANNEL_SCHEDULING_FIXED, \ .p_callback = g_spi##n##_##dir##_transfer_callback, \ .p_context = NULL, \ }; \ const transfer_cfg_t g_transfer##n##_##dir##_cfg = { \ .p_info = &g_transfer##n##_##dir##_info, \ .p_extend = &g_transfer##n##_##dir##_extend, \ }; \ const transfer_instance_t g_transfer##n##_##dir = { \ .p_ctrl = &g_transfer##n##_##dir##_ctrl, \ .p_cfg = &g_transfer##n##_##dir##_cfg, \ .p_api = &g_transfer_on_dmac_b, \ }; #define RZ_RSPI_IRQ_INIT(n) \ do { \ IRQ_CONNECT( \ DT_IRQ_BY_NAME(DT_INST_DMAS_CTLR_BY_NAME(n, rx), \ UTIL_CAT(ch, DT_INST_DMAS_CELL_BY_NAME(n, rx, channel)), \ irq), \ DT_IRQ_BY_NAME(DT_INST_DMAS_CTLR_BY_NAME(n, rx), \ UTIL_CAT(ch, DT_INST_DMAS_CELL_BY_NAME(n, rx, channel)), \ priority), \ dmac_b_int_isr, DEVICE_DT_INST_GET(n), 0); \ IRQ_CONNECT( \ DT_IRQ_BY_NAME(DT_INST_DMAS_CTLR_BY_NAME(n, tx), \ UTIL_CAT(ch, DT_INST_DMAS_CELL_BY_NAME(n, tx, channel)), \ irq), \ DT_IRQ_BY_NAME(DT_INST_DMAS_CTLR_BY_NAME(n, tx), \ UTIL_CAT(ch, DT_INST_DMAS_CELL_BY_NAME(n, tx, channel)), \ priority), \ dmac_b_int_isr, DEVICE_DT_INST_GET(n), 0); \ } while (0) #elif defined(CONFIG_SPI_RENESAS_RZ_RSPI_INTERRUPT) #define RZ_RSPI_IRQ_INIT(n) \ do { \ IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, rx, irq), DT_INST_IRQ_BY_NAME(n, rx, priority), \ spi_rz_rspi_rxi_isr, DEVICE_DT_INST_GET(n), 0); \ IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, tx, irq), DT_INST_IRQ_BY_NAME(n, tx, priority), \ spi_rz_rspi_txi_isr, DEVICE_DT_INST_GET(n), 0); \ IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, error, irq), \ DT_INST_IRQ_BY_NAME(n, error, priority), spi_rz_rspi_eri_isr, \ DEVICE_DT_INST_GET(n), 0); \ irq_enable(DT_INST_IRQ_BY_NAME(n, rx, irq)); \ irq_enable(DT_INST_IRQ_BY_NAME(n, tx, irq)); \ irq_enable(DT_INST_IRQ_BY_NAME(n, error, irq)); \ } while (0) #else #define RZ_RSPI_IRQ_INIT(n) #endif /* CONFIG_SPI_RENESAS_RZ_RSPI_DMAC */ #define SPI_RZ_RSPI_RTIO_DEFINE(n) \ SPI_RTIO_DEFINE(spi_rz_rspi_rtio_##n, CONFIG_SPI_RTIO_SQ_SIZE, CONFIG_SPI_RTIO_CQ_SIZE) #define SPI_RZ_RSPI_INIT(n) \ PINCTRL_DT_INST_DEFINE(n); \ COND_CODE_1(CONFIG_SPI_RTIO, (SPI_RZ_RSPI_RTIO_DEFINE(n)), \ ()); \ static rspi_instance_ctrl_t g_spi##n##_ctrl; \ static rspi_extended_cfg_t g_spi_##n##_cfg_extend = { \ .ssl_polarity = RSPI_SSLP_LOW, \ .mosi_idle = RSPI_MOSI_IDLE_VALUE_FIXING_DISABLE, \ .spck_div = \ { \ .spbr = 4, \ .brdv = 0, \ }, \ .spck_delay = RSPI_DELAY_COUNT_1, \ .ssl_negation_delay = RSPI_DELAY_COUNT_1, \ .next_access_delay = RSPI_DELAY_COUNT_1, \ .ssl_level_keep = RSPI_SSL_LEVEL_KEEP_DISABLE, \ .rx_trigger_level = RSPI_RX_TRIGGER_24, \ .tx_trigger_level = RSPI_TX_TRIGGER_4, \ }; \ IF_ENABLED(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC, \ (RSPI_DMA_RZG_DEFINE(n, tx, TI, DT_INST_PROP(n, channel)))) \ IF_ENABLED(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC, \ (RSPI_DMA_RZG_DEFINE(n, rx, RI, DT_INST_PROP(n, channel)))) \ static spi_cfg_t g_spi_##n##_config = { \ .channel = DT_INST_PROP(n, channel), \ .eri_irq = DT_INST_IRQ_BY_NAME(n, error, irq), \ .rxi_ipl = DT_INST_IRQ_BY_NAME(n, rx, priority), \ .txi_ipl = DT_INST_IRQ_BY_NAME(n, tx, priority), \ .eri_ipl = DT_INST_IRQ_BY_NAME(n, error, priority), \ .operating_mode = SPI_MODE_MASTER, \ .clk_phase = SPI_CLK_PHASE_EDGE_ODD, \ .clk_polarity = SPI_CLK_POLARITY_LOW, \ .mode_fault = SPI_MODE_FAULT_ERROR_ENABLE, \ .bit_order = SPI_BIT_ORDER_MSB_FIRST, \ .p_callback = NULL, \ .p_context = NULL, \ .p_extend = &g_spi_##n##_cfg_extend, \ COND_CODE_1(CONFIG_SPI_RENESAS_RZ_RSPI_DMAC, \ ( \ .rxi_irq = FSP_INVALID_VECTOR, \ .txi_irq = FSP_INVALID_VECTOR, \ .p_transfer_tx = &g_transfer##n##_tx, \ .p_transfer_rx = &g_transfer##n##_rx,), \ ( \ .rxi_irq = DT_INST_IRQ_BY_NAME(n, rx, irq), \ .txi_irq = DT_INST_IRQ_BY_NAME(n, tx, irq), \ .p_transfer_tx = NULL, \ .p_transfer_rx = NULL,)) }; \ static const struct spi_rz_rspi_config spi_rz_rspi_config_##n = { \ .pinctrl_dev = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ .fsp_api = &g_spi_on_rspi, \ }; \ static struct spi_rz_rspi_data spi_rz_rspi_data_##n = { \ SPI_CONTEXT_INIT_LOCK(spi_rz_rspi_data_##n, ctx), \ SPI_CONTEXT_INIT_SYNC(spi_rz_rspi_data_##n, ctx), \ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx).fsp_ctrl = &g_spi##n##_ctrl, \ .fsp_config = &g_spi_##n##_config, \ IF_ENABLED(CONFIG_SPI_RTIO, \ (.rtio_ctx = &spi_rz_rspi_rtio_##n,)) }; \ static int spi_rz_rspi_init_##n(const struct device *dev) \ { \ int err = spi_rz_rspi_init(dev); \ if (err != 0) { \ return err; \ } \ RZ_RSPI_IRQ_INIT(n); \ return 0; \ } \ DEVICE_DT_INST_DEFINE(n, &spi_rz_rspi_init_##n, NULL, &spi_rz_rspi_data_##n, \ &spi_rz_rspi_config_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ &spi_rz_rspi_driver_api); DT_INST_FOREACH_STATUS_OKAY(SPI_RZ_RSPI_INIT)