diff options
| -rw-r--r-- | sound/soc/sh/fsi.c | 51 |
1 files changed, 33 insertions, 18 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 30390260bb67..b33ca7cd085b 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
| @@ -235,6 +235,8 @@ struct fsi_stream { | |||
| 235 | struct sh_dmae_slave slave; /* see fsi_handler_init() */ | 235 | struct sh_dmae_slave slave; /* see fsi_handler_init() */ |
| 236 | struct work_struct work; | 236 | struct work_struct work; |
| 237 | dma_addr_t dma; | 237 | dma_addr_t dma; |
| 238 | int loop_cnt; | ||
| 239 | int additional_pos; | ||
| 238 | }; | 240 | }; |
| 239 | 241 | ||
| 240 | struct fsi_clk { | 242 | struct fsi_clk { |
| @@ -1289,6 +1291,8 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io) | |||
| 1289 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | | 1291 | io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) | |
| 1290 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); | 1292 | BUSOP_SET(16, PACKAGE_16BITBUS_STREAM); |
| 1291 | 1293 | ||
| 1294 | io->loop_cnt = 2; /* push 1st, 2nd period first, then 3rd, 4th... */ | ||
| 1295 | io->additional_pos = 0; | ||
| 1292 | io->dma = dma_map_single(dai->dev, runtime->dma_area, | 1296 | io->dma = dma_map_single(dai->dev, runtime->dma_area, |
| 1293 | snd_pcm_lib_buffer_bytes(io->substream), dir); | 1297 | snd_pcm_lib_buffer_bytes(io->substream), dir); |
| 1294 | return 0; | 1298 | return 0; |
| @@ -1305,11 +1309,15 @@ static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io) | |||
| 1305 | return 0; | 1309 | return 0; |
| 1306 | } | 1310 | } |
| 1307 | 1311 | ||
| 1308 | static dma_addr_t fsi_dma_get_area(struct fsi_stream *io) | 1312 | static dma_addr_t fsi_dma_get_area(struct fsi_stream *io, int additional) |
| 1309 | { | 1313 | { |
| 1310 | struct snd_pcm_runtime *runtime = io->substream->runtime; | 1314 | struct snd_pcm_runtime *runtime = io->substream->runtime; |
| 1315 | int period = io->period_pos + additional; | ||
| 1311 | 1316 | ||
| 1312 | return io->dma + samples_to_bytes(runtime, io->buff_sample_pos); | 1317 | if (period >= runtime->periods) |
| 1318 | period = 0; | ||
| 1319 | |||
| 1320 | return io->dma + samples_to_bytes(runtime, period * io->period_samples); | ||
| 1313 | } | 1321 | } |
| 1314 | 1322 | ||
| 1315 | static void fsi_dma_complete(void *data) | 1323 | static void fsi_dma_complete(void *data) |
| @@ -1321,7 +1329,7 @@ static void fsi_dma_complete(void *data) | |||
| 1321 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? | 1329 | enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ? |
| 1322 | DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1330 | DMA_TO_DEVICE : DMA_FROM_DEVICE; |
| 1323 | 1331 | ||
| 1324 | dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io), | 1332 | dma_sync_single_for_cpu(dai->dev, fsi_dma_get_area(io, 0), |
| 1325 | samples_to_bytes(runtime, io->period_samples), dir); | 1333 | samples_to_bytes(runtime, io->period_samples), dir); |
| 1326 | 1334 | ||
| 1327 | io->buff_sample_pos += io->period_samples; | 1335 | io->buff_sample_pos += io->period_samples; |
| @@ -1347,7 +1355,7 @@ static void fsi_dma_do_work(struct work_struct *work) | |||
| 1347 | struct snd_pcm_runtime *runtime; | 1355 | struct snd_pcm_runtime *runtime; |
| 1348 | enum dma_data_direction dir; | 1356 | enum dma_data_direction dir; |
| 1349 | int is_play = fsi_stream_is_play(fsi, io); | 1357 | int is_play = fsi_stream_is_play(fsi, io); |
| 1350 | int len; | 1358 | int len, i; |
| 1351 | dma_addr_t buf; | 1359 | dma_addr_t buf; |
| 1352 | 1360 | ||
| 1353 | if (!fsi_stream_is_working(fsi, io)) | 1361 | if (!fsi_stream_is_working(fsi, io)) |
| @@ -1357,26 +1365,33 @@ static void fsi_dma_do_work(struct work_struct *work) | |||
| 1357 | runtime = io->substream->runtime; | 1365 | runtime = io->substream->runtime; |
| 1358 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1366 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
| 1359 | len = samples_to_bytes(runtime, io->period_samples); | 1367 | len = samples_to_bytes(runtime, io->period_samples); |
| 1360 | buf = fsi_dma_get_area(io); | ||
| 1361 | 1368 | ||
| 1362 | dma_sync_single_for_device(dai->dev, buf, len, dir); | 1369 | for (i = 0; i < io->loop_cnt; i++) { |
| 1370 | buf = fsi_dma_get_area(io, io->additional_pos); | ||
| 1363 | 1371 | ||
| 1364 | desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, | 1372 | dma_sync_single_for_device(dai->dev, buf, len, dir); |
| 1365 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
| 1366 | if (!desc) { | ||
| 1367 | dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); | ||
| 1368 | return; | ||
| 1369 | } | ||
| 1370 | 1373 | ||
| 1371 | desc->callback = fsi_dma_complete; | 1374 | desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, |
| 1372 | desc->callback_param = io; | 1375 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
| 1376 | if (!desc) { | ||
| 1377 | dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); | ||
| 1378 | return; | ||
| 1379 | } | ||
| 1373 | 1380 | ||
| 1374 | if (dmaengine_submit(desc) < 0) { | 1381 | desc->callback = fsi_dma_complete; |
| 1375 | dev_err(dai->dev, "tx_submit() fail\n"); | 1382 | desc->callback_param = io; |
| 1376 | return; | 1383 | |
| 1384 | if (dmaengine_submit(desc) < 0) { | ||
| 1385 | dev_err(dai->dev, "tx_submit() fail\n"); | ||
| 1386 | return; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | dma_async_issue_pending(io->chan); | ||
| 1390 | |||
| 1391 | io->additional_pos = 1; | ||
| 1377 | } | 1392 | } |
| 1378 | 1393 | ||
| 1379 | dma_async_issue_pending(io->chan); | 1394 | io->loop_cnt = 1; |
| 1380 | 1395 | ||
| 1381 | /* | 1396 | /* |
| 1382 | * FIXME | 1397 | * FIXME |
