Skip to content

Commit e38d067

Browse files
committed
drivers: spi: litex: use async
implement async spi transfers Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
1 parent cbb48a2 commit e38d067

File tree

1 file changed

+135
-89
lines changed

1 file changed

+135
-89
lines changed

drivers/spi/spi_litex_litespi.c

Lines changed: 135 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ LOG_MODULE_REGISTER(spi_litex_litespi);
1414
#include "spi_litex_common.h"
1515

1616
#define SPI_LITEX_ANY_HAS_IRQ DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts)
17+
#define SPI_LITEX_ALL_HAS_IRQ DT_ALL_INST_HAS_PROP_STATUS_OKAY(interrupts)
18+
19+
#define SPI_LITEX_HAS_IRQ (SPI_LITEX_ALL_HAS_IRQ || dev_config->has_irq)
1720

1821
#define SPIFLASH_CORE_MASTER_PHYCONFIG_LEN_OFFSET 0x0
1922
#define SPIFLASH_CORE_MASTER_PHYCONFIG_WIDTH_OFFSET 0x1
@@ -25,6 +28,9 @@ LOG_MODULE_REGISTER(spi_litex_litespi);
2528
#define SPI_MAX_WORD_SIZE 32
2629
#define SPI_MAX_CS_SIZE 4
2730

