spi_nxp_lpspi: Rewrite driver, fix native chip sel
To fix the native hardware chip select, we need to rewrite this driver to not use the MCUX SDK handle abstraction, which does not fit the zephyr use case. Signed-off-by: Declan Snyder <declan.snyder@nxp.com>
This commit is contained in:
parent
0bb7ccbb0c
commit
62b911feea
4 changed files with 368 additions and 166 deletions
|
@ -1,6 +1,6 @@
|
|||
# Copyright 2024 NXP
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI spi_nxp_lpspi_common.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI_NORMAL spi_mcux_lpspi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI_NORMAL spi_nxp_lpspi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI_DMA spi_nxp_lpspi_dma.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SPI_MCUX_LPSPI_RTIO spi_mcux_lpspi_rtio.c)
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018, 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_lpspi
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(spi_mcux_lpspi, CONFIG_SPI_LOG_LEVEL);
|
||||
|
||||
#include "spi_nxp_lpspi_priv.h"
|
||||
|
||||
struct lpspi_driver_data {
|
||||
lpspi_master_handle_t handle;
|
||||
};
|
||||
|
||||
static int spi_mcux_transfer_next_packet(const struct device *dev)
|
||||
{
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
|
||||
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||
struct spi_context *ctx = &data->ctx;
|
||||
size_t max_chunk = spi_context_max_continuous_chunk(ctx);
|
||||
lpspi_transfer_t transfer;
|
||||
status_t status;
|
||||
|
||||
if (max_chunk == 0) {
|
||||
spi_context_cs_control(ctx, false);
|
||||
spi_context_complete(ctx, dev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->transfer_len = max_chunk;
|
||||
|
||||
transfer.configFlags = LPSPI_MASTER_XFER_CFG_FLAGS(ctx->config->slave);
|
||||
transfer.txData = (ctx->tx_len == 0 ? NULL : ctx->tx_buf);
|
||||
transfer.rxData = (ctx->rx_len == 0 ? NULL : ctx->rx_buf);
|
||||
transfer.dataSize = max_chunk;
|
||||
|
||||
status = LPSPI_MasterTransferNonBlocking(base, &lpspi_data->handle, &transfer);
|
||||
if (status != kStatus_Success) {
|
||||
LOG_ERR("Transfer could not start on %s: %d", dev->name, status);
|
||||
return status == kStatus_LPSPI_Busy ? -EBUSY : -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpspi_isr(const struct device *dev)
|
||||
{
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
struct lpspi_driver_data *lpspi_data = (struct lpspi_driver_data *)data->driver_data;
|
||||
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||
|
||||
LPSPI_MasterTransferHandleIRQ(LPSPI_IRQ_HANDLE_ARG, &lpspi_data->handle);
|
||||
}
|
||||
|
||||
static void spi_mcux_master_callback(LPSPI_Type *base, lpspi_master_handle_t *handle,
|
||||
status_t status, void *userData)
|
||||
{
|
||||
struct spi_mcux_data *data = userData;
|
||||
|
||||
spi_context_update_tx(&data->ctx, 1, data->transfer_len);
|
||||
spi_context_update_rx(&data->ctx, 1, data->transfer_len);
|
||||
|
||||
spi_mcux_transfer_next_packet(data->dev);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
int ret;
|
||||
|
||||
spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg);
|
||||
|
||||
ret = spi_mcux_configure(dev, spi_cfg);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
LPSPI_MasterTransferCreateHandle(base, &lpspi_data->handle, spi_mcux_master_callback, data);
|
||||
|
||||
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);
|
||||
|
||||
spi_context_cs_control(&data->ctx, true);
|
||||
|
||||
ret = spi_mcux_transfer_next_packet(dev);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = spi_context_wait_for_completion(&data->ctx);
|
||||
out:
|
||||
spi_context_release(&data->ctx, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spi_mcux_transceive_sync(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 spi_mcux_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 /* CONFIG_SPI_ASYNC */
|
||||
|
||||
static DEVICE_API(spi, spi_mcux_driver_api) = {
|
||||
.transceive = spi_mcux_transceive_sync,
|
||||
#ifdef CONFIG_SPI_ASYNC
|
||||
.transceive_async = spi_mcux_transceive_async,
|
||||
#endif
|
||||
.release = spi_mcux_release,
|
||||
};
|
||||
|
||||
static int spi_mcux_init(const struct device *dev)
|
||||
{
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
int err = 0;
|
||||
|
||||
err = spi_nxp_init_common(dev);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
spi_context_unlock_unconditionally(&data->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LPSPI_INIT(n) \
|
||||
SPI_NXP_LPSPI_COMMON_INIT(n) \
|
||||
SPI_MCUX_LPSPI_CONFIG_INIT(n) \
|
||||
\
|
||||
static struct lpspi_driver_data lpspi_##n##_driver_data; \
|
||||
\
|
||||
static struct spi_mcux_data spi_mcux_data_##n = { \
|
||||
SPI_NXP_LPSPI_COMMON_DATA_INIT(n) \
|
||||
.driver_data = &lpspi_##n##_driver_data, \
|
||||
}; \
|
||||
\
|
||||
SPI_DEVICE_DT_INST_DEFINE(n, spi_mcux_init, NULL, &spi_mcux_data_##n, \
|
||||
&spi_mcux_config_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
|
||||
&spi_mcux_driver_api);
|
||||
|
||||
#define SPI_MCUX_LPSPI_INIT_IF_DMA(n) IF_DISABLED(SPI_NXP_LPSPI_HAS_DMAS(n), (LPSPI_INIT(n)))
|
||||
|
||||
#define SPI_MCUX_LPSPI_INIT(n) \
|
||||
COND_CODE_1(CONFIG_SPI_MCUX_LPSPI_DMA, \
|
||||
(SPI_MCUX_LPSPI_INIT_IF_DMA(n)), (LPSPI_INIT(n)))
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SPI_MCUX_LPSPI_INIT)
|
362
drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c
Normal file
362
drivers/spi/spi_nxp_lpspi/spi_nxp_lpspi.c
Normal file
|
@ -0,0 +1,362 @@
|
|||
/*
|
||||
* Copyright 2024-2025 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_lpspi
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(spi_mcux_lpspi, CONFIG_SPI_LOG_LEVEL);
|
||||
|
||||
#include "spi_nxp_lpspi_priv.h"
|
||||
|
||||
struct lpspi_driver_data {
|
||||
size_t fill_len;
|
||||
size_t tx_total_len;
|
||||
size_t rx_total_len;
|
||||
uint8_t word_size_bytes;
|
||||
};
|
||||
|
||||
static inline void lpspi_wait_tx_fifo_empty(const struct device *dev)
|
||||
{
|
||||
LPSPI_Type *base = (LPSPI_Type *)DEVICE_MMIO_NAMED_GET(dev, reg_base);
|
||||
|
||||
while (LPSPI_GetTxFifoCount(base) != 0) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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 num_bytes = MIN(lpspi_data->word_size_bytes, ctx->rx_len);
|
||||
uint8_t *buf = ctx->rx_buf + offset;
|
||||
uint32_t word = LPSPI_ReadData(base);
|
||||
|
||||
if (!spi_context_rx_buf_on(ctx) && spi_context_rx_on(ctx)) {
|
||||
/* receive no actual data if rx buf is NULL */
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < num_bytes; i++) {
|
||||
buf[i] = (uint8_t)(word >> (BITS_PER_BYTE * i));
|
||||
}
|
||||
}
|
||||
|
||||
/* Reads a maximum number of words from RX fifo and writes them to the remainder of the RX buf */
|
||||
static inline size_t lpspi_rx_buf_write_words(const struct device *dev, uint8_t max_read)
|
||||
{
|
||||
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 buf_len = ctx->rx_len / lpspi_data->word_size_bytes;
|
||||
uint8_t words_read = 0;
|
||||
size_t offset = 0;
|
||||
|
||||
while (buf_len-- > 0 && max_read-- > 0) {
|
||||
lpspi_rx_word_write_bytes(dev, offset);
|
||||
offset += lpspi_data->word_size_bytes;
|
||||
words_read++;
|
||||
}
|
||||
|
||||
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 total_words_written = 0;
|
||||
uint8_t total_words_read = 0;
|
||||
uint8_t words_read;
|
||||
uint8_t rx_fsr;
|
||||
|
||||
LPSPI_ClearStatusFlags(base, kLPSPI_RxDataReadyFlag);
|
||||
|
||||
LOG_DBG("RX FIFO: %d, RX BUF: %p", rx_fsr, ctx->rx_buf);
|
||||
|
||||
while ((rx_fsr = rx_fifo_cur_len(base)) > 0 && spi_context_rx_on(ctx)) {
|
||||
words_read = lpspi_rx_buf_write_words(dev, rx_fsr);
|
||||
total_words_read += words_read;
|
||||
total_words_written += (spi_context_rx_buf_on(ctx) ? words_read : 0);
|
||||
spi_context_update_rx(ctx, lpspi_data->word_size_bytes, words_read);
|
||||
}
|
||||
|
||||
LOG_DBG("RX done %d words to spi buf", total_words_written);
|
||||
|
||||
if (!spi_context_rx_on(ctx)) {
|
||||
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable);
|
||||
LPSPI_FlushFifo(base, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t lpspi_next_tx_word(const struct device *dev, int offset)
|
||||
{
|
||||
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;
|
||||
const uint8_t *byte = ctx->tx_buf + offset;
|
||||
uint32_t num_bytes = MIN(lpspi_data->word_size_bytes, ctx->tx_len);
|
||||
uint32_t next_word = 0;
|
||||
|
||||
for (uint8_t i = 0; i < num_bytes; i++) {
|
||||
next_word |= *byte << (BITS_PER_BYTE * i);
|
||||
}
|
||||
|
||||
return next_word;
|
||||
}
|
||||
|
||||
static inline void lpspi_fill_tx_fifo(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;
|
||||
size_t bytes_in_xfer = lpspi_data->fill_len * lpspi_data->word_size_bytes;
|
||||
size_t offset;
|
||||
|
||||
for (offset = 0; offset < bytes_in_xfer; offset += lpspi_data->word_size_bytes) {
|
||||
LPSPI_WriteData(base, lpspi_next_tx_word(dev, offset));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
for (int i = 0; i < lpspi_data->fill_len; i++) {
|
||||
LPSPI_WriteData(base, 0);
|
||||
}
|
||||
|
||||
LOG_DBG("Filled TX fifo with %d NOPs", lpspi_data->fill_len);
|
||||
}
|
||||
|
||||
static void lpspi_next_tx_fill(const struct device *dev)
|
||||
{
|
||||
const struct spi_mcux_config *config = dev->config;
|
||||
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 max_chunk;
|
||||
|
||||
/* Convert bytes to words for this xfer */
|
||||
max_chunk = ctx->tx_len / lpspi_data->word_size_bytes;
|
||||
max_chunk = MIN(max_chunk, config->tx_fifo_size);
|
||||
lpspi_data->fill_len = max_chunk;
|
||||
|
||||
if (spi_context_tx_buf_on(ctx)) {
|
||||
lpspi_fill_tx_fifo(dev);
|
||||
} else {
|
||||
lpspi_fill_tx_fifo_nop(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void lpspi_handle_tx_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;
|
||||
|
||||
spi_context_update_tx(ctx, lpspi_data->word_size_bytes, lpspi_data->fill_len);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 spi_context *ctx = &data->ctx;
|
||||
|
||||
if (status_flags & kLPSPI_RxDataReadyFlag) {
|
||||
lpspi_handle_rx_irq(dev);
|
||||
}
|
||||
|
||||
if (status_flags & kLPSPI_TxDataRequestFlag) {
|
||||
lpspi_handle_tx_irq(dev);
|
||||
}
|
||||
|
||||
if (!spi_context_tx_on(ctx) && lpspi_is_rx_done(dev)) {
|
||||
spi_context_complete(ctx, dev, 0);
|
||||
NVIC_ClearPendingIRQ(config->irqn);
|
||||
lpspi_clear_remaining_rx(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
int ret;
|
||||
|
||||
spi_context_lock(&data->ctx, asynchronous, cb, userdata, spi_cfg);
|
||||
|
||||
lpspi_data->word_size_bytes = SPI_WORD_SIZE_GET(spi_cfg->operation) / BITS_PER_BYTE;
|
||||
if (lpspi_data->word_size_bytes > 4) {
|
||||
LOG_ERR("Maximum 4 byte word size");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, lpspi_data->word_size_bytes);
|
||||
|
||||
lpspi_data->tx_total_len = spi_context_total_tx_len(&data->ctx);
|
||||
lpspi_data->rx_total_len = spi_context_total_rx_len(&data->ctx);
|
||||
|
||||
ret = spi_mcux_configure(dev, spi_cfg);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
LPSPI_FlushFifo(base, true, true);
|
||||
LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag);
|
||||
LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable);
|
||||
|
||||
LOG_DBG("Starting LPSPI transfer");
|
||||
spi_context_cs_control(&data->ctx, true);
|
||||
|
||||
LPSPI_SetFifoWatermarks(base, 0, 0);
|
||||
LPSPI_Enable(base, true);
|
||||
|
||||
/* keep the chip select asserted until the end of the zephyr xfer */
|
||||
base->TCR |= LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK;
|
||||
/* tcr is written to tx fifo */
|
||||
lpspi_wait_tx_fifo_empty(dev);
|
||||
|
||||
/* start the transfer sequence which are handled by irqs */
|
||||
lpspi_next_tx_fill(dev);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int spi_mcux_transceive_sync(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 spi_mcux_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 /* CONFIG_SPI_ASYNC */
|
||||
|
||||
static DEVICE_API(spi, spi_mcux_driver_api) = {
|
||||
.transceive = spi_mcux_transceive_sync,
|
||||
#ifdef CONFIG_SPI_ASYNC
|
||||
.transceive_async = spi_mcux_transceive_async,
|
||||
#endif
|
||||
.release = spi_mcux_release,
|
||||
};
|
||||
|
||||
static int spi_mcux_init(const struct device *dev)
|
||||
{
|
||||
struct spi_mcux_data *data = dev->data;
|
||||
int err = 0;
|
||||
|
||||
err = spi_nxp_init_common(dev);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
spi_context_unlock_unconditionally(&data->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define LPSPI_INIT(n) \
|
||||
SPI_NXP_LPSPI_COMMON_INIT(n) \
|
||||
SPI_MCUX_LPSPI_CONFIG_INIT(n) \
|
||||
\
|
||||
static struct lpspi_driver_data lpspi_##n##_driver_data; \
|
||||
\
|
||||
static struct spi_mcux_data spi_mcux_data_##n = { \
|
||||
SPI_NXP_LPSPI_COMMON_DATA_INIT(n) \
|
||||
.driver_data = &lpspi_##n##_driver_data, \
|
||||
}; \
|
||||
\
|
||||
SPI_DEVICE_DT_INST_DEFINE(n, spi_mcux_init, NULL, &spi_mcux_data_##n, \
|
||||
&spi_mcux_config_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
|
||||
&spi_mcux_driver_api);
|
||||
|
||||
#define SPI_MCUX_LPSPI_INIT_IF_DMA(n) IF_DISABLED(SPI_NXP_LPSPI_HAS_DMAS(n), (LPSPI_INIT(n)))
|
||||
|
||||
#define SPI_MCUX_LPSPI_INIT(n) \
|
||||
COND_CODE_1(CONFIG_SPI_MCUX_LPSPI_DMA, \
|
||||
(SPI_MCUX_LPSPI_INIT_IF_DMA(n)), (LPSPI_INIT(n)))
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SPI_MCUX_LPSPI_INIT)
|
|
@ -44,6 +44,7 @@ struct spi_mcux_config {
|
|||
bool output_config;
|
||||
uint8_t tx_fifo_size;
|
||||
uint8_t rx_fifo_size;
|
||||
uint8_t irqn;
|
||||
};
|
||||
|
||||
struct spi_mcux_data {
|
||||
|
@ -86,6 +87,9 @@ int spi_mcux_release(const struct device *dev, const struct spi_config *spi_cfg)
|
|||
(SPI_MCUX_LPSPI_IRQ_FUNC_LP_FLEXCOMM(n)), \
|
||||
(SPI_MCUX_LPSPI_IRQ_FUNC_DISTINCT(n)))
|
||||
|
||||
#define LPSPI_IRQN(n) COND_CODE_1(DT_NODE_HAS_COMPAT(DT_INST_PARENT(n), nxp_lp_flexcomm), \
|
||||
(DT_IRQN(DT_INST_PARENT(n))), (DT_INST_IRQN(n)))
|
||||
|
||||
#define SPI_MCUX_LPSPI_CONFIG_INIT(n) \
|
||||
static const struct spi_mcux_config spi_mcux_config_##n = { \
|
||||
DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \
|
||||
|
@ -103,6 +107,7 @@ int spi_mcux_release(const struct device *dev, const struct spi_config *spi_cfg)
|
|||
.output_config = DT_INST_PROP(n, tristate_output), \
|
||||
.rx_fifo_size = (uint8_t)DT_INST_PROP(n, rx_fifo_size), \
|
||||
.tx_fifo_size = (uint8_t)DT_INST_PROP(n, tx_fifo_size), \
|
||||
.irqn = (uint8_t)LPSPI_IRQN(n), \
|
||||
};
|
||||
|
||||
#define SPI_NXP_LPSPI_COMMON_INIT(n) \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue