Skip to content

Commit 75e9544

Browse files
committed
spi_nxp_lpspi: Convert to Zephyr Native Driver
Remove the shim to the SDK driver, and only use direct register writes in the zephyr driver instead. This will save flash space. Remove mcux branding from all code. While doing this part of the rewrite, I discovered also some issues that I went ahead and fixed: - The driver was hardcoded to always only use PCS 0 no matter what the user provided spi_config set slave to. - Active high CS configuration was not respected. Also fixes an issue where SDK driver performed an althgorithm on 2,048 possible clock configurations before every transfer. This was replaced with a binary search in the native version. And make it so that this configuration does not need to happen every transfer, if the same spi_cfg is used, to improve performance. Various optimizations also due to the fact that the use case is more clear than the SDK was written for, so we can be more straightforward and simpler. Signed-off-by: Declan Snyder <[email protected]>
1 parent 52b8e3d commit 75e9544

30 files changed

+395
-237
lines changed

drivers/clock_control/clock_control_mcux_ccm.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include <zephyr/logging/log.h>
2121
LOG_MODULE_REGISTER(clock_control);
2222

23-
#ifdef CONFIG_SPI_MCUX_LPSPI
23+
#ifdef CONFIG_SPI_NXP_LPSPI
2424
static const clock_name_t lpspi_clocks[] = {
2525
kCLOCK_Usb1PllPfd1Clk,
2626
kCLOCK_Usb1PllPfd0Clk,
@@ -207,7 +207,7 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev,
207207
break;
208208
#endif
209209

210-
#ifdef CONFIG_SPI_MCUX_LPSPI
210+
#ifdef CONFIG_SPI_NXP_LPSPI
211211
case IMX_CCM_LPSPI_CLK:
212212
{
213213
uint32_t lpspi_mux = CLOCK_GetMux(kCLOCK_LpspiMux);

drivers/clock_control/clock_control_mcux_ccm_rev2.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev,
8181
break;
8282
#endif
8383

84-
#ifdef CONFIG_SPI_MCUX_LPSPI
84+
#ifdef CONFIG_SPI_NXP_LPSPI
8585
#if defined(CONFIG_SOC_SERIES_IMXRT118X)
8686
case IMX_CCM_LPSPI0102_CLK:
8787
clock_root = kCLOCK_Root_Lpspi0102 + instance;
@@ -91,7 +91,7 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev,
9191
clock_root = kCLOCK_Root_Lpspi1 + instance;
9292
break;
9393
#endif /* CONFIG_SOC_SERIES_IMXRT118X */
94-
#endif /* CONFIG_SPI_MCUX_LPSPI */
94+
#endif /* CONFIG_SPI_NXP_LPSPI */
9595

9696
#ifdef CONFIG_UART_MCUX_LPUART
9797
#if defined(CONFIG_SOC_SERIES_IMXRT118X)
+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# Copyright 2024 NXP
1+
# Copyright 2024-2025 NXP
22

3-
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI spi_nxp_lpspi_common.c)
4-
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI_NORMAL spi_nxp_lpspi.c)
5-
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI_DMA spi_nxp_lpspi_dma.c)
3+
zephyr_library_sources_ifdef(CONFIG_SPI_NXP_LPSPI spi_nxp_lpspi_common.c)
4+
zephyr_library_sources_ifdef(CONFIG_SPI_NXP_LPSPI_CPU spi_nxp_lpspi.c)
5+
zephyr_library_sources_ifdef(CONFIG_SPI_NXP_LPSPI_DMA spi_nxp_lpspi_dma.c)

drivers/spi/spi_nxp_lpspi/Kconfig

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
# Copyright 2018, 2024 NXP
1+
# Copyright 2018, 2024-2025 NXP
22
# SPDX-License-Identifier: Apache-2.0
33

4-
config SPI_MCUX_LPSPI
4+
config SPI_NXP_LPSPI
55
bool "NXP LPSPI peripheral"
66
default y
77
depends on DT_HAS_NXP_LPSPI_ENABLED
@@ -10,21 +10,21 @@ config SPI_MCUX_LPSPI
1010
help
1111
Enable support for NXP LPSPI.
1212

