Skip to content

Commit e71aa64

Browse files
decsnykartben
authored andcommitted
spi_nxp_lpspi: Support SPI_HOLD_ON_CS FLAG
Support SPI_HOLD_ON_CS flag in the CPU-based driver. To do this we will set CONTC bit to continue previous command. Technically it may not be necessary right now, and could just not clear CONT bit... but in the future in the lpspi driver we will decouple the config/init of a transfer from the SDK and therefore have more control over TCR, and when we write the TCR, we need to take CONTC bit into account otherwise a new command will be made. So this approach is how it should be handled in the driver going forward in my opinion, even if it might be possible without this bit right now, I want to introduce it's usage now. This commit also does a minor refactor in the ISR and adds some comments to make the strange CS behavior and strange handling code more clear to future readers. Also, make the early predicted SPI xfer end code only happen for spi versions where it is necessary, since I think that code is really the best we can do but might have a race condition, where possible the last word is not finished sending when we end the xfer. So limit the potential affect to v1 lpspi where the workaround is actually required due to stalling behavior. Lastly, set the LPSPI into master mode at active low in init, due to it being the most common case, we want the SPI CS lines to be initialized at init of driver. I don't think it's worth it to make it configurable at this time, but in the future it could be if needed. Signed-off-by: Declan Snyder <[email protected]>
1 parent 17ec70c commit e71aa64

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,23 @@ static inline void lpspi_handle_tx_irq(const struct device *dev)
219219
lpspi_next_tx_fill(data->dev);
220220
}
221221

222+
static inline void lpspi_end_xfer(const struct device *dev)
223+
{
224+
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
225+
const struct lpspi_config *config = dev->config;
226+
struct lpspi_data *data = dev->data;
227+
struct spi_context *ctx = &data->ctx;
228+
229+
spi_context_complete(ctx, dev, 0);
230+
NVIC_ClearPendingIRQ(config->irqn);
231+
if (!(ctx->config->operation & SPI_HOLD_ON_CS)) {
232+
base->TCR &= ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK);
233+
}
234+
lpspi_wait_tx_fifo_empty(dev);
235+
spi_context_cs_control(ctx, false);
236+
spi_context_release(&data->ctx, 0);
237+
}
238+
222239
static void lpspi_isr(const struct device *dev)
223240
{
224241
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
@@ -253,15 +270,13 @@ static void lpspi_isr(const struct device *dev)
253270
lpspi_data->fill_len = fill_len;
254271
}
255272

256-
if (spi_context_rx_len_left(ctx) == 1) {
257-
base->TCR &= ~LPSPI_TCR_CONT_MASK;
273+
if (spi_context_rx_len_left(ctx) == 1 && (LPSPI_VERID_MAJOR(base->VERID) < 2)) {
274+
/* Due to stalling behavior on older LPSPI,
275+
* need to end xfer in order to get last bit clocked out on bus.
276+
*/
277+
base->TCR |= LPSPI_TCR_CONT_MASK;
258278
} else if (spi_context_rx_len_left(ctx) == 0) {
259-
spi_context_complete(ctx, dev, 0);
260-
NVIC_ClearPendingIRQ(config->irqn);
261-
base->TCR &= ~LPSPI_TCR_CONT_MASK;
262-
lpspi_wait_tx_fifo_empty(dev);
263-
spi_context_cs_control(ctx, false);
264-
spi_context_release(&data->ctx, 0);
279+
lpspi_end_xfer(dev);
265280
}
266281
}
267282

@@ -302,8 +317,16 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
302317

303318
base->CR |= LPSPI_CR_MEN_MASK;
304319

305-
/* keep the chip select asserted until the end of the zephyr xfer */
306-
base->TCR |= LPSPI_TCR_CONT_MASK;
320+
/* keep the chip select asserted until the end of the zephyr xfer by using
321+
* continunous transfer mode. If SPI_HOLD_ON_CS is requested, we need
322+
* to also set CONTC in order to continue the previous command to keep CS
323+
* asserted.
324+
*/
325+
if (spi_cfg->operation & SPI_HOLD_ON_CS || base->TCR & LPSPI_TCR_CONTC_MASK) {
326+
base->TCR |= LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK;
327+
} else {
328+
base->TCR |= LPSPI_TCR_CONT_MASK;
329+
}
307330
/* tcr is written to tx fifo */
308331
lpspi_wait_tx_fifo_empty(dev);
309332

@@ -352,6 +375,7 @@ static DEVICE_API(spi, lpspi_driver_api) = {
352375

353376
static int lpspi_init(const struct device *dev)
354377
{
378+
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
355379
struct lpspi_data *data = dev->data;
356380
int err = 0;
357381

@@ -360,6 +384,14 @@ static int lpspi_init(const struct device *dev)
360384
return err;
361385
}
362386

387+
/* Starting config should be master with active low CS, to make sure
388+
* the CS lines are configured properly at init for the most common use
389+
* cases. This can be changed later on transceive call if user specifies
390+
* different spi configuration.
391+
*/
392+
base->CFGR1 |= LPSPI_CFGR1_MASTER_MASK;
393+
base->CFGR1 &= ~LPSPI_CFGR1_PCSPOL_MASK;
394+
363395
spi_context_unlock_unconditionally(&data->ctx);
364396

365397
return 0;

0 commit comments

Comments
 (0)