@@ -1193,169 +1193,188 @@ static const struct i2s_config *i2s_esp32_config_get(const struct device *dev, e
1193
1193
return & stream -> data -> i2s_cfg ;
1194
1194
}
1195
1195
1196
- static int i2s_esp32_trigger_stream (const struct device * dev , const struct i2s_esp32_stream * stream ,
1197
- enum i2s_dir dir , enum i2s_trigger_cmd cmd )
1196
+ static inline bool tx_has_data (const struct i2s_esp32_stream * s )
1198
1197
{
1199
- const struct i2s_esp32_cfg * dev_cfg = dev -> config ;
1200
- const i2s_hal_context_t * hal = & dev_cfg -> hal ;
1201
- unsigned int key ;
1202
- int err ;
1203
-
1204
- switch (cmd ) {
1205
- case I2S_TRIGGER_START :
1206
- /* if already streaming, treat as success */
1207
- if (stream -> data -> state == I2S_STATE_RUNNING ) {
1208
- LOG_DBG ("START ignored: already RUNNING" );
1209
- return 0 ;
1210
- }
1211
- if (stream -> data -> state != I2S_STATE_READY ) {
1212
- LOG_ERR ("START - Invalid state: %d" , (int )stream -> data -> state );
1213
- return - EIO ;
1214
- }
1198
+ return k_msgq_num_used_get (& s -> data -> queue ) > 0 ;
1199
+ }
1215
1200
1216
- key = irq_lock ();
1201
+ static inline bool is_ready_or_running (const struct i2s_esp32_stream * s )
1202
+ {
1203
+ return s -> data -> state == I2S_STATE_READY || s -> data -> state == I2S_STATE_RUNNING ;
1204
+ }
1217
1205
1218
- if (dir == I2S_DIR_RX ) {
1219
- i2s_hal_rx_stop (hal );
1220
- i2s_hal_rx_reset (hal );
1206
+ static inline void reset_fifo (const i2s_hal_context_t * hal , enum i2s_dir dir )
1207
+ {
1208
+ if (dir == I2S_DIR_RX ) {
1209
+ i2s_hal_rx_stop (hal );
1210
+ i2s_hal_rx_reset (hal );
1221
1211
#if !SOC_GDMA_SUPPORTED
1222
- i2s_hal_rx_reset_dma (hal );
1223
- #endif /* !SOC_GDMA_SUPPORTED */
1224
- i2s_hal_rx_reset_fifo (hal );
1225
- } else if ( dir == I2S_DIR_TX ) {
1226
- i2s_hal_tx_stop (hal );
1227
- i2s_hal_tx_reset (hal );
1212
+ i2s_hal_rx_reset_dma (hal );
1213
+ #endif
1214
+ i2s_hal_rx_reset_fifo (hal );
1215
+ } else {
1216
+ i2s_hal_tx_stop (hal );
1217
+ i2s_hal_tx_reset (hal );
1228
1218
#if !SOC_GDMA_SUPPORTED
1229
- i2s_hal_tx_reset_dma (hal );
1230
- #endif /* !SOC_GDMA_SUPPORTED */
1231
- i2s_hal_tx_reset_fifo (hal );
1232
- }
1219
+ i2s_hal_tx_reset_dma (hal );
1220
+ #endif
1221
+ i2s_hal_tx_reset_fifo (hal );
1222
+ }
1223
+ }
1233
1224
1234
- err = stream -> conf -> start_transfer (dev );
1235
- if (err < 0 ) {
1236
- LOG_ERR ("START - Transfer start failed: %d" , err );
1237
- irq_unlock (key );
1238
- return - EIO ;
1239
- }
1240
- stream -> data -> last_block = false;
1241
- /*
1242
- * If no mem_block was available (queue empty), stay READY.
1243
- * The next write() will auto-kick TX into RUNNING.
1244
- */
1245
- if (dir == I2S_DIR_TX && stream -> data -> mem_block == NULL &&
1246
- !stream -> data -> dma_pending ) {
1247
- stream -> data -> state = I2S_STATE_READY ;
1248
- irq_unlock (key );
1249
- return 0 ;
1250
- }
1251
- stream -> data -> state = I2S_STATE_RUNNING ;
1252
- irq_unlock (key );
1253
- break ;
1225
+ static int handle_start (const struct device * dev , const struct i2s_esp32_stream * stream ,
1226
+ enum i2s_dir dir , const i2s_hal_context_t * hal )
1227
+ {
1228
+ if (stream -> data -> state == I2S_STATE_RUNNING ) {
1229
+ LOG_DBG ("START ignored: already RUNNING" );
1230
+ return 0 ;
1231
+ }
1232
+ if (stream -> data -> state != I2S_STATE_READY ) {
1233
+ LOG_ERR ("START - Invalid state: %d" , (int )stream -> data -> state );
1234
+ return - EIO ;
1235
+ }
1254
1236
1255
- case I2S_TRIGGER_STOP :
1256
- key = irq_lock ();
1257
- if (stream -> data -> state == I2S_STATE_READY ) {
1258
- /* Already idle; treat STOP as success */
1259
- irq_unlock (key );
1260
- return 0 ;
1261
- }
1262
- if (stream -> data -> state != I2S_STATE_RUNNING ) {
1263
- irq_unlock (key );
1264
- LOG_ERR ("STOP - Invalid state: %d" , (int )stream -> data -> state );
1265
- return - EIO ;
1266
- }
1237
+ reset_fifo (hal , dir );
1267
1238
1268
- if (stream -> data -> dma_pending ) {
1269
- stream -> data -> stop_without_draining = true;
1270
- stream -> data -> state = I2S_STATE_STOPPING ;
1271
- } else {
1272
- stream -> conf -> stop_transfer (dev );
1273
- stream -> data -> last_block = true;
1274
- stream -> data -> state = I2S_STATE_READY ;
1275
- }
1239
+ int err = stream -> conf -> start_transfer (dev );
1276
1240
1277
- irq_unlock (key );
1278
- break ;
1241
+ if (err < 0 ) {
1242
+ LOG_ERR ("START - Transfer start failed: %d" , err );
1243
+ return - EIO ;
1244
+ }
1279
1245
1280
- case I2S_TRIGGER_DRAIN :
1281
- key = irq_lock ();
1282
- int32_t st = stream -> data -> state ;
1246
+ stream -> data -> last_block = false;
1247
+
1248
+ /* TX: if no mem_block was set (queue empty), remain READY */
1249
+ if (dir == I2S_DIR_TX && stream -> data -> mem_block == NULL && !stream -> data -> dma_pending ) {
1250
+ stream -> data -> state = I2S_STATE_READY ;
1251
+ return 0 ;
1252
+ }
1253
+
1254
+ stream -> data -> state = I2S_STATE_RUNNING ;
1255
+ return 0 ;
1256
+ }
1257
+
1258
+ static int handle_stop (const struct device * dev , const struct i2s_esp32_stream * stream )
1259
+ {
1260
+ if (stream -> data -> state == I2S_STATE_READY ) {
1261
+ return 0 ; /* already idle */
1262
+ }
1263
+ if (stream -> data -> state != I2S_STATE_RUNNING ) {
1264
+ LOG_ERR ("STOP - Invalid state: %d" , (int )stream -> data -> state );
1265
+ return - EIO ;
1266
+ }
1267
+
1268
+ if (stream -> data -> dma_pending ) {
1269
+ stream -> data -> stop_without_draining = true;
1270
+ stream -> data -> state = I2S_STATE_STOPPING ;
1271
+ } else {
1272
+ stream -> conf -> stop_transfer (dev );
1273
+ stream -> data -> last_block = true;
1274
+ stream -> data -> state = I2S_STATE_READY ;
1275
+ }
1276
+ return 0 ;
1277
+ }
1278
+
1279
+ static int handle_drain (const struct device * dev , const struct i2s_esp32_stream * stream ,
1280
+ enum i2s_dir dir )
1281
+ {
1282
+ int32_t st = stream -> data -> state ;
1283
1283
1284
- if (st == I2S_STATE_READY ) {
1284
+ if (st != I2S_STATE_READY && st != I2S_STATE_RUNNING ) {
1285
+ LOG_ERR ("DRAIN - Invalid state: %d" , (int )st );
1286
+ return - EIO ;
1287
+ }
1288
+
1289
+ if (st == I2S_STATE_READY ) {
1285
1290
#if I2S_ESP32_IS_DIR_EN (tx )
1286
- if (dir == I2S_DIR_TX ) {
1287
- bool have_data = (k_msgq_num_used_get (& stream -> data -> queue ) > 0 );
1288
-
1289
- /* If there's data queued and TX is idle, kick once and drain */
1290
- if (have_data && !stream -> data -> dma_pending ) {
1291
- int kick = stream -> conf -> start_transfer (dev );
1292
-
1293
- if (kick < 0 ) {
1294
- irq_unlock (key );
1295
- LOG_ERR ("DRAIN - autostart failed: %d" , kick );
1296
- return - EIO ;
1297
- }
1298
- stream -> data -> last_block = false;
1299
- stream -> data -> stop_without_draining = false;
1300
- stream -> data -> state = I2S_STATE_STOPPING ;
1301
- irq_unlock (key );
1302
- break ;
1303
- }
1291
+ if (dir == I2S_DIR_TX ) {
1292
+ bool have_data = tx_has_data (stream );
1293
+
1294
+ /* If idle but data queued, kick once and drain */
1295
+ if (have_data && !stream -> data -> dma_pending ) {
1296
+ int kick = stream -> conf -> start_transfer (dev );
1304
1297
1305
- /* Nothing to drain (idle and no queued blocks) */
1306
- if (!have_data && !stream -> data -> dma_pending ) {
1307
- irq_unlock (key );
1308
- return 0 ;
1298
+ if (kick < 0 ) {
1299
+ LOG_ERR ("DRAIN - autostart failed: %d" , kick );
1300
+ return - EIO ;
1309
1301
}
1302
+ stream -> data -> last_block = false;
1303
+ stream -> data -> stop_without_draining = false;
1304
+ stream -> data -> state = I2S_STATE_STOPPING ;
1305
+ return 0 ;
1306
+ }
1307
+
1308
+ /* Idle and no data: nothing to drain */
1309
+ if (!have_data && !stream -> data -> dma_pending ) {
1310
+ return 0 ;
1310
1311
}
1312
+ }
1311
1313
#endif /* I2S_ESP32_IS_DIR_EN(tx) */
1312
1314
1313
1315
#if I2S_ESP32_IS_DIR_EN (rx )
1314
- if (dir == I2S_DIR_RX ) {
1315
- /* If RX is idle and no DMA pending, nothing to drain */
1316
- if (!stream -> data -> dma_pending ) {
1317
- irq_unlock (key );
1318
- return 0 ;
1319
- }
1316
+ if (dir == I2S_DIR_RX ) {
1317
+ if (!stream -> data -> dma_pending ) {
1318
+ return 0 ; /* idle, no data */
1320
1319
}
1321
- #endif /* I2S_ESP32_IS_DIR_EN(rx) */
1322
- } else {
1323
- irq_unlock (key );
1324
- LOG_ERR ("DRAIN - Invalid state: %d" , (int )st );
1325
- return - EIO ;
1326
1320
}
1321
+ #endif /* I2S_ESP32_IS_DIR_EN(rx) */
1322
+ }
1327
1323
1324
+ /* Common tail: RUNNING, or READY with dma_pending */
1328
1325
#if I2S_ESP32_IS_DIR_EN (tx )
1329
- if (dir == I2S_DIR_TX ) {
1330
- if (k_msgq_num_used_get (& stream -> data -> queue ) > 0 ||
1331
- stream -> data -> dma_pending ) {
1332
- stream -> data -> stop_without_draining = false;
1333
- stream -> data -> state = I2S_STATE_STOPPING ;
1334
- } else {
1335
- stream -> conf -> stop_transfer (dev );
1336
- stream -> data -> state = I2S_STATE_READY ;
1337
- }
1326
+ if (dir == I2S_DIR_TX ) {
1327
+ if (tx_has_data (stream ) || stream -> data -> dma_pending ) {
1328
+ stream -> data -> stop_without_draining = false;
1329
+ stream -> data -> state = I2S_STATE_STOPPING ;
1330
+ } else {
1331
+ stream -> conf -> stop_transfer (dev );
1332
+ stream -> data -> state = I2S_STATE_READY ;
1338
1333
}
1334
+ }
1339
1335
#endif /* I2S_ESP32_IS_DIR_EN(tx) */
1340
1336
1341
1337
#if I2S_ESP32_IS_DIR_EN (rx )
1342
- if (dir == I2S_DIR_RX ) {
1343
- if (stream -> data -> dma_pending ) {
1344
- stream -> data -> stop_without_draining = true;
1345
- stream -> data -> state = I2S_STATE_STOPPING ;
1346
- } else {
1347
- stream -> conf -> stop_transfer (dev );
1348
- stream -> data -> last_block = true;
1349
- stream -> data -> state = I2S_STATE_READY ;
1350
- }
1338
+ if (dir == I2S_DIR_RX ) {
1339
+ if (stream -> data -> dma_pending ) {
1340
+ stream -> data -> stop_without_draining = true;
1341
+ stream -> data -> state = I2S_STATE_STOPPING ;
1342
+ } else {
1343
+ stream -> conf -> stop_transfer (dev );
1344
+ stream -> data -> last_block = true;
1345
+ stream -> data -> state = I2S_STATE_READY ;
1351
1346
}
1347
+ }
1352
1348
#endif /* I2S_ESP32_IS_DIR_EN(rx) */
1353
1349
1354
- irq_unlock (key );
1350
+ return 0 ;
1351
+ }
1352
+
1353
+ static int i2s_esp32_trigger_stream (const struct device * dev , const struct i2s_esp32_stream * stream ,
1354
+ enum i2s_dir dir , enum i2s_trigger_cmd cmd )
1355
+ {
1356
+ const struct i2s_esp32_cfg * dev_cfg = dev -> config ;
1357
+ const i2s_hal_context_t * hal = & dev_cfg -> hal ;
1358
+
1359
+ unsigned int key = irq_lock ();
1360
+ int ret = 0 ;
1361
+
1362
+ switch (cmd ) {
1363
+ case I2S_TRIGGER_START :
1364
+ ret = handle_start (dev , stream , dir , hal );
1365
+ break ;
1366
+
1367
+ case I2S_TRIGGER_STOP :
1368
+ ret = handle_stop (dev , stream );
1369
+ break ;
1370
+
1371
+ case I2S_TRIGGER_DRAIN :
1372
+ ret = handle_drain (dev , stream , dir );
1355
1373
break ;
1356
1374
1357
1375
case I2S_TRIGGER_DROP :
1358
1376
if (stream -> data -> state == I2S_STATE_NOT_READY ) {
1377
+ irq_unlock (key );
1359
1378
LOG_ERR ("DROP - invalid state: %d" , (int )stream -> data -> state );
1360
1379
return - EIO ;
1361
1380
}
@@ -1366,6 +1385,7 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e
1366
1385
1367
1386
case I2S_TRIGGER_PREPARE :
1368
1387
if (stream -> data -> state != I2S_STATE_ERROR ) {
1388
+ irq_unlock (key );
1369
1389
LOG_ERR ("PREPARE - invalid state: %d" , (int )stream -> data -> state );
1370
1390
return - EIO ;
1371
1391
}
@@ -1374,11 +1394,13 @@ static int i2s_esp32_trigger_stream(const struct device *dev, const struct i2s_e
1374
1394
break ;
1375
1395
1376
1396
default :
1397
+ irq_unlock (key );
1377
1398
LOG_ERR ("Unsupported trigger command: %d" , (int )cmd );
1378
1399
return - EINVAL ;
1379
1400
}
1380
1401
1381
- return 0 ;
1402
+ irq_unlock (key );
1403
+ return ret ;
1382
1404
}
1383
1405
1384
1406
static int i2s_esp32_trigger (const struct device * dev , enum i2s_dir dir , enum i2s_trigger_cmd cmd )
0 commit comments