31+
#define SPI_LITEX_WIDTH BIT(0)
32+
#define SPI_LITEX_MASK BIT(0)
33+
2834
struct spi_litex_dev_config {
2935
uint32_t core_master_cs_addr;
3036
uint32_t core_master_phyconfig_addr;
@@ -35,6 +41,7 @@ struct spi_litex_dev_config {
3541
bool phy_clk_divisor_exists;
3642
#if SPI_LITEX_ANY_HAS_IRQ
3743
bool has_irq;
44+
void (*irq_config_func)(const struct device *dev);
3845
uint32_t core_master_ev_pending_addr;
3946
uint32_t core_master_ev_enable_addr;
4047
#endif
@@ -43,9 +50,7 @@ struct spi_litex_dev_config {
4350
struct spi_litex_data {
4451
struct spi_context ctx;
4552
uint8_t dfs; /* dfs in bytes: 1,2 or 4 */
46-
#if SPI_LITEX_ANY_HAS_IRQ
47-
struct k_sem sem_rx_ready;
48-
#endif /* SPI_LITEX_ANY_HAS_IRQ */
53+
uint8_t len; /* length of the last transfer in bytes */
4954
};
5055

5156

@@ -93,11 +98,6 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
9398
return -ENOTSUP;
9499
}
95100

96-
if (config->operation & SPI_LOCK_ON) {
97-
LOG_ERR("Lock On not supported");
98-
return -ENOTSUP;
99-
}
100-
101101
if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) &&
102102
(config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
103103
LOG_ERR("Only supports single mode");
@@ -144,40 +144,54 @@ static void spiflash_len_mask_width_write(uint32_t len, uint32_t width, uint32_t
144144
litex_write32(word, addr);
145145
}
146146

147-
static void spi_litex_wait_for_rx_ready(const struct device *dev)
147+
static void spi_litex_spi_do_tx(const struct device *dev)
148148
{
149149
const struct spi_litex_dev_config *dev_config = dev->config;
150-
151-
#if SPI_LITEX_ANY_HAS_IRQ
152150
struct spi_litex_data *data = dev->data;
153-
154-
if (dev_config->has_irq) {
155-
/* Wait for the RX ready event */
156-
k_sem_take(&data->sem_rx_ready, K_FOREVER);
157-
return;
151+
struct spi_context *ctx = &data->ctx;
152+
uint8_t len;
153+
uint32_t txd = 0U;
154+
155+
len = MIN(spi_context_max_continuous_chunk(ctx), dev_config->core_master_rxtx_size);
156+
if (len != data->len) {
157+
spiflash_len_mask_width_write(len * 8, SPI_LITEX_WIDTH, SPI_LITEX_MASK,
158+
dev_config->core_master_phyconfig_addr);
159+
data->len = len;
158160
}
159-
#endif /* SPI_LITEX_ANY_HAS_IRQ */
160161

161-
while (!(litex_read8(dev_config->core_master_status_addr) &
162-
BIT(SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET))) {
163-
;
162+
if (spi_context_tx_buf_on(ctx)) {
163+
litex_spi_tx_put(len, &txd, ctx->tx_buf);
164164
}
165+
166+
LOG_DBG("txd: 0x%x", txd);
167+
litex_write32(txd, dev_config->core_master_rxtx_addr);
168+
169+
spi_context_update_tx(ctx, data->dfs, len / data->dfs);
165170
}
166171

167-
static int spi_litex_xfer(const struct device *dev, const struct spi_config *config)
172+
static void spi_litex_spi_do_rx(const struct device *dev)
168173
{
169174
const struct spi_litex_dev_config *dev_config = dev->config;
170175
struct spi_litex_data *data = dev->data;
171176
struct spi_context *ctx = &data->ctx;
172-
uint32_t txd, rxd;
173-
int ret = 0;
177+
uint32_t rxd;
178+
179+
rxd = litex_read32(dev_config->core_master_rxtx_addr);
180+
LOG_DBG("rxd: 0x%x", rxd);
174181

175-
uint8_t len = data->dfs; /* SPI Xfer length*/
176-
uint8_t old_len = len; /* old SPI Xfer length*/
177-
uint8_t width = BIT(0); /* SPI Xfer width*/
178-
uint8_t mask = BIT(0); /* SPI Xfer mask*/
182+
if (spi_context_rx_buf_on(ctx)) {
183+
litex_spi_rx_put(data->len, &rxd, ctx->rx_buf);
184+
}
185+
186+
spi_context_update_rx(ctx, data->dfs, data->len / data->dfs);
187+
}
179188

180-
spiflash_len_mask_width_write(len * 8, width, mask, dev_config->core_master_phyconfig_addr);
189+
static int spi_litex_xfer(const struct device *dev, const struct spi_config *config)
190+
{
191+
const struct spi_litex_dev_config *dev_config = dev->config;
192+
struct spi_litex_data *data = dev->data;
193+
struct spi_context *ctx = &data->ctx;
194+
uint32_t rxd;
181195

182196
litex_write32(BIT(config->slave), dev_config->core_master_cs_addr);
183197

@@ -188,100 +202,105 @@ static int spi_litex_xfer(const struct device *dev, const struct spi_config *con
188202
LOG_DBG("flushed rxd: 0x%x", rxd);
189203
}
190204

205+
while (!(litex_read8(dev_config->core_master_status_addr) &
206+
BIT(SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET))) {
207+
;
208+
}
209+
191210
#if SPI_LITEX_ANY_HAS_IRQ
192-
if (dev_config->has_irq) {
211+
if (SPI_LITEX_HAS_IRQ) {
193212
litex_write8(BIT(0), dev_config->core_master_ev_enable_addr);
194213
litex_write8(BIT(0), dev_config->core_master_ev_pending_addr);
195-
k_sem_reset(&data->sem_rx_ready);
214+
215+
spi_litex_spi_do_tx(dev);
216+
217+
return spi_context_wait_for_completion(ctx);
196218
}
197219
#endif /* SPI_LITEX_ANY_HAS_IRQ */
198220

199221
do {
200-
len = MIN(spi_context_max_continuous_chunk(ctx), dev_config->core_master_rxtx_size);
201-
if (len != old_len) {
202-
spiflash_len_mask_width_write(len * 8, width, mask,
203-
dev_config->core_master_phyconfig_addr);
204-
old_len = len;
205-
}
206-
207-
if (spi_context_tx_buf_on(ctx)) {
208-
litex_spi_tx_put(len, &txd, ctx->tx_buf);
209-
} else {
210-
txd = 0U;
211-
}
222+
spi_litex_spi_do_tx(dev);
212223

213224
while (!(litex_read8(dev_config->core_master_status_addr) &
214-
BIT(SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET))) {
225+
BIT(SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET))) {
215226
;
216227
}
217228

218-
LOG_DBG("txd: 0x%x", txd);
219-
litex_write32(txd, dev_config->core_master_rxtx_addr);
220-
221-
spi_context_update_tx(ctx, data->dfs, len / data->dfs);
222-
223-
spi_litex_wait_for_rx_ready(dev);
224-
225-
rxd = litex_read32(dev_config->core_master_rxtx_addr);
226-
LOG_DBG("rxd: 0x%x", rxd);
227-
228-
if (spi_context_rx_buf_on(ctx)) {
229-
litex_spi_rx_put(len, &rxd, ctx->rx_buf);
230-
}
231-
232-
spi_context_update_rx(ctx, data->dfs, len / data->dfs);
233-
229+
spi_litex_spi_do_rx(dev);
234230
} while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx));
235231

236232
litex_write32(0, dev_config->core_master_cs_addr);
237233

238-
#if SPI_LITEX_ANY_HAS_IRQ
239-
if (dev_config->has_irq) {
240-
/* Wait for the RX ready event */
241-
litex_write8(0, dev_config->core_master_ev_enable_addr);
242-
}
243-
#endif /* SPI_LITEX_ANY_HAS_IRQ */
244234
spi_context_complete(ctx, dev, 0);
245235

246-
return ret;
236+
return 0;
247237
}
248238

249-
static int spi_litex_transceive(const struct device *dev, const struct spi_config *config,
250-
const struct spi_buf_set *tx_bufs,
251-
const struct spi_buf_set *rx_bufs)
239+
static int transceive(const struct device *dev,
240+
const struct spi_config *config,
241+
const struct spi_buf_set *tx_bufs,
242+
const struct spi_buf_set *rx_bufs,
243+
bool asynchronous,
244+
spi_callback_t cb,
245+
void *userdata)
252246
{
247+
#if SPI_LITEX_ANY_HAS_IRQ
248+
const struct spi_litex_dev_config *dev_config = dev->config;
249+
#endif /* SPI_LITEX_ANY_HAS_IRQ */
253250
struct spi_litex_data *data = dev->data;
254-
255-
int ret = spi_config(dev, config);
256-
257-
if (ret) {
258-
return ret;
259-
}
251+
int ret;
260252

261253
if (!tx_bufs && !rx_bufs) {
262254
return 0;
263255
}
256+
#if SPI_LITEX_ANY_HAS_IRQ
257+
if (!SPI_LITEX_HAS_IRQ && asynchronous) {
258+
return -ENOTSUP;
259+
}
260+
#endif /* SPI_LITEX_ANY_HAS_IRQ */
261+
262+
spi_context_lock(&data->ctx, asynchronous, cb, userdata, config);
263+
264+
ret = spi_config(dev, config);
265+
266+
if (ret < 0) {
267+
return ret;
268+
}
264269

265270
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);
266271

267272
ret = spi_litex_xfer(dev, config);
268273

274+
spi_context_release(&data->ctx, ret);
275+
269276
return ret;
270277
}
271278

279+
static int spi_litex_transceive(const struct device *dev,
280+
const struct spi_config *config,
281+
const struct spi_buf_set *tx_bufs,
282+
const struct spi_buf_set *rx_bufs)
283+
{
284+
return transceive(dev, config, tx_bufs, rx_bufs, false, NULL, NULL);
285+
}
286+
272287
#ifdef CONFIG_SPI_ASYNC
273-
static int spi_litex_transceive_async(const struct device *dev, const struct spi_config *config,
288+
static int spi_litex_transceive_async(const struct device *dev,
289+
const struct spi_config *config,
274290
const struct spi_buf_set *tx_bufs,
275291
const struct spi_buf_set *rx_bufs,
276-
struct k_poll_signal *async)
292+
spi_callback_t cb,
293+
void *userdata)
277294
{
278-
return -ENOTSUP;
295+
return transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata);
279296
}
280297
#endif /* CONFIG_SPI_ASYNC */
281298

