Skip to content

Commit de070f4

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 de070f4

File tree

1 file changed

+140
-88
lines changed

1 file changed

+140
-88
lines changed

drivers/spi/spi_litex_litespi.c

Lines changed: 140 additions & 88 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

@@ -70,6 +75,11 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
7075
{
7176
struct spi_litex_data *dev_data = dev->data;
7277

78+
if (spi_context_configured(&dev_data->ctx, config)) {
79+
/* Context is already configured */
80+
return 0;
81+
}
82+
7383
if (config->slave != 0) {
7484
if (config->slave >= SPI_MAX_CS_SIZE) {
7585
LOG_ERR("More slaves than supported");
@@ -93,11 +103,6 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
93103
return -ENOTSUP;
94104
}
95105

96-
if (config->operation & SPI_LOCK_ON) {
97-
LOG_ERR("Lock On not supported");
98-
return -ENOTSUP;
99-
}
100-
101106
if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) &&
102107
(config->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) {
103108
LOG_ERR("Only supports single mode");
@@ -128,6 +133,8 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
128133

129134
spi_litex_set_frequency(dev, config);
130135

136+
dev_data->ctx.config = config;
137+
131138
return 0;
132139
}
133140

@@ -144,40 +151,54 @@ static void spiflash_len_mask_width_write(uint32_t len, uint32_t width, uint32_t
144151
litex_write32(word, addr);
145152
}
146153

147-
static void spi_litex_wait_for_rx_ready(const struct device *dev)
154+
static void spi_litex_spi_do_tx(const struct device *dev)
148155
{
149156
const struct spi_litex_dev_config *dev_config = dev->config;
150-
151-
#if SPI_LITEX_ANY_HAS_IRQ
152157
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;
158+
struct spi_context *ctx = &data->ctx;
159+
uint8_t len;
160+
uint32_t txd = 0U;
161+
162+
len = MIN(spi_context_max_continuous_chunk(ctx), dev_config->core_master_rxtx_size);
163+
if (len != data->len) {
164+
spiflash_len_mask_width_write(len * 8, SPI_LITEX_WIDTH, SPI_LITEX_MASK,
165+
dev_config->core_master_phyconfig_addr);
166+
data->len = len;
158167
}
159-
#endif /* SPI_LITEX_ANY_HAS_IRQ */
160168

161-
while (!(litex_read8(dev_config->core_master_status_addr) &
162-
BIT(SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET))) {
163-
;
169+
if (spi_context_tx_buf_on(ctx)) {
170+
litex_spi_tx_put(len, &txd, ctx->tx_buf);
164171
}
172+
173+
LOG_DBG("txd: 0x%x", txd);
174+
litex_write32(txd, dev_config->core_master_rxtx_addr);
175+
176+
spi_context_update_tx(ctx, data->dfs, len / data->dfs);
165177
}
166178

167-
static int spi_litex_xfer(const struct device *dev, const struct spi_config *config)
179+
static void spi_litex_spi_do_rx(const struct device *dev)
168180
{
169181
const struct spi_litex_dev_config *dev_config = dev->config;
170182
struct spi_litex_data *data = dev->data;
171183
struct spi_context *ctx = &data->ctx;
172-
uint32_t txd, rxd;
173-
int ret = 0;
184+
uint32_t rxd;
185+
186+
rxd = litex_read32(dev_config->core_master_rxtx_addr);
187+
LOG_DBG("rxd: 0x%x", rxd);
188+
189+
if (spi_context_rx_buf_on(ctx)) {
190+
litex_spi_rx_put(data->len, &rxd, ctx->rx_buf);
191+
}
174192

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*/
193+
spi_context_update_rx(ctx, data->dfs, data->len / data->dfs);
194+
}
179195

180-
spiflash_len_mask_width_write(len * 8, width, mask, dev_config->core_master_phyconfig_addr);
196+
static int spi_litex_xfer(const struct device *dev, const struct spi_config *config)
197+
{
198+
const struct spi_litex_dev_config *dev_config = dev->config;
199+
struct spi_litex_data *data = dev->data;
200+
struct spi_context *ctx = &data->ctx;
201+
uint32_t rxd;
181202

182203
litex_write32(BIT(config->slave), dev_config->core_master_cs_addr);
183204

@@ -188,100 +209,104 @@ static int spi_litex_xfer(const struct device *dev, const struct spi_config *con
188209
LOG_DBG("flushed rxd: 0x%x", rxd);
189210
}
190211

212+
while (!(litex_read8(dev_config->core_master_status_addr) &
213+
BIT(SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET))) {
214+
;
215+
}
216+
191217
#if SPI_LITEX_ANY_HAS_IRQ
192-
if (dev_config->has_irq) {
218+
if (SPI_LITEX_HAS_IRQ) {
193219
litex_write8(BIT(0), dev_config->core_master_ev_enable_addr);
194220
litex_write8(BIT(0), dev_config->core_master_ev_pending_addr);
195-
k_sem_reset(&data->sem_rx_ready);
221+
222+
spi_litex_spi_do_tx(dev);
223+
224+
return spi_context_wait_for_completion(ctx);
196225
}
197226
#endif /* SPI_LITEX_ANY_HAS_IRQ */
198227

199228
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-
}
229+
spi_litex_spi_do_tx(dev);
212230

213231
while (!(litex_read8(dev_config->core_master_status_addr) &
214-
BIT(SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET))) {
232+
BIT(SPIFLASH_CORE_MASTER_STATUS_RX_READY_OFFSET))) {
215233
;
216234
}
217235

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-
236+
spi_litex_spi_do_rx(dev);
234237
} while (spi_context_tx_on(ctx) || spi_context_rx_on(ctx));
235238

236239
litex_write32(0, dev_config->core_master_cs_addr);
237240

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 */
244241
spi_context_complete(ctx, dev, 0);
245242

246-
return ret;
243+
return 0;
247244
}
248245

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)
246+
static int transceive(const struct device *dev,
247+
const struct spi_config *config,
248+
const struct spi_buf_set *tx_bufs,
249+
const struct spi_buf_set *rx_bufs,
250+
bool asynchronous,
251+
spi_callback_t cb,
252+
void *userdata)
252253
{
253254
struct spi_litex_data *data = dev->data;
254-
255-
int ret = spi_config(dev, config);
256-
257-
if (ret) {
258-
return ret;
259-
}
255+
int ret;
260256

261257
if (!tx_bufs && !rx_bufs) {
262258
return 0;
263259
}
264260

261+
spi_context_lock(&data->ctx, asynchronous, cb, userdata, config);
262+
263+
ret = spi_config(dev, config);
264+
if (ret < 0) {
265+
goto end;
266+
}
267+
265268
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, data->dfs);
266269

