@@ -14,6 +14,9 @@ LOG_MODULE_REGISTER(spi_litex_litespi);
14
14
#include "spi_litex_common.h"
15
15
16
16
#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)
17
20
18
21
#define SPIFLASH_CORE_MASTER_PHYCONFIG_LEN_OFFSET 0x0
19
22
#define SPIFLASH_CORE_MASTER_PHYCONFIG_WIDTH_OFFSET 0x1
@@ -25,6 +28,9 @@ LOG_MODULE_REGISTER(spi_litex_litespi);
25
28
#define SPI_MAX_WORD_SIZE 32
26
29
#define SPI_MAX_CS_SIZE 4
27
30
31
+ #define SPI_LITEX_WIDTH BIT(0)
32
+ #define SPI_LITEX_MASK BIT(0)
33
+
28
34
struct spi_litex_dev_config {
29
35
uint32_t core_master_cs_addr ;
30
36
uint32_t core_master_phyconfig_addr ;
@@ -35,6 +41,7 @@ struct spi_litex_dev_config {
35
41
bool phy_clk_divisor_exists ;
36
42
#if SPI_LITEX_ANY_HAS_IRQ
37
43
bool has_irq ;
44
+ void (* irq_config_func )(const struct device * dev );
38
45
uint32_t core_master_ev_pending_addr ;
39
46
uint32_t core_master_ev_enable_addr ;
40
47
#endif
@@ -43,9 +50,7 @@ struct spi_litex_dev_config {
43
50
struct spi_litex_data {
44
51
struct spi_context ctx ;
45
52
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 */
49
54
};
50
55
51
56
@@ -70,6 +75,11 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
70
75
{
71
76
struct spi_litex_data * dev_data = dev -> data ;
72
77
78
+ if (spi_context_configured (& dev_data -> ctx , config )) {
79
+ /* Context is already configured */
80
+ return 0 ;
81
+ }
82
+
73
83
if (config -> slave != 0 ) {
74
84
if (config -> slave >= SPI_MAX_CS_SIZE ) {
75
85
LOG_ERR ("More slaves than supported" );
@@ -93,11 +103,6 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
93
103
return - ENOTSUP ;
94
104
}
95
105
96
- if (config -> operation & SPI_LOCK_ON ) {
97
- LOG_ERR ("Lock On not supported" );
98
- return - ENOTSUP ;
99
- }
100
-
101
106
if (IS_ENABLED (CONFIG_SPI_EXTENDED_MODES ) &&
102
107
(config -> operation & SPI_LINES_MASK ) != SPI_LINES_SINGLE ) {
103
108
LOG_ERR ("Only supports single mode" );
@@ -128,6 +133,8 @@ static int spi_config(const struct device *dev, const struct spi_config *config)
128
133
129
134
spi_litex_set_frequency (dev , config );
130
135
136
+ dev_data -> ctx .config = config ;
137
+
131
138
return 0 ;
132
139
}
133
140
@@ -144,40 +151,54 @@ static void spiflash_len_mask_width_write(uint32_t len, uint32_t width, uint32_t
144
151
litex_write32 (word , addr );
145
152
}
146
153
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 )
148
155
{
149
156
const struct spi_litex_dev_config * dev_config = dev -> config ;
150
-
151
- #if SPI_LITEX_ANY_HAS_IRQ
152
157
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 ;
158
167
}
159
- #endif /* SPI_LITEX_ANY_HAS_IRQ */
160
168
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 );
164
171
}
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 );
165
177
}
166
178
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 )
168
180
{
169
181
const struct spi_litex_dev_config * dev_config = dev -> config ;
170
182
struct spi_litex_data * data = dev -> data ;
171
183
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
+ }
174
192
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
+ }
179
195
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 ;
181
202
182
203
litex_write32 (BIT (config -> slave ), dev_config -> core_master_cs_addr );
183
204
@@ -188,100 +209,104 @@ static int spi_litex_xfer(const struct device *dev, const struct spi_config *con
188
209
LOG_DBG ("flushed rxd: 0x%x" , rxd );
189
210
}
190
211
212
+ while (!(litex_read8 (dev_config -> core_master_status_addr ) &
213
+ BIT (SPIFLASH_CORE_MASTER_STATUS_TX_READY_OFFSET ))) {
214
+ ;
215
+ }
216
+
191
217
#if SPI_LITEX_ANY_HAS_IRQ
192
- if (dev_config -> has_irq ) {
218
+ if (SPI_LITEX_HAS_IRQ ) {
193
219
litex_write8 (BIT (0 ), dev_config -> core_master_ev_enable_addr );
194
220
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 );
196
225
}
197
226
#endif /* SPI_LITEX_ANY_HAS_IRQ */
198
227
199
228
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 );
212
230
213
231
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 ))) {
215
233
;
216
234
}
217
235
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 );
234
237
} while (spi_context_tx_on (ctx ) || spi_context_rx_on (ctx ));
235
238
236
239
litex_write32 (0 , dev_config -> core_master_cs_addr );
237
240
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 */
244
241
spi_context_complete (ctx , dev , 0 );
245
242
246
- return ret ;
243
+ return 0 ;
247
244
}
248
245
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 )
252
253
{
253
254
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 ;
260
256
261
257
if (!tx_bufs && !rx_bufs ) {
262
258
return 0 ;
263
259
}
264
260
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
+
265
268
spi_context_buffers_setup (& data -> ctx , tx_bufs , rx_bufs , data -> dfs );
266
269
267
270
ret = spi_litex_xfer (dev , config );
268
271
272
+ end :
273
+ spi_context_release (& data -> ctx , ret );
274
+
269
275
return ret ;
270
276
}
271
277
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
+
272
286
#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 ,
274
289
const struct spi_buf_set * tx_bufs ,
275
290
const struct spi_buf_set * rx_bufs ,
276
- struct k_poll_signal * async )
291
+ spi_callback_t cb ,
292
+ void * userdata )
277
293
{
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 */
278
301
return - ENOTSUP ;
279
302
}
280
303
#endif /* CONFIG_SPI_ASYNC */
281
304
282
305
static int spi_litex_release (const struct device * dev , const struct spi_config * config )
283
306
{
307
+ struct spi_litex_data * data = dev -> data ;
284
308
309
+ spi_context_unlock_unconditionally (& data -> ctx );
285
310
return 0 ;
286
311
}
287
312
@@ -290,16 +315,48 @@ static void spi_litex_irq_handler(const struct device *dev)
290
315
{
291
316
struct spi_litex_data * data = dev -> data ;
292
317
const struct spi_litex_dev_config * dev_config = dev -> config ;
318
+ struct spi_context * ctx = & data -> ctx ;
293
319
294
320
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 );
296
322
297
323
/* ack reader irq */
298
324
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
+ }
299
335
}
300
336
}
301
337
#endif /* SPI_LITEX_ANY_HAS_IRQ */
302
338
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
+
303
360
/* Device Instantiation */
304
361
static DEVICE_API (spi , spi_litex_api ) = {
305
362
.transceive = spi_litex_transceive ,
@@ -316,21 +373,18 @@ static DEVICE_API(spi, spi_litex_api) = {
316
373
BUILD_ASSERT(DT_INST_REG_HAS_NAME(n, core_master_ev_pending) && \
317
374
DT_INST_REG_HAS_NAME(n, core_master_ev_enable), "registers for interrupts missing"); \
318
375
\
319
- static int spi_litex_irq_config##n(const struct device *dev) \
376
+ static void spi_litex_irq_config##n(const struct device *dev) \
320
377
{ \
321
378
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), spi_litex_irq_handler, \
322
379
DEVICE_DT_INST_GET(n), 0); \
323
380
\
324
381
irq_enable(DT_INST_IRQN(n)); \
325
- \
326
- return 0; \
327
382
};
328
383
329
- #define SPI_LITEX_IRQ_DATA (n ) \
330
- .sem_rx_ready = Z_SEM_INITIALIZER(spi_litex_data_##n.sem_rx_ready, 0, 1),
331
-
332
384
#define SPI_LITEX_IRQ_CONFIG (n ) \
333
385
.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)), \
334
388
.core_master_ev_pending_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, core_master_ev_pending, 0), \
335
389
.core_master_ev_enable_addr = DT_INST_REG_ADDR_BY_NAME_OR(n, core_master_ev_enable, 0),
336
390
@@ -340,7 +394,6 @@ static DEVICE_API(spi, spi_litex_api) = {
340
394
static struct spi_litex_data spi_litex_data_##n = { \
341
395
SPI_CONTEXT_INIT_LOCK(spi_litex_data_##n, ctx), \
342
396
SPI_CONTEXT_INIT_SYNC(spi_litex_data_##n, ctx), \
343
- IF_ENABLED(SPI_LITEX_ANY_HAS_IRQ, (SPI_LITEX_IRQ_DATA(n))) \
344
397
}; \
345
398
\
346
399
static struct spi_litex_dev_config spi_litex_cfg_##n = { \
@@ -355,8 +408,7 @@ static DEVICE_API(spi, spi_litex_api) = {
355
408
}; \
356
409
\
357
410
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);
361
413
362
414
DT_INST_FOREACH_STATUS_OKAY (SPI_INIT )
0 commit comments