@@ -20,6 +20,11 @@ struct stream_cfg {
20
20
nrfx_i2s_config_t nrfx_cfg ;
21
21
};
22
22
23
+ struct i2s_buf {
24
+ void * mem_block ;
25
+ size_t size ;
26
+ };
27
+
23
28
struct i2s_nrfx_drv_data {
24
29
struct onoff_manager * clk_mgr ;
25
30
struct onoff_client clk_cli ;
@@ -189,9 +194,14 @@ static void find_suitable_clock(const struct i2s_nrfx_drv_cfg *drv_cfg,
189
194
static bool get_next_tx_buffer (struct i2s_nrfx_drv_data * drv_data ,
190
195
nrfx_i2s_buffers_t * buffers )
191
196
{
197
+ struct i2s_buf buf ;
192
198
int ret = k_msgq_get (& drv_data -> tx_queue ,
193
- & buffers -> p_tx_buffer ,
199
+ & buf ,
194
200
K_NO_WAIT );
201
+ if (ret == 0 ) {
202
+ buffers -> p_tx_buffer = buf .mem_block ;
203
+ buffers -> buffer_size = buf .size / sizeof (uint32_t );
204
+ }
195
205
return (ret == 0 );
196
206
}
197
207
@@ -226,21 +236,22 @@ static void free_rx_buffer(struct i2s_nrfx_drv_data *drv_data, void *buffer)
226
236
static bool supply_next_buffers (struct i2s_nrfx_drv_data * drv_data ,
227
237
nrfx_i2s_buffers_t * next )
228
238
{
229
- uint32_t block_size = (drv_data -> active_dir == I2S_DIR_TX )
230
- ? drv_data -> tx .cfg .block_size
231
- : drv_data -> rx .cfg .block_size ;
232
-
233
- drv_data -> last_tx_buffer = next -> p_tx_buffer ;
234
-
235
239
if (drv_data -> active_dir != I2S_DIR_TX ) { /* -> RX active */
236
240
if (!get_next_rx_buffer (drv_data , next )) {
237
241
drv_data -> state = I2S_STATE_ERROR ;
238
242
nrfx_i2s_stop (drv_data -> p_i2s );
239
243
return false;
240
244
}
245
+ /* Set buffer size if there is no TX buffer (which effectively
246
+ * controls how many bytes will be received).
247
+ */
248
+ if (drv_data -> active_dir == I2S_DIR_RX ) {
249
+ next -> buffer_size =
250
+ drv_data -> rx .cfg .block_size / sizeof (uint32_t );
251
+ }
241
252
}
242
253
243
- next -> buffer_size = block_size / sizeof ( uint32_t ) ;
254
+ drv_data -> last_tx_buffer = next -> p_tx_buffer ;
244
255
245
256
LOG_DBG ("Next buffers: %p/%p" , next -> p_tx_buffer , next -> p_rx_buffer );
246
257
nrfx_i2s_next_buffers_set (drv_data -> p_i2s , next );
@@ -300,8 +311,12 @@ static void data_handler(const struct device *dev,
300
311
if (drv_data -> discard_rx ) {
301
312
free_rx_buffer (drv_data , released -> p_rx_buffer );
302
313
} else {
314
+ struct i2s_buf buf = {
315
+ .mem_block = released -> p_rx_buffer ,
316
+ .size = released -> buffer_size * sizeof (uint32_t )
317
+ };
303
318
int ret = k_msgq_put (& drv_data -> rx_queue ,
304
- & released -> p_rx_buffer ,
319
+ & buf ,
305
320
K_NO_WAIT );
306
321
if (ret < 0 ) {
307
322
LOG_ERR ("No room in RX queue" );
@@ -351,6 +366,7 @@ static void data_handler(const struct device *dev,
351
366
* before this buffer would be started again).
352
367
*/
353
368
next .p_tx_buffer = drv_data -> last_tx_buffer ;
369
+ next .buffer_size = 1 ;
354
370
} else if (get_next_tx_buffer (drv_data , & next )) {
355
371
/* Next TX buffer successfully retrieved from
356
372
* the queue, nothing more to do here.
@@ -367,6 +383,7 @@ static void data_handler(const struct device *dev,
367
383
* will be stopped earlier.
368
384
*/
369
385
next .p_tx_buffer = drv_data -> last_tx_buffer ;
386
+ next .buffer_size = 1 ;
370
387
} else {
371
388
/* Next TX buffer cannot be supplied now.
372
389
* Defer it to when the user writes more data.
@@ -383,21 +400,21 @@ static void data_handler(const struct device *dev,
383
400
static void purge_queue (const struct device * dev , enum i2s_dir dir )
384
401
{
385
402
struct i2s_nrfx_drv_data * drv_data = dev -> data ;
386
- void * mem_block ;
403
+ struct i2s_buf buf ;
387
404
388
405
if (dir == I2S_DIR_TX || dir == I2S_DIR_BOTH ) {
389
406
while (k_msgq_get (& drv_data -> tx_queue ,
390
- & mem_block ,
407
+ & buf ,
391
408
K_NO_WAIT ) == 0 ) {
392
- free_tx_buffer (drv_data , mem_block );
409
+ free_tx_buffer (drv_data , buf . mem_block );
393
410
}
394
411
}
395
412
396
413
if (dir == I2S_DIR_RX || dir == I2S_DIR_BOTH ) {
397
414
while (k_msgq_get (& drv_data -> rx_queue ,
398
- & mem_block ,
415
+ & buf ,
399
416
K_NO_WAIT ) == 0 ) {
400
- free_rx_buffer (drv_data , mem_block );
417
+ free_rx_buffer (drv_data , buf . mem_block );
401
418
}
402
419
}
403
420
}
@@ -560,6 +577,7 @@ static int i2s_nrfx_read(const struct device *dev,
560
577
void * * mem_block , size_t * size )
561
578
{
562
579
struct i2s_nrfx_drv_data * drv_data = dev -> data ;
580
+ struct i2s_buf buf ;
563
581
int ret ;
564
582
565
583
if (!drv_data -> rx_configured ) {
@@ -568,18 +586,19 @@ static int i2s_nrfx_read(const struct device *dev,
568
586
}
569
587
570
588
ret = k_msgq_get (& drv_data -> rx_queue ,
571
- mem_block ,
589
+ & buf ,
572
590
(drv_data -> state == I2S_STATE_ERROR )
573
591
? K_NO_WAIT
574
592
: SYS_TIMEOUT_MS (drv_data -> rx .cfg .timeout ));
575
593
if (ret == - ENOMSG ) {
576
594
return - EIO ;
577
595
}
578
596
579
- LOG_DBG ("Released RX %p" , * mem_block );
597
+ LOG_DBG ("Released RX %p" , buf . mem_block );
580
598
581
599
if (ret == 0 ) {
582
- * size = drv_data -> rx .cfg .block_size ;
600
+ * mem_block = buf .mem_block ;
601
+ * size = buf .size ;
583
602
}
584
603
585
604
return ret ;
@@ -589,6 +608,7 @@ static int i2s_nrfx_write(const struct device *dev,
589
608
void * mem_block , size_t size )
590
609
{
591
610
struct i2s_nrfx_drv_data * drv_data = dev -> data ;
611
+ struct i2s_buf buf = { .mem_block = mem_block , .size = size };
592
612
int ret ;
593
613
594
614
if (!drv_data -> tx_configured ) {
@@ -602,14 +622,14 @@ static int i2s_nrfx_write(const struct device *dev,
602
622
return - EIO ;
603
623
}
604
624
605
- if (size != drv_data -> tx .cfg .block_size ) {
606
- LOG_ERR ("This device can only write blocks of %u bytes" ,
625
+ if (size > drv_data -> tx .cfg .block_size || size < sizeof ( uint32_t ) ) {
626
+ LOG_ERR ("This device can only write blocks up to %u bytes" ,
607
627
drv_data -> tx .cfg .block_size );
608
628
return - EIO ;
609
629
}
610
630
611
631
ret = k_msgq_put (& drv_data -> tx_queue ,
612
- & mem_block ,
632
+ & buf ,
613
633
SYS_TIMEOUT_MS (drv_data -> tx .cfg .timeout ));
614
634
if (ret < 0 ) {
615
635
return ret ;
@@ -662,12 +682,17 @@ static int start_transfer(struct i2s_nrfx_drv_data *drv_data)
662
682
/* Failed to allocate next RX buffer */
663
683
ret = - ENOMEM ;
664
684
} else {
665
- uint32_t block_size = (drv_data -> active_dir == I2S_DIR_TX )
666
- ? drv_data -> tx .cfg .block_size
667
- : drv_data -> rx .cfg .block_size ;
668
685
nrfx_err_t err ;
669
686
670
- initial_buffers .buffer_size = block_size / sizeof (uint32_t );
687
+ /* It is necessary to set buffer size here only for I2S_DIR_RX,
688
+ * because only then the get_next_tx_buffer() call in the if
689
+ * condition above gets short-circuited.
690
+ */
691
+ if (drv_data -> active_dir == I2S_DIR_RX ) {
692
+ initial_buffers .buffer_size =
693
+ drv_data -> rx .cfg .block_size / sizeof (uint32_t );
694
+ }
695
+
671
696
drv_data -> last_tx_buffer = initial_buffers .p_tx_buffer ;
672
697
673
698
err = nrfx_i2s_start (drv_data -> p_i2s , & initial_buffers , 0 );
@@ -904,8 +929,8 @@ static const struct i2s_driver_api i2s_nrf_drv_api = {
904
929
#define I2S_CLK_SRC (idx ) DT_STRING_TOKEN(I2S(idx), clock_source)
905
930
906
931
#define I2S_NRFX_DEVICE (idx ) \
907
- static void * tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \
908
- static void * rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \
932
+ static struct i2s_buf tx_msgs##idx[CONFIG_I2S_NRFX_TX_BLOCK_COUNT]; \
933
+ static struct i2s_buf rx_msgs##idx[CONFIG_I2S_NRFX_RX_BLOCK_COUNT]; \
909
934
static void data_handler##idx(nrfx_i2s_buffers_t const *p_released, \
910
935
uint32_t status) \
911
936
{ \
@@ -941,10 +966,10 @@ static const struct i2s_driver_api i2s_nrf_drv_api = {
941
966
return err; \
942
967
} \
943
968
k_msgq_init(&i2s_nrfx_data##idx.tx_queue, \
944
- (char *)tx_msgs##idx, sizeof(void *), \
969
+ (char *)tx_msgs##idx, sizeof(struct i2s_buf), \
945
970
ARRAY_SIZE(tx_msgs##idx)); \
946
971
k_msgq_init(&i2s_nrfx_data##idx.rx_queue, \
947
- (char *)rx_msgs##idx, sizeof(void *), \
972
+ (char *)rx_msgs##idx, sizeof(struct i2s_buf), \
948
973
ARRAY_SIZE(rx_msgs##idx)); \
949
974
init_clock_manager(dev); \
950
975
return 0; \
0 commit comments