282299
static int spi_litex_release(const struct device *dev, const struct spi_config *config)
283300
{
301+
struct spi_litex_data *data = dev->data;
284302

303+
spi_context_unlock_unconditionally(&data->ctx);
285304
return 0;
286305
}
287306

@@ -290,16 +309,48 @@ static void spi_litex_irq_handler(const struct device *dev)
290309
{
291310
struct spi_litex_data *data = dev->data;
292311
const struct spi_litex_dev_config *dev_config = dev->config;
312+
struct spi_context *ctx = &data->ctx;
293313

294314
if (litex_read8(dev_config->core_master_ev_pending_addr) & BIT(0)) {
295-
k_sem_give(&data->sem_rx_ready);
315+
spi_litex_spi_do_rx(dev);
296316

297317
/* ack reader irq */
298318
litex_write8(BIT(0), dev_config->core_master_ev_pending_addr);
319+
320+
if (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) {
321+
spi_litex_spi_do_tx(dev);
322+
} else {
323+
litex_write8(0, dev_config->core_master_ev_enable_addr);
324+
325+
litex_write32(0, dev_config->core_master_cs_addr);
326+
327+
spi_context_complete(ctx, dev, 0);
328+
}
299329
}
300330
}
301331
#endif /* SPI_LITEX_ANY_HAS_IRQ */
302332

333+
static int spi_litex_init(const struct device *dev)
334+
{
335+
const struct spi_litex_dev_config *dev_config = dev->config;
336+
struct spi_litex_data *data = dev->data;
337+
338+
#if SPI_LITEX_ANY_HAS_IRQ
339+
if (SPI_LITEX_HAS_IRQ) {
340+
dev_config->irq_config_func(dev);
341+
}
342+
#endif /* SPI_LITEX_ANY_HAS_IRQ */
343+
344+
data->len = dev_config->master_rxtx_size;
345+
346+
spiflash_len_mask_width_write(data->len * 8, SPI_LITEX_WIDTH, SPI_LITEX_MASK,
347+
dev_config->master_phyconfig_addr);
348+
349+
spi_context_unlock_unconditionally(&data->ctx);
350+
351+
return 0;
352+
}
353+
303354
/* Device Instantiation */
304355
static DEVICE_API(spi, spi_litex_api) = {
305356
.transceive = spi_litex_transceive,
@@ -316,21 +367,18 @@ static DEVICE_API(spi, spi_litex_api) = {
316367
BUILD_ASSERT(DT_INST_REG_HAS_NAME(n, core_master_ev_pending) && \
317368
DT_INST_REG_HAS_NAME(n, core_master_ev_enable), "registers for interrupts missing"); \
318369
\
319-
static int spi_litex_irq_config##n(const struct device *dev) \
370+
static void spi_litex_irq_config##n(const struct device *dev) \
320371
{ \
321372
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), spi_litex_irq_handler, \
322373
DEVICE_DT_INST_GET(n), 0); \
323374
\
324375
irq_enable(DT_INST_IRQN(n)); \
325-
\
326-
return 0; \
327376
};
328377

329-
#define SPI_LITEX_IRQ_DATA(n) \
330-
.sem_rx_ready = Z_SEM_INITIALIZER(spi_litex_data_##n.sem_rx_ready, 0, 1),
331-
332378
#define SPI_LITEX_IRQ_CONFIG(n) \
333379
.has_irq = DT_INST_IRQ_HAS_IDX(n, 0), \
380+
.irq_config_func = COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), \
381+
(spi_litex_irq_config##n), (NULL)), \
334382
.core_master_ev_pending_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, core_master_ev_pending, 0), \
335383
.core_master_ev_enable_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, core_master_ev_enable, 0),
336384

@@ -340,7 +388,6 @@ static DEVICE_API(spi, spi_litex_api) = {
340388
static struct spi_litex_data spi_litex_data_##n = { \
341389
SPI_CONTEXT_INIT_LOCK(spi_litex_data_##n, ctx), \
342390
SPI_CONTEXT_INIT_SYNC(spi_litex_data_##n, ctx), \
343-
IF_ENABLED(SPI_LITEX_ANY_HAS_IRQ, (SPI_LITEX_IRQ_DATA(n))) \
344391
}; \
345392
\
346393
static struct spi_litex_dev_config spi_litex_cfg_##n = { \
@@ -355,8 +402,7 @@ static DEVICE_API(spi, spi_litex_api) = {
355402
}; \
356403
\
357404
SPI_DEVICE_DT_INST_DEFINE(n, \
358-
COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), (spi_litex_irq_config##n), (NULL)), NULL, \
359-
&spi_litex_data_##n, &spi_litex_cfg_##n, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \
360-
&spi_litex_api);
405+
spi_litex_init, NULL, &spi_litex_data_##n, &spi_litex_cfg_##n, POST_KERNEL, \
406+
CONFIG_SPI_INIT_PRIORITY, &spi_litex_api);
361407

362408
DT_INST_FOREACH_STATUS_OKAY(SPI_INIT)

0 commit comments

Comments
 (0)