267270
ret = spi_litex_xfer(dev, config);
268271

272+
end:
273+
spi_context_release(&data->ctx, ret);
274+
269275
return ret;
270276
}
271277

278+
static int spi_litex_transceive(const struct device *dev,
279+
const struct spi_config *config,
280+
const struct spi_buf_set *tx_bufs,
281+
const struct spi_buf_set *rx_bufs)
282+
{
283+
return transceive(dev, config, tx_bufs, rx_bufs, false, NULL, NULL);
284+
}
285+
272286
#ifdef CONFIG_SPI_ASYNC
273-
static int spi_litex_transceive_async(const struct device *dev, const struct spi_config *config,
287+
static int spi_litex_transceive_async(const struct device *dev,
288+
const struct spi_config *config,
274289
const struct spi_buf_set *tx_bufs,
275290
const struct spi_buf_set *rx_bufs,
276-
struct k_poll_signal *async)
291+
spi_callback_t cb,
292+
void *userdata)
277293
{
294+
#if SPI_LITEX_ANY_HAS_IRQ
295+
const struct spi_litex_dev_config *dev_config = dev->config;
296+
297+
if (SPI_LITEX_HAS_IRQ) {
298+
return transceive(dev, config, tx_bufs, rx_bufs, true, cb, userdata);
299+
}
300+
#endif /* SPI_LITEX_ANY_HAS_IRQ */
278301
return -ENOTSUP;
279302
}
280303
#endif /* CONFIG_SPI_ASYNC */
281304

282305
static int spi_litex_release(const struct device *dev, const struct spi_config *config)
283306
{
307+
struct spi_litex_data *data = dev->data;
284308

309+
spi_context_unlock_unconditionally(&data->ctx);
285310
return 0;
286311
}
287312

