spi_nxp_lpspi: RX bigger than TX read all RX
Change the driver behavior so that if the provided RX buffer set is bigger than the TX buffer, we will read all the RX buffer and fill the TX with NOPs. The SPI driver API does not say to do this, and my original interpretation of the API was that the TX length controls the entire transfer length, but this behavior might fit better with some de facto expectations of in tree consumers. Also add some robustness to the calculation of how many extra bytes to fill when tx should be nops. Signed-off-by: Declan Snyder <declan.snyder@nxp.com>
This commit is contained in:
parent
b5ca5b7b77
commit
2a35835979
1 changed files with 39 additions and 52 deletions
|
@ -26,6 +26,17 @@ static inline void lpspi_wait_tx_fifo_empty(const struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint8_t rx_fifo_cur_len(LPSPI_Type *base)
|
||||
{
|
||||
return (base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT;
|
||||
}
|
||||
|
||||
static inline uint8_t tx_fifo_cur_len(LPSPI_Type *base)
|
||||
{
|
||||
return (base->FSR & LPSPI_FSR_TXCOUNT_MASK) >> LPSPI_FSR_TXCOUNT_SHIFT;
|
||||
}
|
||||
|
||||
|
||||
/* Reads a word from the RX fifo and handles writing it into the RX spi buf */
|
||||
static inline void lpspi_rx_word_write_bytes(const struct device *dev, size_t offset)
|
||||
{
|
||||
|
@ -66,21 +77,16 @@ static inline size_t lpspi_rx_buf_write_words(const struct device *dev, uint8_t
|
|||
return words_read;
|
||||
}
|
||||
|
||||
static inline uint8_t rx_fifo_cur_len(LPSPI_Type *base)
|
||||
{
|
||||
return (base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT;
|
||||
}
|
||||
|
||||
static inline void lpspi_handle_rx_irq(const struct device *dev)
|
||||
{
|
||||
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
uint8_t rx_fsr = rx_fifo_cur_len(base);
|
||||
uint8_t total_words_written = 0;
|
||||
uint8_t total_words_read = 0;
|
||||
uint8_t words_read;
|
||||
uint8_t rx_fsr;
|
||||
|
||||
LPSPI_ClearStatusFlags(base, kLPSPI_RxDataReadyFlag);
|
||||
|
||||
|
@ -95,7 +101,7 @@ static inline void lpspi_handle_rx_irq(const struct device *dev)
|
|||
|
||||
LOG_DBG("RX done %d words to spi buf", total_words_written);
|
||||
|
||||
if (!spi_context_rx_on(ctx)) {
|
||||
if (spi_context_rx_len_left(ctx) == 0) {
|
||||
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
|
||||
LPSPI_FlushFifo(base, false, true);
|
||||
}
|
||||
|
@ -132,7 +138,7 @@ static inline void lpspi_fill_tx_fifo(const struct device *dev)
|
|||
LOG_DBG("Filled TX FIFO to %d words (%d bytes)", lpspi_data->fill_len, offset);
|
||||
}
|
||||
|
||||
static inline void lpspi_fill_tx_fifo_nop(const struct device *dev)
|
||||
static void lpspi_fill_tx_fifo_nop(const struct device *dev)
|
||||
{
|
||||
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
|
@ -176,15 +182,7 @@ static inline void lpspi_handle_tx_irq(const struct device *dev)
|
|||
|
||||
LPSPI_ClearStatusFlags(base, kLPSPI_TxDataRequestFlag);
|
||||
|
||||
/* Having no buffer length left indicates transfer is done, if there
|
||||
* was RX to do left, the TX buf would be null but
|
||||
* ctx still tracks length of dummy data
|
||||
*/
|
||||
if (!spi_context_tx_on(ctx)) {
|
||||
/* Disable chip select and end transfer clocks last word */
|
||||
base->TCR = 0;
|
||||
lpspi_wait_tx_fifo_empty(dev);
|
||||
spi_context_cs_control(ctx, false);
|
||||
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
|
||||
return;
|
||||
}
|
||||
|
@ -192,39 +190,13 @@ static inline void lpspi_handle_tx_irq(const struct device *dev)
|
|||
lpspi_next_tx_fill(data->dev);
|
||||
}
|
||||
|
||||
static inline bool lpspi_is_rx_done(const struct device *dev)
|
||||
{
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
size_t tx_total = lpspi_data->tx_total_len;
|
||||
size_t rx_total = lpspi_data->rx_total_len;
|
||||
|
||||
if (tx_total >= rx_total) {
|
||||
return (spi_context_total_rx_len(ctx) == 0);
|
||||
} else {
|
||||
return (tx_total <= (rx_total - spi_context_rx_len_left(ctx)));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void lpspi_clear_remaining_rx(struct spi_context *ctx)
|
||||
{
|
||||
size_t remaining_len;
|
||||
|
||||
while ((remaining_len = spi_context_rx_len_left(ctx)) > 0) {
|
||||
for (int i = 0; i < ctx->rx_len; i++) {
|
||||
ctx->rx_buf[i] = 0;
|
||||
}
|
||||
spi_context_update_rx(ctx, 1, ctx->rx_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpspi_isr(const struct device *dev)
|
||||
{
|
||||
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||
const struct spi_mcux_config *config = dev->config;
|
||||
uint32_t status_flags = LPSPI_GetStatusFlags(base);
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
|
||||
if (status_flags & kLPSPI_RxDataReadyFlag) {
|
||||
|
@ -235,10 +207,29 @@ static void lpspi_isr(const struct device *dev)
|
|||
lpspi_handle_tx_irq(dev);
|
||||
}
|
||||
|
||||
if (!spi_context_tx_on(ctx) && lpspi_is_rx_done(dev)) {
|
||||
if (spi_context_tx_on(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spi_context_rx_len_left(ctx) == 1) {
|
||||
base->TCR = 0;
|
||||
} else if (spi_context_rx_on(ctx)) {
|
||||
size_t rx_fifo_len = rx_fifo_cur_len(base);
|
||||
size_t expected_rx_left = rx_fifo_len < ctx->rx_len ? ctx->rx_len - rx_fifo_len : 0;
|
||||
size_t max_fill = MIN(expected_rx_left, config->rx_fifo_size);
|
||||
size_t tx_current_fifo_len = tx_fifo_cur_len(base);
|
||||
|
||||
lpspi_data->fill_len = tx_current_fifo_len < ctx->rx_len ?
|
||||
max_fill - tx_current_fifo_len : 0;
|
||||
|
||||
lpspi_fill_tx_fifo_nop(dev);
|
||||
} else {
|
||||
spi_context_complete(ctx, dev, 0);
|
||||
NVIC_ClearPendingIRQ(config->irqn);
|
||||
lpspi_clear_remaining_rx(ctx);
|
||||
base->TCR = 0;
|
||||
lpspi_wait_tx_fifo_empty(dev);
|
||||
spi_context_cs_control(ctx, false);
|
||||
spi_context_release(&data->ctx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,7 +248,7 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
|
|||
if (lpspi_data->word_size_bytes > 4) {
|
||||
LOG_ERR("Maximum 4 byte word size");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, lpspi_data->word_size_bytes);
|
||||
|
@ -267,7 +258,7 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
|
|||
|
||||
ret = spi_mcux_configure(dev, spi_cfg);
|
||||
if (ret) {
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
LPSPI_FlushFifo(base, true, true);
|
||||
|
@ -291,11 +282,7 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
|
|||
LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable |
|
||||
(uint32_t)kLPSPI_RxInterruptEnable);
|
||||
|
||||
ret = spi_context_wait_for_completion(&data->ctx);
|
||||
out:
|
||||
spi_context_release(&data->ctx, ret);
|
||||
|
||||
return ret;
|
||||
return spi_context_wait_for_completion(&data->ctx);
|
||||
}
|
||||
|
||||
static int spi_mcux_transceive_sync(const struct device *dev, const struct spi_config *spi_cfg,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue