Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

869 lines
25 KiB

/*
* Copyright (c) 2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT renesas_rx_rspi
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/irq.h>
#include <soc.h>
#include "r_rspi_rx_if.h"
#include "iodefine.h"
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(rx_rspi);
#include "spi_context.h"
#if defined(CONFIG_SPI_RENESAS_RX_INTERRUPT)
typedef enum {
/* Values will be used as bit flags.*/
RSPI_DO_TX = 0x1,
RSPI_DO_RX = 0x2,
RSPI_DO_TX_RX = 0x3
} rspi_operation_t;
typedef struct rx_rspi_tcb_s {
rspi_operation_t transfer_mode;
rspi_str_tranmode_t data_tran_mode;
uint16_t tx_count;
uint16_t rx_count;
uint16_t xfr_length;
uint8_t bytes_per_transfer;
bool do_rx_now;
bool do_tx;
} rx_rspi_tcb_t;
static uint8_t rspi_get_data_type(rspi_command_word_t command_word)
{
switch (command_word.bit_length) {
case RSPI_SPCMD_BIT_LENGTH_8:
return RSPI_BYTE_DATA;
case RSPI_SPCMD_BIT_LENGTH_9:
case RSPI_SPCMD_BIT_LENGTH_10:
case RSPI_SPCMD_BIT_LENGTH_11:
case RSPI_SPCMD_BIT_LENGTH_12:
case RSPI_SPCMD_BIT_LENGTH_13:
case RSPI_SPCMD_BIT_LENGTH_14:
case RSPI_SPCMD_BIT_LENGTH_15:
case RSPI_SPCMD_BIT_LENGTH_16:
return RSPI_WORD_DATA;
case RSPI_SPCMD_BIT_LENGTH_20:
case RSPI_SPCMD_BIT_LENGTH_24:
case RSPI_SPCMD_BIT_LENGTH_32:
return RSPI_LONG_DATA;
default:
return 0;
}
} /* End of function rspi_get_data_type */
#endif /* CONFIG_SPI_RENESAS_RX_INTERRUPT */
struct rx_rspi_data {
struct spi_context ctx;
int channel_id;
int ssl_assert;
volatile struct st_rspi *preg;
rspi_handle_t rspi;
rspi_chnl_settings_t channel_setting;
rspi_command_word_t command_word;
rspi_callback_data_t callback_data;
uint8_t dfs;
#if CONFIG_SPI_RENESAS_RX_INTERRUPT
rx_rspi_tcb_t tcb;
uint32_t rxdata;
uint32_t data_len;
#endif
};
struct rx_rspi_config {
const struct pinctrl_dev_config *pcfg;
};
static void spi_cb(void *p_args)
{
struct device *dev = (struct device *)p_args;
struct rx_rspi_data *data = dev->data;
switch (data->callback_data.event_code) {
case RSPI_EVT_TRANSFER_COMPLETE:
spi_context_cs_control(&data->ctx, false);
spi_context_complete(&data->ctx, dev, 0);
break;
case RSPI_EVT_TRANSFER_ABORTED:
case RSPI_EVT_ERR_MODE_FAULT:
case RSPI_EVT_ERR_READ_OVF:
case RSPI_EVT_ERR_PARITY:
case RSPI_EVT_ERR_UNDER_RUN:
case RSPI_EVT_ERR_UNDEF:
spi_context_cs_control(&data->ctx, false);
spi_context_complete(&data->ctx, dev, -EIO);
break;
default:
break;
}
}
#if defined(CONFIG_SPI_RENESAS_RX_INTERRUPT)
static void transmit_data(struct rx_rspi_data *data, uint16_t tx_count)
{
rx_rspi_tcb_t *rspi_tcb = &(data->tcb);
void *psrc = (void *)data->ctx.tx_buf;
uint8_t data_size = rspi_tcb->bytes_per_transfer;
if (rspi_tcb->do_tx) {
if (RSPI_BYTE_DATA == data_size) {
data->preg->SPDR.LONG = ((uint8_t *)psrc)[tx_count];
} else if (RSPI_WORD_DATA == data_size) {
data->preg->SPDR.LONG = ((uint16_t *)psrc)[tx_count];
} else {
data->preg->SPDR.LONG = ((uint32_t *)psrc)[tx_count];
}
} else {
data->preg->SPDR.LONG = 0;
}
}
void rx_rspi_spti_sub(const struct device *dev)
{
struct rx_rspi_data *data = dev->data;
rx_rspi_tcb_t *rspi_tcb = &(data->tcb);
uint16_t tx_count = rspi_tcb->tx_count;
/* If transmit only, enable SPII interrupt in transmit */
if ((!spi_context_rx_on(&data->ctx)) && (tx_count == rspi_tcb->xfr_length - 1)) {
data->preg->SPCR2.BIT.SPIIE = 1;
/* If the SPI is in slave mode */
if (spi_context_is_slave(&data->ctx)) {
/* Disable RSPI */
data->preg->SPCR.BIT.SPE = 0;
/**
* Transfer complete. Call the user callback function passing
* pointer to the result structure.
*/
if (data->rspi->pcallback != NULL) {
data->callback_data.handle = data->rspi;
data->callback_data.event_code = RSPI_EVT_TRANSFER_COMPLETE;
data->rspi->pcallback((void *)dev);
}
}
}
/* Service the hardware first to keep it busy. */
/* Feed the TX. */
if (tx_count < rspi_tcb->xfr_length) {
transmit_data(data, tx_count);
rspi_tcb->tx_count++;
} else {
if (spi_context_is_slave(&data->ctx)) {
spi_context_update_tx(&data->ctx, data->dfs, data->data_len);
}
}
}
#endif
static int rx_rspi_configure(const struct device *dev, const struct spi_config *config)
{
struct rx_rspi_data *data = dev->data;
rspi_err_t err;
if (spi_context_configured(&data->ctx, config)) {
/* Nothing to do */
return 0;
}
err = R_RSPI_Close(data->rspi);
if ((config->operation & SPI_FRAME_FORMAT_TI) == SPI_FRAME_FORMAT_TI) {
return -ENOTSUP;
}
if (config->operation & SPI_OP_MODE_SLAVE) {
data->channel_setting.master_slave_mode = RSPI_MS_MODE_SLAVE;
} else {
data->channel_setting.master_slave_mode = RSPI_MS_MODE_MASTER;
}
if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) {
data->command_word.cpol = RSPI_SPCMD_CPOL_IDLE_HI;
} else {
data->command_word.cpol = RSPI_SPCMD_CPOL_IDLE_LO;
}
if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) {
data->command_word.cpha = RSPI_SPCMD_CPHA_SAMPLE_EVEN;
} else {
if (data->channel_setting.master_slave_mode == RSPI_MS_MODE_MASTER) {
data->command_word.cpha = RSPI_SPCMD_CPHA_SAMPLE_ODD;
} else {
/* In slave mode cpha must be 1 */
LOG_ERR("Invalid clock phase");
return -EINVAL;
}
}
if (config->operation & SPI_TRANSFER_LSB) {
data->command_word.bit_order = RSPI_SPCMD_ORDER_LSB_FIRST;
} else {
data->command_word.bit_order = RSPI_SPCMD_ORDER_MSB_FIRST;
}
if (spi_cs_is_gpio(config) || !IS_ENABLED(CONFIG_SPI_RENESAS_RX_USE_HW_SS)) {
data->channel_setting.gpio_ssl = RSPI_IF_MODE_3WIRE;
} else {
data->channel_setting.gpio_ssl = RSPI_IF_MODE_4WIRE;
switch (data->ssl_assert) {
case 0:
data->command_word.ssl_assert = RSPI_SPCMD_ASSERT_SSL0;
break;
case 1:
data->command_word.ssl_assert = RSPI_SPCMD_ASSERT_SSL1;
break;
case 2:
data->command_word.ssl_assert = RSPI_SPCMD_ASSERT_SSL2;
break;
case 3:
data->command_word.ssl_assert = RSPI_SPCMD_ASSERT_SSL3;
break;
default:
LOG_ERR("Invalid SSL");
return -EINVAL;
}
}
data->channel_setting.bps_target = config->frequency;
data->channel_setting.tran_mode = RSPI_TRANS_MODE_SW;
uint8_t array_rspi_bit_length[] = {
RSPI_SPCMD_BIT_LENGTH_8, RSPI_SPCMD_BIT_LENGTH_9, RSPI_SPCMD_BIT_LENGTH_10,
RSPI_SPCMD_BIT_LENGTH_11, RSPI_SPCMD_BIT_LENGTH_12, RSPI_SPCMD_BIT_LENGTH_13,
RSPI_SPCMD_BIT_LENGTH_14, RSPI_SPCMD_BIT_LENGTH_15, RSPI_SPCMD_BIT_LENGTH_16};
uint16_t bit_frame_size = SPI_WORD_SIZE_GET(config->operation);
if (bit_frame_size >= 8 && bit_frame_size <= 16) {
data->command_word.bit_length = array_rspi_bit_length[bit_frame_size - 8];
} else {
switch (bit_frame_size) {
case 20:
data->command_word.bit_length = RSPI_SPCMD_BIT_LENGTH_20;
break;
case 24:
data->command_word.bit_length = RSPI_SPCMD_BIT_LENGTH_24;
break;
case 32:
data->command_word.bit_length = RSPI_SPCMD_BIT_LENGTH_32;
break;
default:
return -ENOTSUP;
}
}
err = R_RSPI_Open(data->channel_id, &data->channel_setting, data->command_word, spi_cb,
&data->rspi);
if (err != RSPI_SUCCESS) {
LOG_ERR("R_RSPI_Open error: %d", err);
return -EINVAL;
#if defined(CONFIG_SPI_RENESAS_RX_INTERRUPT)
} else {
data->tcb.data_tran_mode = data->channel_setting.tran_mode;
#endif
}
/* Manually set these bits, because the Open function not */
data->preg->SPCMD0.BIT.CPHA = data->command_word.cpha;
data->preg->SPCMD0.BIT.LSBF = data->command_word.bit_order;
data->preg->SPCMD0.BIT.SSLA = data->command_word.ssl_assert;
/* Set the ctx config = config for next time enter the function */
data->ctx.config = config;
return 0;
}
static bool rx_spi_transfer_ongoing(struct rx_rspi_data *data)
{
#if defined(CONFIG_SPI_RENESAS_RX_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
}
#ifndef CONFIG_SPI_RENESAS_RX_INTERRUPT
static int rx_rspi_transceive_slave(struct rx_rspi_data *data)
{
if (data->preg->SPSR.BIT.SPTEF && spi_context_tx_on(&data->ctx)) {
uint32_t tx;
if (data->ctx.tx_buf != NULL) {
if (data->dfs > 2) {
tx = UNALIGNED_GET((uint32_t *)(data->ctx.tx_buf));
} else if (data->dfs > 1) {
tx = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf));
} else {
tx = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf));
}
} else {
tx = 0;
}
/* Write a specific number of frame clear the SPTEF bit */
data->preg->SPDR.LONG = tx;
spi_context_update_tx(&data->ctx, data->dfs, 1);
} else {
data->preg->SPCR.BIT.SPTIE = 0;
}
uint32_t rx;
if (data->preg->SPSR.BIT.SPRF && spi_context_rx_buf_on(&data->ctx)) {
/* Read data from the Data Reg make the receive full flag being cleared */
rx = data->preg->SPDR.LONG;
if (data->dfs > 2) {
UNALIGNED_PUT(rx, (uint32_t *)data->ctx.rx_buf);
} else if (data->dfs > 1) {
UNALIGNED_PUT(rx, (uint16_t *)data->ctx.rx_buf);
} else {
UNALIGNED_PUT(rx, (uint8_t *)data->ctx.rx_buf);
}
spi_context_update_rx(&data->ctx, data->dfs, 1);
}
return 0;
}
static int rx_rspi_transceive_master(struct rx_rspi_data *data)
{
uint32_t tx;
uint32_t rx;
if (spi_context_tx_buf_on(&data->ctx)) {
if (data->dfs > 2) {
tx = UNALIGNED_GET((uint32_t *)(data->ctx.tx_buf));
} else if (data->dfs > 1) {
tx = UNALIGNED_GET((uint16_t *)(data->ctx.tx_buf));
} else {
tx = UNALIGNED_GET((uint8_t *)(data->ctx.tx_buf));
}
} else {
tx = 0U;
}
while (!data->preg->SPSR.BIT.SPTEF) {
}
data->preg->SPDR.LONG = tx;
spi_context_update_tx(&data->ctx, data->dfs, 1);
if (spi_context_rx_on(&data->ctx)) {
while (!data->preg->SPSR.BIT.SPRF) {
}
rx = data->preg->SPDR.LONG;
if (spi_context_rx_buf_on(&data->ctx)) {
if (data->dfs > 2) {
UNALIGNED_PUT(rx, (uint32_t *)data->ctx.rx_buf);
} else if (data->dfs > 1) {
UNALIGNED_PUT(rx, (uint16_t *)data->ctx.rx_buf);
} else {
UNALIGNED_PUT(rx, (uint8_t *)data->ctx.rx_buf);
}
}
spi_context_update_rx(&data->ctx, data->dfs, 1);
} else {
/* If there no rx and the tx still send, read and drop the data */
if (data->preg->SPSR.BIT.SPRF) {
/* In case there no rx drop the incoming data*/
rx = data->preg->SPDR.LONG;
}
}
return 0;
}
static int rx_rspi_transceive_data(struct rx_rspi_data *data)
{
uint16_t operation = data->ctx.config->operation;
if (SPI_OP_MODE_GET(operation) == SPI_OP_MODE_MASTER) {
rx_rspi_transceive_master(data);
} else {
rx_rspi_transceive_slave(data);
}
return 0;
}
#endif
static int transceive(const struct device *dev, const struct spi_config *spi_cfg,
const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs,
bool asynchronous, spi_callback_t cb, void *userdata)
{
struct rx_rspi_data *data = dev->data;
int ret = 0;
if (!tx_bufs && !rx_bufs) {
return 0;
}
if (!IS_ENABLED(CONFIG_SPI_RENESAS_RX_INTERRUPT) && asynchronous) {
return -ENOTSUP;
}
spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg);
ret = rx_rspi_configure(dev, spi_cfg);
if (ret) {
goto end;
}
data->dfs = ((SPI_WORD_SIZE_GET(spi_cfg->operation) - 1) / 8) + 1;
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);
spi_context_cs_control(&data->ctx, true);
if ((!spi_context_tx_buf_on(&data->ctx)) && (!spi_context_rx_buf_on(&data->ctx))) {
/* If current buffer has no data, do nothing */
goto end;
}
#ifdef CONFIG_SPI_RENESAS_RX_INTERRUPT
if (data->ctx.rx_len == 0) {
data->data_len = spi_context_is_slave(&data->ctx)
? (spi_context_total_tx_len(&data->ctx) / data->dfs)
: data->ctx.tx_len;
} else if (data->ctx.tx_len == 0) {
data->data_len = spi_context_is_slave(&data->ctx)
? (spi_context_total_rx_len(&data->ctx) / data->dfs)
: data->ctx.rx_len;
} else {
data->data_len = spi_context_is_slave(&data->ctx)
? (MAX(spi_context_total_tx_len(&data->ctx),
spi_context_total_rx_len(&data->ctx)) /
data->dfs)
: MIN(data->ctx.tx_len, data->ctx.rx_len);
}
data->tcb.xfr_length = data->data_len;
data->tcb.tx_count = 0;
data->tcb.rx_count = 0;
data->tcb.do_rx_now = false;
data->tcb.do_tx = true;
data->tcb.bytes_per_transfer = rspi_get_data_type(data->command_word);
if (data->tcb.bytes_per_transfer == 0) {
LOG_ERR("Invalid bit length");
ret = -EINVAL;
goto end;
}
if (data->ctx.rx_buf == NULL) {
data->tcb.transfer_mode = RSPI_DO_TX;
rspi_err_t err = R_RSPI_Write(data->rspi, data->command_word,
(void *)data->ctx.tx_buf, data->data_len);
if (err != 0) {
ret = -EINVAL;
goto end;
}
} else if (data->ctx.tx_buf == NULL) {
data->tcb.transfer_mode = RSPI_DO_RX;
data->tcb.do_tx = false;
rspi_err_t err = R_RSPI_Read(data->rspi, data->command_word,
(void *)data->ctx.rx_buf, data->data_len);
if (err != 0) {
ret = -EINVAL;
goto end;
}
} else {
data->tcb.transfer_mode = RSPI_DO_TX_RX;
rspi_err_t err =
R_RSPI_WriteRead(data->rspi, data->command_word, (void *)data->ctx.tx_buf,
(void *)data->ctx.rx_buf, data->data_len);
if (err != 0) {
ret = -EINVAL;
goto end;
}
}
ret = spi_context_wait_for_completion(&data->ctx);
#else
data->preg->SPCR.BIT.TXMD = 0x0; /* tx - rx */
if (!spi_context_rx_on(&data->ctx)) {
data->preg->SPCR.BIT.TXMD = 0x1; /* tx only */
}
/* Enable the SPI Transfer */
data->preg->SPCMD0.BIT.SPB = data->command_word.bit_length;
data->preg->SPCR.BIT.SPE = 1;
do {
rx_rspi_transceive_data(data);
} while (rx_spi_transfer_ongoing(data));
if (SPI_OP_MODE_GET(data->ctx.config->operation) == SPI_OP_MODE_MASTER) {
/* Wait for transmision complete */
while (data->preg->SPSR.BIT.IDLNF) {
if (data->preg->SPSR.BIT.SPRF) {
/* Drop the incoming data because there are no rx */
uint32_t trash_can;
trash_can = data->preg->SPDR.LONG;
}
}
}
/* Disable the SPI Transfer. */
data->preg->SPCR.BIT.SPE = 0;
#ifdef CONFIG_SPI_SLAVE
if (spi_context_is_slave(&data->ctx) && !ret) {
ret = data->ctx.recv_frames;
}
#endif /* CONFIG_SPI_SLAVE */
#endif /* CONFIG_SPI_RENESAS_RX_INTERRUPT */
end:
spi_context_release(&data->ctx, ret);
return ret;
}
static int rx_rspi_transceive(const struct device *dev, const struct spi_config *spi_cfg,
const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs)
{
return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL);
}
#ifdef CONFIG_SPI_ASYNC
static int rx_rspi_transceive_async(const struct device *dev, const struct spi_config *spi_cfg,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs, spi_callback_t cb,
void *userdata)
{
return transceive(dev, spi_cfg, tx_bufs, rx_bufs, true, cb, userdata);
}
#endif
static int rx_rspi_release(const struct device *dev, const struct spi_config *spi_cfg)
{
struct rx_rspi_data *data = dev->data;
spi_context_unlock_unconditionally(&data->ctx);
return 0;
}
static DEVICE_API(spi, rx_spi_api) = {
.transceive = rx_rspi_transceive,
#ifdef CONFIG_SPI_ASYNC
.transceive_async = rx_rspi_transceive_async,
#endif
.release = rx_rspi_release,
};
static int rspi_rx_init(const struct device *dev)
{
const struct rx_rspi_config *config = dev->config;
struct rx_rspi_data *data = dev->data;
int ret;
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
return ret;
}
ret = spi_context_cs_configure_all(&data->ctx);
if (ret < 0) {
return ret;
}
spi_context_unlock_unconditionally(&data->ctx);
return 0;
}
#if defined(CONFIG_SPI_RENESAS_RX_INTERRUPT)
static void rx_rspi_retransmit(struct rx_rspi_data *data)
{
if (data->ctx.rx_len == 0) {
data->data_len = data->ctx.tx_len;
data->tcb.transfer_mode = RSPI_DO_TX;
data->tcb.do_tx = true;
} else if (data->ctx.tx_len == 0) {
data->data_len = data->ctx.rx_len;
data->tcb.transfer_mode = RSPI_DO_RX;
data->tcb.do_tx = false;
} else {
data->data_len = MIN(data->ctx.tx_len, data->ctx.rx_len);
data->tcb.transfer_mode = RSPI_DO_TX_RX;
data->tcb.do_tx = true;
}
data->tcb.do_rx_now = false;
data->tcb.tx_count = 0;
data->tcb.rx_count = 0;
data->tcb.xfr_length = data->data_len;
/* Execute the transmit of first byte here to start transmit on the new buffer */
rx_rspi_tcb_t *rspi_tcb = &(data->tcb);
uint16_t tx_count = rspi_tcb->tx_count;
if (tx_count < rspi_tcb->xfr_length) {
transmit_data(data, tx_count);
rspi_tcb->tx_count++;
}
}
static void rx_rspi_spri_isr(const struct device *dev)
{
struct rx_rspi_data *data = dev->data;
rx_rspi_tcb_t *rspi_tcb = &(data->tcb);
uint32_t *rxdata = &(data->rxdata);
if (RSPI_TRANS_MODE_SW == rspi_tcb->data_tran_mode) {
*rxdata = data->preg->SPDR.LONG;
rspi_tcb->rx_count++;
#if RSPI_CFG_HIGH_SPEED_READ == 0
rx_rspi_spti_sub(dev);
#endif
void *pdest = (void *)data->ctx.rx_buf;
uint16_t rx_count = rspi_tcb->rx_count;
uint8_t data_size = rspi_tcb->bytes_per_transfer;
if (rspi_tcb->do_rx_now) {
if (RSPI_BYTE_DATA == data_size) {
((uint8_t *)pdest)[rx_count - 1] = *((uint8_t *)rxdata);
} else if (RSPI_WORD_DATA == data_size) {
((uint16_t *)pdest)[rx_count - 1] = *((uint16_t *)rxdata);
} else {
((uint32_t *)pdest)[rx_count - 1] = *rxdata;
}
}
if (rx_count == rspi_tcb->xfr_length) {
data->preg->SPCR2.BIT.SPIIE = 1;
/* If the SPI is in slave mode */
if (spi_context_is_slave(&data->ctx)) {
spi_context_update_rx(&data->ctx, data->dfs, data->data_len);
/* Disable RSPI */
data->preg->SPCR.BIT.SPE = 0;
/**
* Transfer complete. Call the user callback function passing
* pointer to the result structure.
*/
if (data->rspi->pcallback != NULL) {
data->callback_data.handle = data->rspi;
data->callback_data.event_code = RSPI_EVT_TRANSFER_COMPLETE;
data->rspi->pcallback((void *)dev);
}
}
}
} else {
R_RSPI_IntSpriIerClear(data->rspi);
R_RSPI_DisableRSPI(data->rspi);
/**
* Transfer complete. Call the user callback function passing pointer to the result
* structure.
*/
if (data->rspi->pcallback != NULL) {
data->callback_data.handle = data->rspi;
data->callback_data.event_code = RSPI_EVT_TRANSFER_COMPLETE;
data->rspi->pcallback((void *)dev);
}
}
}
static void rx_rspi_spti_isr(const struct device *dev)
{
struct rx_rspi_data *data = dev->data;
uint32_t *rxdata = &(data->rxdata);
rx_rspi_tcb_t *rspi_tcb = &(data->tcb);
if (RSPI_TRANS_MODE_SW == rspi_tcb->data_tran_mode) {
if (0 == rspi_tcb->tx_count) {
*rxdata = data->preg->SPDR.LONG;
}
/**
* If master mode then disable further SPTI interrupts on first transmit.
* If slave mode then we do two transmits to fill the double buffer,
* then disable SPTI interrupts.
* The receive interrupt will handle any remaining data.
*/
#if RSPI_CFG_HIGH_SPEED_READ == 0
if ((data->preg->SPCR.BIT.MSTR) || (rspi_tcb->txcount > 0)) {
data->preg->SPCR.BIT.SPTIE = 0;
}
#endif
rx_rspi_spti_sub(dev);
if (rspi_tcb->transfer_mode & RSPI_DO_RX) {
/* Count was incremented in the call to rx_rspi_spti_sub. */
if ((data->preg->SPCR.BIT.MSTR) || (rspi_tcb->tx_count > 1)) {
/* Enables saving of receive data on next receive interrupt. */
rspi_tcb->do_rx_now = true;
}
}
} else {
R_RSPI_DisableSpti(data->rspi);
R_RSPI_IntSptiIerClear(data->rspi);
}
}
static void rx_rspi_spii_isr(const struct device *dev)
{
struct rx_rspi_data *data = dev->data;
if (data->tcb.rx_count >= data->tcb.xfr_length) {
spi_context_update_rx(&data->ctx, data->dfs, data->data_len);
}
if (data->tcb.tx_count >= data->tcb.xfr_length) {
spi_context_update_tx(&data->ctx, data->dfs, data->data_len);
}
if (rx_spi_transfer_ongoing(data)) {
data->preg->SPCR2.BIT.SPIIE = 0;
rx_rspi_retransmit(data);
} else {
uint8_t status_flags = data->preg->SPSR.BYTE;
rspi_evt_t event = RSPI_EVT_ERR_UNDEF;
rspi_callback_data_t *rspi_cb_data = &(data->callback_data);
rspi_cb_data->event_code = event;
if ((status_flags & RSPI_SPSR_IDLNF) == 0x00) {
/* Disable idle interrupt requests of the RSPI. */
data->preg->SPCR2.BIT.SPIIE = 0;
/* Disable RSPI */
data->preg->SPCR.BIT.SPE = 0;
/**
* Transfer complete. Call the user callback function passing pointer to the
* result structure.
*/
if (data->rspi->pcallback != NULL) {
rspi_cb_data->handle = data->rspi;
rspi_cb_data->event_code = RSPI_EVT_TRANSFER_COMPLETE;
data->rspi->pcallback((void *)dev);
}
}
}
}
static void rx_rspi_spei_isr(const struct device *dev)
{
struct rx_rspi_data *data = dev->data;
uint8_t status_flags = data->preg->SPSR.BYTE;
rspi_evt_t event = RSPI_EVT_ERR_UNDEF;
rspi_callback_data_t *rspi_cb_data = &(data->callback_data);
/* Identify and clear error condition. */
if (status_flags & RSPI_SPSR_OVRF) {
event = RSPI_EVT_ERR_READ_OVF;
/* Clear error source: OVRF flag. */
data->preg->SPSR.BIT.OVRF = 0;
goto error_callback;
}
if (status_flags & RSPI_SPSR_MODF) {
if (status_flags & RSPI_SPSR_UDRF) {
event = RSPI_EVT_ERR_UNDER_RUN;
/* Clear error source: MODF flag and UDRF. */
data->preg->SPSR.BYTE &= RSPI_SPSR_MODF_UDRF_MASK;
} else {
event = RSPI_EVT_ERR_MODE_FAULT;
/* Clear error source: MODF flag. */
data->preg->SPSR.BIT.MODF = 0;
}
goto error_callback;
}
if (status_flags & RSPI_SPSR_PERF) {
event = RSPI_EVT_ERR_PARITY;
/* Clear error source: PERF flag. */
data->preg->SPSR.BIT.PERF = 0;
goto error_callback;
}
error_callback:
rspi_cb_data->event_code = event;
/* Disable the RSPI operation. */
data->preg->SPCR.BYTE &= (uint8_t)(~((RSPI_SPCR_SPTIE | RSPI_SPCR_SPRIE) | RSPI_SPCR_SPE));
/* Disable idle interrupt requests of the RSPI. */
data->preg->SPCR2.BIT.SPIIE = 0;
/* Call the user callback function passing pointer to the result structure. */
if (data->rspi->pcallback != NULL) {
rspi_cb_data->handle = data->rspi;
data->rspi->pcallback((void *)dev);
}
}
#endif
#if defined(CONFIG_SPI_RENESAS_RX_INTERRUPT)
#define RX_RSPI_IRQ_CONFIG_INIT(n) \
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, spri, irq), DT_INST_IRQ_BY_NAME(n, spri, priority), \
rx_rspi_spri_isr, DEVICE_DT_INST_GET(n), 0); \
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, spti, irq), DT_INST_IRQ_BY_NAME(n, spti, priority), \
rx_rspi_spti_isr, DEVICE_DT_INST_GET(n), 0); \
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, spii, irq), DT_INST_IRQ_BY_NAME(n, spii, priority), \
rx_rspi_spii_isr, DEVICE_DT_INST_GET(n), 0); \
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, spei, irq), DT_INST_IRQ_BY_NAME(n, spei, priority), \
rx_rspi_spei_isr, DEVICE_DT_INST_GET(n), 0); \
\
irq_enable(DT_INST_IRQ_BY_NAME(n, spri, irq)); \
irq_enable(DT_INST_IRQ_BY_NAME(n, spti, irq)); \
irq_enable(DT_INST_IRQ_BY_NAME(n, spei, irq));
#else
#define RX_RSPI_IRQ_CONFIG_INIT(n)
#endif
#define RX_RSPI_INIT(n) \
PINCTRL_DT_INST_DEFINE(n); \
static const struct rx_rspi_config rx_rspi_config_##n = { \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
}; \
static struct rx_rspi_data rx_rspi_data_##n = { \
SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx) \
SPI_CONTEXT_INIT_LOCK(rx_rspi_data_##n, ctx), \
SPI_CONTEXT_INIT_SYNC(rx_rspi_data_##n, ctx), \
.preg = (struct st_rspi *)DT_INST_REG_ADDR(n), \
.channel_id = DT_INST_PROP(n, channel), \
.ssl_assert = DT_INST_PROP(n, ssl_assert), \
}; \
static int rspi_rx_init##n(const struct device *dev) \
{ \
int err = rspi_rx_init(dev); \
if (err != 0) { \
return err; \
} \
RX_RSPI_IRQ_CONFIG_INIT(n); \
return 0; \
} \
SPI_DEVICE_DT_INST_DEFINE(n, rspi_rx_init##n, PM_DEVICE_DT_INST_GET(n), &rx_rspi_data_##n, \
&rx_rspi_config_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
&rx_spi_api);
DT_INST_FOREACH_STATUS_OKAY(RX_RSPI_INIT)