@@ -290,16 +315,48 @@ static void spi_litex_irq_handler(const struct device *dev)
290315
{
291316
struct spi_litex_data *data = dev->data;
292317
const struct spi_litex_dev_config *dev_config = dev->config;
318+
struct spi_context *ctx = &data->ctx;
293319

294320
if (litex_read8(dev_config->core_master_ev_pending_addr) & BIT(0)) {
295-
k_sem_give(&data->sem_rx_ready);
321+
spi_litex_spi_do_rx(dev);
296322

297323
/* ack reader irq */
298324
litex_write8(BIT(0), dev_config->core_master_ev_pending_addr);
325+
326+
if (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) {
327+
spi_litex_spi_do_tx(dev);
328+
} else {
329+
litex_write8(0, dev_config->core_master_ev_enable_addr);
330+
331+
litex_write32(0, dev_config->core_master_cs_addr);
332+
333+
spi_context_complete(ctx, dev, 0);
334+
}
299335
}
300336
}
301337
#endif /* SPI_LITEX_ANY_HAS_IRQ */
302338

339+
static int spi_litex_init(const struct device *dev)
340+
{
341+
const struct spi_litex_dev_config *dev_config = dev->config;
342+
struct spi_litex_data *data = dev->data;
343+
344+
#if SPI_LITEX_ANY_HAS_IRQ
345+
if (SPI_LITEX_HAS_IRQ) {
346+
dev_config->irq_config_func(dev);
347+
}
348+
#endif /* SPI_LITEX_ANY_HAS_IRQ */
349+
350+
data->len = dev_config->master_rxtx_size;
351+
352+
spiflash_len_mask_width_write(data->len * 8, SPI_LITEX_WIDTH, SPI_LITEX_MASK,
353+
dev_config->master_phyconfig_addr);
354+
355+
spi_context_unlock_unconditionally(&data->ctx);
356+
357+
return 0;
358+
}
359+
303360
/* Device Instantiation */
304361
static DEVICE_API(spi, spi_litex_api) = {
305362
.transceive = spi_litex_transceive,
@@ -316,21 +373,18 @@ static DEVICE_API(spi, spi_litex_api) = {
316373
BUILD_ASSERT(DT_INST_REG_HAS_NAME(n, core_master_ev_pending) && \
317374
DT_INST_REG_HAS_NAME(n, core_master_ev_enable), "registers for interrupts missing"); \
318375
\
319-
static int spi_litex_irq_config##n(const struct device *dev) \
376+
static void spi_litex_irq_config##n(const struct device *dev) \
320377
{ \
321378
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), spi_litex_irq_handler, \
322379
DEVICE_DT_INST_GET(n), 0); \
323380
\
324381
irq_enable(DT_INST_IRQN(n)); \
325-
\
326-
return 0; \
327382
};
328383

329-
#define SPI_LITEX_IRQ_DATA(n) \
330-
.sem_rx_ready = Z_SEM_INITIALIZER(spi_litex_data_##n.sem_rx_ready, 0, 1),
331-
332384
#define SPI_LITEX_IRQ_CONFIG(n) \
333385
.has_irq = DT_INST_IRQ_HAS_IDX(n, 0), \
386+
.irq_config_func = COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), \
387+
(spi_litex_irq_config##n), (NULL)), \
334388
.core_master_ev_pending_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, core_master_ev_pending, 0), \
335389
.core_master_ev_enable_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, core_master_ev_enable, 0),
336390

@@ -340,7 +394,6 @@ static DEVICE_API(spi, spi_litex_api) = {
340394
static struct spi_litex_data spi_litex_data_##n = { \
341395
SPI_CONTEXT_INIT_LOCK(spi_litex_data_##n, ctx), \
342396
SPI_CONTEXT_INIT_SYNC(spi_litex_data_##n, ctx), \
343-
IF_ENABLED(SPI_LITEX_ANY_HAS_IRQ, (SPI_LITEX_IRQ_DATA(n))) \
344397
}; \
345398
\
346399
static struct spi_litex_dev_config spi_litex_cfg_##n = { \
@@ -355,8 +408,7 @@ static DEVICE_API(spi, spi_litex_api) = {
355408
}; \
356409
\
357410
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);
411+
spi_litex_init, NULL, &spi_litex_data_##n, &spi_litex_cfg_##n, POST_KERNEL, \
412+
CONFIG_SPI_INIT_PRIORITY, &spi_litex_api);
361413

362414
DT_INST_FOREACH_STATUS_OKAY(SPI_INIT)

0 commit comments

Comments
 (0)