13-
if SPI_MCUX_LPSPI
13+
if SPI_NXP_LPSPI
1414

15-
config SPI_MCUX_LPSPI_DMA
16-
bool "MCUX LPSPI SPI DMA Support"
15+
config SPI_NXP_LPSPI_DMA
16+
bool "NXP LPSPI SPI DMA Driver"
1717
select DMA
1818
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_NXP_LPSPI),dmas)
1919
help
2020
Enable the SPI DMA mode for SPI instances
2121
that enable dma channels in their device tree node.
2222

23-
config SPI_MCUX_LPSPI_NORMAL
24-
bool "NXP MCUX LPSPI driver"
23+
config SPI_NXP_LPSPI_CPU
24+
bool "NXP LPSPI CPU based driver"
2525
default y
26-
depends on $(dt_compat_any_not_has_prop,$(DT_COMPAT_NXP_LPSPI),dmas) || !SPI_MCUX_LPSPI_DMA
26+
depends on $(dt_compat_any_not_has_prop,$(DT_COMPAT_NXP_LPSPI),dmas) || !SPI_NXP_LPSPI_DMA
2727
help
2828
Use the traditional (non-RTIO) SPI driver for NXP LPSPI.
2929

30-
endif # SPI_MCUX_LPSPI
30+
endif # SPI_NXP_LPSPI

drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c

+46-62
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#define DT_DRV_COMPAT nxp_lpspi
88

99
#include <zephyr/logging/log.h>
10-
LOG_MODULE_REGISTER(spi_mcux_lpspi, CONFIG_SPI_LOG_LEVEL);
10+
LOG_MODULE_REGISTER(spi_nxp_lpspi, CONFIG_SPI_LOG_LEVEL);
1111

1212
#include "spi_nxp_lpspi_priv.h"
1313

@@ -18,24 +18,16 @@ struct lpspi_driver_data {
1818
uint8_t word_size_bytes;
1919
};
2020

21-
static inline void lpspi_wait_tx_fifo_empty(const struct device *dev)
22-
{
23-
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
24-
25-
while (LPSPI_GetTxFifoCount(base) != 0) {
26-
}
27-
}
28-
2921
/* Reads a word from the RX fifo and handles writing it into the RX spi buf */
3022
static inline void lpspi_rx_word_write_bytes(const struct device *dev, size_t offset)
3123
{
3224
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
33-
struct spi_mcux_data *data = dev->data;
25+
struct spi_nxp_data *data = dev->data;
3426
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
3527
struct spi_context *ctx = &data->ctx;
3628
uint8_t num_bytes = MIN(lpspi_data->word_size_bytes, ctx->rx_len);
3729
uint8_t *buf = ctx->rx_buf + offset;
38-
uint32_t word = LPSPI_ReadData(base);
30+
uint32_t word = base->RDR;
3931

4032
if (!spi_context_rx_buf_on(ctx) && spi_context_rx_on(ctx)) {
4133
/* receive no actual data if rx buf is NULL */
@@ -50,7 +42,7 @@ static inline void lpspi_rx_word_write_bytes(const struct device *dev, size_t of
5042
/* Reads a maximum number of words from RX fifo and writes them to the remainder of the RX buf */
5143
static inline size_t lpspi_rx_buf_write_words(const struct device *dev, uint8_t max_read)
5244
{
53-
struct spi_mcux_data *data = dev->data;
45+
struct spi_nxp_data *data = dev->data;
5446
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
5547
struct spi_context *ctx = &data->ctx;
5648
size_t buf_len = ctx->rx_len / lpspi_data->word_size_bytes;
@@ -68,21 +60,21 @@ static inline size_t lpspi_rx_buf_write_words(const struct device *dev, uint8_t
6860

6961
static inline uint8_t rx_fifo_cur_len(LPSPI_Type *base)
7062
{
71-
return (base->FSR & LPSPI_FSR_RXCOUNT_MASK) >> LPSPI_FSR_RXCOUNT_SHIFT;
63+
return FIELD_GET(LPSPI_FSR_RXCOUNT_MASK, base->FSR);
7264
}
7365

7466
static inline void lpspi_handle_rx_irq(const struct device *dev)
7567
{
7668
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
77-
struct spi_mcux_data *data = dev->data;
69+
struct spi_nxp_data *data = dev->data;
7870
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
7971
struct spi_context *ctx = &data->ctx;
8072
uint8_t total_words_written = 0;
8173
uint8_t total_words_read = 0;
8274
uint8_t words_read;
8375
uint8_t rx_fsr;
8476

85-
LPSPI_ClearStatusFlags(base, kLPSPI_RxDataReadyFlag);
77+
base->SR = LPSPI_SR_RDF_MASK;
8678

8779
LOG_DBG("RX FIFO: %d, RX BUF: %p", rx_fsr, ctx->rx_buf);
8880

@@ -96,14 +88,14 @@ static inline void lpspi_handle_rx_irq(const struct device *dev)
9688
LOG_DBG("RX done %d words to spi buf", total_words_written);
9789

9890
if (!spi_context_rx_on(ctx)) {
99-
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
100-
LPSPI_FlushFifo(base, false, true);
91+
base->IER &= ~LPSPI_IER_RDIE_MASK;
92+
base->CR |= LPSPI_CR_RRF_MASK; /* flush rx fifo */
10193
}
10294
}
10395

10496
static inline uint32_t lpspi_next_tx_word(const struct device *dev, int offset)
10597
{
106-
struct spi_mcux_data *data = dev->data;
98+
struct spi_nxp_data *data = dev->data;
10799
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
108100
struct spi_context *ctx = &data->ctx;
109101
const uint8_t *byte = ctx->tx_buf + offset;
@@ -120,13 +112,13 @@ static inline uint32_t lpspi_next_tx_word(const struct device *dev, int offset)
120112
static inline void lpspi_fill_tx_fifo(const struct device *dev)
121113
{
122114
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
123-
struct spi_mcux_data *data = dev->data;
115+
struct spi_nxp_data *data = dev->data;
124116
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
125117
size_t bytes_in_xfer = lpspi_data->fill_len * lpspi_data->word_size_bytes;
126118
size_t offset;
127119

128120
for (offset = 0; offset < bytes_in_xfer; offset += lpspi_data->word_size_bytes) {
129-
LPSPI_WriteData(base, lpspi_next_tx_word(dev, offset));
121+
base->TDR = lpspi_next_tx_word(dev, offset);
130122
}
131123

132124
LOG_DBG("Filled TX FIFO to %d words (%d bytes)", lpspi_data->fill_len, offset);
@@ -135,20 +127,20 @@ static inline void lpspi_fill_tx_fifo(const struct device *dev)
135127
static inline void lpspi_fill_tx_fifo_nop(const struct device *dev)
136128
{
137129
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
138-
struct spi_mcux_data *data = dev->data;
130+
struct spi_nxp_data *data = dev->data;
139131
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
140132

141133
for (int i = 0; i < lpspi_data->fill_len; i++) {
142-
LPSPI_WriteData(base, 0);
134+
base->TDR = 0;
143135
}
144136

145137
LOG_DBG("Filled TX fifo with %d NOPs", lpspi_data->fill_len);
146138
}
147139

148140
static void lpspi_next_tx_fill(const struct device *dev)
149141
{
150-
const struct spi_mcux_config *config = dev->config;
151-
struct spi_mcux_data *data = dev->data;
142+
const struct spi_nxp_config *config = dev->config;
143+
struct spi_nxp_data *data = dev->data;
152144
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
153145
struct spi_context *ctx = &data->ctx;
154146
size_t max_chunk;
@@ -168,13 +160,13 @@ static void lpspi_next_tx_fill(const struct device *dev)
168160
static inline void lpspi_handle_tx_irq(const struct device *dev)
169161
{
170162
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
171-
struct spi_mcux_data *data = dev->data;
163+
struct spi_nxp_data *data = dev->data;
172164
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
173165
struct spi_context *ctx = &data->ctx;
174166

175167
spi_context_update_tx(ctx, lpspi_data->word_size_bytes, lpspi_data->fill_len);
176168

177-
LPSPI_ClearStatusFlags(base, kLPSPI_TxDataRequestFlag);
169+
base->SR = LPSPI_SR_TDF_MASK;
178170

179171
/* Having no buffer length left indicates transfer is done, if there
180172
* was RX to do left, the TX buf would be null but
@@ -185,7 +177,7 @@ static inline void lpspi_handle_tx_irq(const struct device *dev)
185177
base->TCR = 0;
186178
lpspi_wait_tx_fifo_empty(dev);
187179
spi_context_cs_control(ctx, false);
188-
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable);
180+
base->IER &= ~LPSPI_IER_TDIE_MASK;
189181
return;
190182
}
191183

@@ -194,7 +186,7 @@ static inline void lpspi_handle_tx_irq(const struct device *dev)
194186

195187
static inline bool lpspi_is_rx_done(const struct device *dev)
196188
{
197-
struct spi_mcux_data *data = dev->data;
189+
struct spi_nxp_data *data = dev->data;
198190
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
199191
struct spi_context *ctx = &data->ctx;
200192
size_t tx_total = lpspi_data->tx_total_len;
@@ -222,16 +214,16 @@ static inline void lpspi_clear_remaining_rx(struct spi_context *ctx)
222214
static void lpspi_isr(const struct device *dev)
223215
{
224216
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
225-
const struct spi_mcux_config *config = dev->config;
226-
uint32_t status_flags = LPSPI_GetStatusFlags(base);
227-
struct spi_mcux_data *data = dev->data;
217+
const struct spi_nxp_config *config = dev->config;
218+
uint32_t status_flags = base->SR;
219+
struct spi_nxp_data *data = dev->data;
228220
struct spi_context *ctx = &data->ctx;
229221

230-
if (status_flags & kLPSPI_RxDataReadyFlag) {
222+
if (status_flags & LPSPI_SR_RDF_MASK) {
231223
lpspi_handle_rx_irq(dev);
232224
}
233225

234-
if (status_flags & kLPSPI_TxDataRequestFlag) {
226+
if (status_flags & LPSPI_SR_TDF_MASK) {
235227
lpspi_handle_tx_irq(dev);
236228
}
237229

@@ -247,7 +239,7 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
247239
bool asynchronous, spi_callback_t cb, void *userdata)
248240
{
249241
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
250-
struct spi_mcux_data *data = dev->data;
242+
struct spi_nxp_data *data = dev->data;
251243
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
252244
int ret;
253245

@@ -265,21 +257,14 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
265257
lpspi_data->tx_total_len = spi_context_total_tx_len(&data->ctx);
266258
lpspi_data->rx_total_len = spi_context_total_rx_len(&data->ctx);
267259

268-
ret = spi_mcux_configure(dev, spi_cfg);
260+
ret = spi_nxp_configure(dev, spi_cfg);
269261
if (ret) {
270262
goto out;
271263
}
272264

273-
LPSPI_FlushFifo(base, true, true);
274-
LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
275-
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
276-
277265
LOG_DBG("Starting LPSPI transfer");
278266
spi_context_cs_control(&data->ctx, true);
279267

280-
LPSPI_SetFifoWatermarks(base, 0, 0);
281-
LPSPI_Enable(base, true);
282-
283268
/* keep the chip select asserted until the end of the zephyr xfer */
284269
base->TCR |= LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK;
285270
/* tcr is written to tx fifo */
@@ -288,8 +273,7 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
288273
/* start the transfer sequence which are handled by irqs */
289274
lpspi_next_tx_fill(dev);
290275

291-
LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable |
292-
(uint32_t)kLPSPI_RxInterruptEnable);
276+
base->IER |= LPSPI_IER_TDIE_MASK | LPSPI_IER_RDIE_MASK;
293277

294278
ret = spi_context_wait_for_completion(&data->ctx);
295279
out:
@@ -298,15 +282,15 @@ static int transceive(const struct device *dev, const struct spi_config *spi_cfg
298282
return ret;
299283
}
300284

301-
static int spi_mcux_transceive_sync(const struct device *dev, const struct spi_config *spi_cfg,
285+
static int spi_nxp_transceive_sync(const struct device *dev, const struct spi_config *spi_cfg,
302286
const struct spi_buf_set *tx_bufs,
303287
const struct spi_buf_set *rx_bufs)
304288
{
305289
return transceive(dev, spi_cfg, tx_bufs, rx_bufs, false, NULL, NULL);
306290
}
307291

308292
#ifdef CONFIG_SPI_ASYNC
309-
static int spi_mcux_transceive_async(const struct device *dev, const struct spi_config *spi_cfg,
293+
static int spi_nxp_transceive_async(const struct device *dev, const struct spi_config *spi_cfg,
310294
const struct spi_buf_set *tx_bufs,
311295
const struct spi_buf_set *rx_bufs, spi_callback_t cb,
312296
void *userdata)
@@ -315,20 +299,20 @@ static int spi_mcux_transceive_async(const struct device *dev, const struct spi_
315299
}
316300
#endif /* CONFIG_SPI_ASYNC */
317301

318-
static DEVICE_API(spi, spi_mcux_driver_api) = {
319-
.transceive = spi_mcux_transceive_sync,
302+
static DEVICE_API(spi, spi_nxp_driver_api) = {
303+
.transceive = spi_nxp_transceive_sync,
320304
#ifdef CONFIG_SPI_ASYNC
321-
.transceive_async = spi_mcux_transceive_async,
305+
.transceive_async = spi_nxp_transceive_async,
322306
#endif
323307
#ifdef CONFIG_SPI_RTIO
324308
.iodev_submit = spi_rtio_iodev_default_submit,
325309
#endif
326-
.release = spi_mcux_release,
310+
.release = spi_nxp_release,
327311
};
328312

329-
static int spi_mcux_init(const struct device *dev)
313+
static int spi_nxp_init(const struct device *dev)
330314
{
331-
struct spi_mcux_data *data = dev->data;
315+
struct spi_nxp_data *data = dev->data;
332316
int err = 0;
333317

334318
err = spi_nxp_init_common(dev);
@@ -343,23 +327,23 @@ static int spi_mcux_init(const struct device *dev)
343327

344328
#define LPSPI_INIT(n) \
345329
SPI_NXP_LPSPI_COMMON_INIT(n) \
346-
SPI_MCUX_LPSPI_CONFIG_INIT(n) \
330+
SPI_NXP_LPSPI_CONFIG_INIT(n) \
347331
\
348332
static struct lpspi_driver_data lpspi_##n##_driver_data; \
349333
\
350-
static struct spi_mcux_data spi_mcux_data_##n = { \
334+
static struct spi_nxp_data spi_nxp_data_##n = { \
351335
SPI_NXP_LPSPI_COMMON_DATA_INIT(n) \
352336
.driver_data = &lpspi_##n##_driver_data, \
353337
}; \
354338
\
355-
SPI_DEVICE_DT_INST_DEFINE(n, spi_mcux_init, NULL, &spi_mcux_data_##n, \
356-
&spi_mcux_config_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
357-
&spi_mcux_driver_api);
339+
SPI_DEVICE_DT_INST_DEFINE(n, spi_nxp_init, NULL, &spi_nxp_data_##n, \
340+
&spi_nxp_config_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
341+
&spi_nxp_driver_api);
358342

359-
#define SPI_MCUX_LPSPI_INIT_IF_DMA(n) IF_DISABLED(SPI_NXP_LPSPI_HAS_DMAS(n), (LPSPI_INIT(n)))
343+
#define SPI_NXP_LPSPI_INIT_IF_DMA(n) IF_DISABLED(SPI_NXP_LPSPI_HAS_DMAS(n), (LPSPI_INIT(n)))
360344

361-
#define SPI_MCUX_LPSPI_INIT(n) \
362-
COND_CODE_1(CONFIG_SPI_MCUX_LPSPI_DMA, \
363-
(SPI_MCUX_LPSPI_INIT_IF_DMA(n)), (LPSPI_INIT(n)))
345+
#define SPI_NXP_LPSPI_INIT(n) \
346+
COND_CODE_1(CONFIG_SPI_NXP_LPSPI_DMA, \
347+
(SPI_NXP_LPSPI_INIT_IF_DMA(n)), (LPSPI_INIT(n)))
364348

365-
DT_INST_FOREACH_STATUS_OKAY(SPI_MCUX_LPSPI_INIT)
349+
DT_INST_FOREACH_STATUS_OKAY(SPI_NXP_LPSPI_INIT)

0 commit comments

Comments
 (0)