Skip to content

Commit 2a35835

Browse files
decsnykartben
authored andcommitted
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 <[email protected]>
1 parent b5ca5b7 commit 2a35835

File tree

1 file changed

+39
-52
lines changed

1 file changed

+39
-52
lines changed

drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ static inline void lpspi_wait_tx_fifo_empty(const struct device *dev)
2626
}
2727
}
2828

29+
static inline uint8_t rx_fifo_cur_len(LPSPI_Type *base)
30+
{
31+
return (base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT;
32+
}
33+
34+
static inline uint8_t tx_fifo_cur_len(LPSPI_Type *base)
35+
{
36+
return (base->FSR & LPSPI_FSR_TXCOUNT_MASK) >> LPSPI_FSR_TXCOUNT_SHIFT;
37+
}
38+
39+
2940
/* Reads a word from the RX fifo and handles writing it into the RX spi buf */
3041
static inline void lpspi_rx_word_write_bytes(const struct device *dev, size_t offset)
3142
{
@@ -66,21 +77,16 @@ static inline size_t lpspi_rx_buf_write_words(const struct device *dev, uint8_t
6677
return words_read;
6778
}
6879

69-
static inline uint8_t rx_fifo_cur_len(LPSPI_Type *base)
70-
{
71-
return (base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT;
72-
}
73-
7480
static inline void lpspi_handle_rx_irq(const struct device *dev)
7581
{
7682
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
7783
struct spi_mcux_data *data = dev->data;
7884
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
7985
struct spi_context *ctx = &data->ctx;
86+
uint8_t rx_fsr = rx_fifo_cur_len(base);
8087
uint8_t total_words_written = 0;
8188
uint8_t total_words_read = 0;
8289
uint8_t words_read;
83-
uint8_t rx_fsr;
8490

8591
LPSPI_ClearStatusFlags(base, kLPSPI_RxDataReadyFlag);
8692

@@ -95,7 +101,7 @@ static inline void lpspi_handle_rx_irq(const struct device *dev)
95101

96102
LOG_DBG("RX done %d words to spi buf", total_words_written);
97103

98-
if (!spi_context_rx_on(ctx)) {
104+
if (spi_context_rx_len_left(ctx) == 0) {
99105
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
100106
LPSPI_FlushFifo(base, false, true);
101107
}
@@ -132,7 +138,7 @@ static inline void lpspi_fill_tx_fifo(const struct device *dev)
132138
LOG_DBG("Filled TX FIFO to %d words (%d bytes)", lpspi_data->fill_len, offset);
133139
}
134140

135-
static inline void lpspi_fill_tx_fifo_nop(const struct device *dev)
141+
static void lpspi_fill_tx_fifo_nop(const struct device *dev)
136142
{
137143
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
138144
struct spi_mcux_data *data = dev->data;
@@ -176,55 +182,21 @@ static inline void lpspi_handle_tx_irq(const struct device *dev)
176182

177183
LPSPI_ClearStatusFlags(base, kLPSPI_TxDataRequestFlag);
178184

179-
/* Having no buffer length left indicates transfer is done, if there
180-
* was RX to do left, the TX buf would be null but
181-
* ctx still tracks length of dummy data
182-
*/
183185
if (!spi_context_tx_on(ctx)) {
184-
/* Disable chip select and end transfer clocks last word */
185-
base->TCR = 0;
186-
lpspi_wait_tx_fifo_empty(dev);
187-
spi_context_cs_control(ctx, false);
188186
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
189187
return;
190188
}
191189

192190
lpspi_next_tx_fill(data->dev);
193191
}
194192

195-
static inline bool lpspi_is_rx_done(const struct device *dev)
196-
{
197-
struct spi_mcux_data *data = dev->data;
198-
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
199-
struct spi_context *ctx = &data->ctx;
200-
size_t tx_total = lpspi_data->tx_total_len;
201-
size_t rx_total = lpspi_data->rx_total_len;
202-
203-
if (tx_total >= rx_total) {
204-
return (spi_context_total_rx_len(ctx) == 0);
205-
} else {
206-
return (tx_total <= (rx_total - spi_context_rx_len_left(ctx)));
207-
}
208-
}
209-
210-
static inline void lpspi_clear_remaining_rx(struct spi_context *ctx)
211-
{
212-
size_t remaining_len;
213-
214-
while ((remaining_len = spi_context_rx_len_left(ctx)) > 0) {
215-
for (int i = 0; i < ctx->rx_len; i++) {
216-
ctx->rx_buf[i] = 0;
217-
}
218-
spi_context_update_rx(ctx, 1, ctx->rx_len);
219-
}
220-
}
221-
222193
static void lpspi_isr(const struct device *dev)
223194
{
224195
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
225196
const struct spi_mcux_config *config = dev->config;
226197
uint32_t status_flags = LPSPI_GetStatusFlags(base);
227198
struct spi_mcux_data *data = dev->data;
199+
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
228200
struct spi_context *ctx = &data->ctx;
229201

230202
if (status_flags & kLPSPI_RxDataReadyFlag) {
@@ -235,10 +207,29 @@ static void lpspi_isr(const struct device *dev)
235207
lpspi_handle_tx_irq(dev);
236208
}
237209

238-
if (!spi_context_tx_on(ctx) && lpspi_is_rx_done(dev)) {
210+
if (spi_context_tx_on(ctx)) {
211+
return;
212+
}
213+
214+
if (spi_context_rx_len_left(ctx) == 1) {
215+
base->TCR = 0;
216+
} else if (spi_context_rx_on(ctx)) {
217+
size_t rx_fifo_len = rx_fifo_cur_len(base);
218+
size_t expected_rx_left = rx_fifo_len < ctx->rx_len ? ctx->rx_len - rx_fifo_len : 0;
219+
size_t max_fill = MIN(expected_rx_left, config->rx_fifo_size);
220+
size_t tx_current_fifo_len = tx_fifo_cur_len(base);
221+
222+
lpspi_data->fill_len = tx_current_fifo_len < ctx->rx_len ?
223+
max_fill - tx_current_fifo_len : 0;
224+
225+
lpspi_fill_tx_fifo_nop(dev);
226+
} else {
239227
spi_context_complete(ctx, dev, 0);
240228
NVIC_ClearPendingIRQ(config->irqn);
241-
lpspi_clear_remaining_rx(ctx);
229+
base->TCR = 0;
230+
lpspi_wait_tx_fifo_empty(dev);
231+
spi_context_cs_control(ctx, false);
232+
spi_context_release(&data->ctx, 0);
242233
}
243234
}
244235

@@ -257,7 +248,7 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
257248
if (lpspi_data->word_size_bytes > 4) {
258249
LOG_ERR("Maximum 4 byte word size");
259250
ret = -EINVAL;
260-
goto out;
251+
return ret;
261252
}
262253

263254
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
267258

268259
ret = spi_mcux_configure(dev, spi_cfg);
269260
if (ret) {
270-
goto out;
261+
return ret;
271262
}
272263

273264
LPSPI_FlushFifo(base, true, true);
@@ -291,11 +282,7 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
291282
LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable |
292283
(uint32_t)kLPSPI_RxInterruptEnable);
293284

294-
ret = spi_context_wait_for_completion(&data->ctx);
295-
out:
296-
spi_context_release(&data->ctx, ret);
297-
298-
return ret;
285+
return spi_context_wait_for_completion(&data->ctx);
299286
}
300287

301288
static int spi_mcux_transceive_sync(const struct device *dev, const struct spi_config *spi_cfg,

0 commit comments

Comments
 (0)