diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2012-02-03 03:55:55 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-02-03 06:55:39 -0500 |
commit | 5e97313ac483f03a9af661aada356980fe310e0d (patch) | |
tree | 884c2d0140c581dcbf38c3ff4fc11abf7e11f7c1 /sound/soc/sh | |
parent | 7b1b3331e65e47b6abb32be0a3db46bcf423145a (diff) |
ASoC: fsi: add fsi_stream_handler and PIO handler
This patch adds struct fsi_stream_handler and defined fsi_pio_push/pop_handler.
these are controled by fsi_steam_xxx() function.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/sh')
-rw-r--r-- | sound/soc/sh/fsi.c | 133 |
1 files changed, 118 insertions, 15 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 24dbe165eda8..b02886ad6f87 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -159,18 +159,27 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena | |||
159 | * struct | 159 | * struct |
160 | */ | 160 | */ |
161 | 161 | ||
162 | struct fsi_stream_handler; | ||
162 | struct fsi_stream { | 163 | struct fsi_stream { |
163 | struct snd_pcm_substream *substream; | ||
164 | 164 | ||
165 | /* | ||
166 | * these are initialized by fsi_stream_init() | ||
167 | */ | ||
168 | struct snd_pcm_substream *substream; | ||
165 | int fifo_sample_capa; /* sample capacity of FSI FIFO */ | 169 | int fifo_sample_capa; /* sample capacity of FSI FIFO */ |
166 | int buff_sample_capa; /* sample capacity of ALSA buffer */ | 170 | int buff_sample_capa; /* sample capacity of ALSA buffer */ |
167 | int buff_sample_pos; /* sample position of ALSA buffer */ | 171 | int buff_sample_pos; /* sample position of ALSA buffer */ |
168 | int period_samples; /* sample number / 1 period */ | 172 | int period_samples; /* sample number / 1 period */ |
169 | int period_pos; /* current period position */ | 173 | int period_pos; /* current period position */ |
170 | int sample_width; /* sample width */ | 174 | int sample_width; /* sample width */ |
171 | |||
172 | int uerr_num; | 175 | int uerr_num; |
173 | int oerr_num; | 176 | int oerr_num; |
177 | |||
178 | /* | ||
179 | * thse are initialized by fsi_handler_init() | ||
180 | */ | ||
181 | struct fsi_stream_handler *handler; | ||
182 | struct fsi_priv *priv; | ||
174 | }; | 183 | }; |
175 | 184 | ||
176 | struct fsi_priv { | 185 | struct fsi_priv { |
@@ -190,6 +199,16 @@ struct fsi_priv { | |||
190 | long rate; | 199 | long rate; |
191 | }; | 200 | }; |
192 | 201 | ||
202 | struct fsi_stream_handler { | ||
203 | int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
204 | int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
205 | int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); | ||
206 | }; | ||
207 | #define fsi_stream_handler_call(io, func, args...) \ | ||
208 | (!(io) ? -ENODEV : \ | ||
209 | !((io)->handler->func) ? 0 : \ | ||
210 | (io)->handler->func(args)) | ||
211 | |||
193 | struct fsi_core { | 212 | struct fsi_core { |
194 | int ver; | 213 | int ver; |
195 | 214 | ||
@@ -435,6 +454,11 @@ static int fsi_stream_is_working(struct fsi_priv *fsi, | |||
435 | return ret; | 454 | return ret; |
436 | } | 455 | } |
437 | 456 | ||
457 | static struct fsi_priv *fsi_stream_to_priv(struct fsi_stream *io) | ||
458 | { | ||
459 | return io->priv; | ||
460 | } | ||
461 | |||
438 | static void fsi_stream_init(struct fsi_priv *fsi, | 462 | static void fsi_stream_init(struct fsi_priv *fsi, |
439 | int is_play, | 463 | int is_play, |
440 | struct snd_pcm_substream *substream) | 464 | struct snd_pcm_substream *substream) |
@@ -482,6 +506,53 @@ static void fsi_stream_quit(struct fsi_priv *fsi, int is_play) | |||
482 | spin_unlock_irqrestore(&master->lock, flags); | 506 | spin_unlock_irqrestore(&master->lock, flags); |
483 | } | 507 | } |
484 | 508 | ||
509 | static int fsi_stream_transfer(struct fsi_stream *io) | ||
510 | { | ||
511 | struct fsi_priv *fsi = fsi_stream_to_priv(io); | ||
512 | if (!fsi) | ||
513 | return -EIO; | ||
514 | |||
515 | return fsi_stream_handler_call(io, transfer, fsi, io); | ||
516 | } | ||
517 | |||
518 | static int fsi_stream_probe(struct fsi_priv *fsi) | ||
519 | { | ||
520 | struct fsi_stream *io; | ||
521 | int ret1, ret2; | ||
522 | |||
523 | io = &fsi->playback; | ||
524 | ret1 = fsi_stream_handler_call(io, probe, fsi, io); | ||
525 | |||
526 | io = &fsi->capture; | ||
527 | ret2 = fsi_stream_handler_call(io, probe, fsi, io); | ||
528 | |||
529 | if (ret1 < 0) | ||
530 | return ret1; | ||
531 | if (ret2 < 0) | ||
532 | return ret2; | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int fsi_stream_remove(struct fsi_priv *fsi) | ||
538 | { | ||
539 | struct fsi_stream *io; | ||
540 | int ret1, ret2; | ||
541 | |||
542 | io = &fsi->playback; | ||
543 | ret1 = fsi_stream_handler_call(io, remove, fsi, io); | ||
544 | |||
545 | io = &fsi->capture; | ||
546 | ret2 = fsi_stream_handler_call(io, remove, fsi, io); | ||
547 | |||
548 | if (ret1 < 0) | ||
549 | return ret1; | ||
550 | if (ret2 < 0) | ||
551 | return ret2; | ||
552 | |||
553 | return 0; | ||
554 | } | ||
555 | |||
485 | /* | 556 | /* |
486 | * pio function | 557 | * pio function |
487 | */ | 558 | */ |
@@ -743,13 +814,11 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, struct fsi_stream *io, | |||
743 | return 0; | 814 | return 0; |
744 | } | 815 | } |
745 | 816 | ||
746 | static int fsi_data_pop(struct fsi_priv *fsi) | 817 | static int fsi_pio_pop(struct fsi_priv *fsi, struct fsi_stream *io) |
747 | { | 818 | { |
748 | int is_play = 0; | ||
749 | int sample_residues; /* samples in FSI fifo */ | 819 | int sample_residues; /* samples in FSI fifo */ |
750 | int sample_space; /* ALSA free samples space */ | 820 | int sample_space; /* ALSA free samples space */ |
751 | int samples; | 821 | int samples; |
752 | struct fsi_stream *io = fsi_stream_get(fsi, is_play); | ||
753 | 822 | ||
754 | sample_residues = fsi_get_current_fifo_samples(fsi, io); | 823 | sample_residues = fsi_get_current_fifo_samples(fsi, io); |
755 | sample_space = io->buff_sample_capa - io->buff_sample_pos; | 824 | sample_space = io->buff_sample_capa - io->buff_sample_pos; |
@@ -762,13 +831,11 @@ static int fsi_data_pop(struct fsi_priv *fsi) | |||
762 | samples); | 831 | samples); |
763 | } | 832 | } |
764 | 833 | ||
765 | static int fsi_data_push(struct fsi_priv *fsi) | 834 | static int fsi_pio_push(struct fsi_priv *fsi, struct fsi_stream *io) |
766 | { | 835 | { |
767 | int is_play = 1; | ||
768 | int sample_residues; /* ALSA residue samples */ | 836 | int sample_residues; /* ALSA residue samples */ |
769 | int sample_space; /* FSI fifo free samples space */ | 837 | int sample_space; /* FSI fifo free samples space */ |
770 | int samples; | 838 | int samples; |
771 | struct fsi_stream *io = fsi_stream_get(fsi, is_play); | ||
772 | 839 | ||
773 | sample_residues = io->buff_sample_capa - io->buff_sample_pos; | 840 | sample_residues = io->buff_sample_capa - io->buff_sample_pos; |
774 | sample_space = io->fifo_sample_capa - | 841 | sample_space = io->fifo_sample_capa - |
@@ -782,6 +849,14 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
782 | samples); | 849 | samples); |
783 | } | 850 | } |
784 | 851 | ||
852 | static struct fsi_stream_handler fsi_pio_push_handler = { | ||
853 | .transfer = fsi_pio_push, | ||
854 | }; | ||
855 | |||
856 | static struct fsi_stream_handler fsi_pio_pop_handler = { | ||
857 | .transfer = fsi_pio_pop, | ||
858 | }; | ||
859 | |||
785 | static irqreturn_t fsi_interrupt(int irq, void *data) | 860 | static irqreturn_t fsi_interrupt(int irq, void *data) |
786 | { | 861 | { |
787 | struct fsi_master *master = data; | 862 | struct fsi_master *master = data; |
@@ -792,13 +867,13 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
792 | fsi_master_mask_set(master, SOFT_RST, IR, IR); | 867 | fsi_master_mask_set(master, SOFT_RST, IR, IR); |
793 | 868 | ||
794 | if (int_st & AB_IO(1, AO_SHIFT)) | 869 | if (int_st & AB_IO(1, AO_SHIFT)) |
795 | fsi_data_push(&master->fsia); | 870 | fsi_stream_transfer(&master->fsia.playback); |
796 | if (int_st & AB_IO(1, BO_SHIFT)) | 871 | if (int_st & AB_IO(1, BO_SHIFT)) |
797 | fsi_data_push(&master->fsib); | 872 | fsi_stream_transfer(&master->fsib.playback); |
798 | if (int_st & AB_IO(1, AI_SHIFT)) | 873 | if (int_st & AB_IO(1, AI_SHIFT)) |
799 | fsi_data_pop(&master->fsia); | 874 | fsi_stream_transfer(&master->fsia.capture); |
800 | if (int_st & AB_IO(1, BI_SHIFT)) | 875 | if (int_st & AB_IO(1, BI_SHIFT)) |
801 | fsi_data_pop(&master->fsib); | 876 | fsi_stream_transfer(&master->fsib.capture); |
802 | 877 | ||
803 | fsi_count_fifo_err(&master->fsia); | 878 | fsi_count_fifo_err(&master->fsia); |
804 | fsi_count_fifo_err(&master->fsib); | 879 | fsi_count_fifo_err(&master->fsib); |
@@ -955,14 +1030,16 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
955 | struct snd_soc_dai *dai) | 1030 | struct snd_soc_dai *dai) |
956 | { | 1031 | { |
957 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1032 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1033 | struct fsi_stream *io = fsi_stream_get(fsi, fsi_is_play(substream)); | ||
958 | int is_play = fsi_is_play(substream); | 1034 | int is_play = fsi_is_play(substream); |
959 | int ret = 0; | 1035 | int ret = 0; |
960 | 1036 | ||
961 | switch (cmd) { | 1037 | switch (cmd) { |
962 | case SNDRV_PCM_TRIGGER_START: | 1038 | case SNDRV_PCM_TRIGGER_START: |
963 | fsi_stream_init(fsi, is_play, substream); | 1039 | fsi_stream_init(fsi, is_play, substream); |
964 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); | 1040 | ret = fsi_stream_transfer(io); |
965 | fsi_port_start(fsi, is_play); | 1041 | if (0 == ret) |
1042 | fsi_port_start(fsi, is_play); | ||
966 | break; | 1043 | break; |
967 | case SNDRV_PCM_TRIGGER_STOP: | 1044 | case SNDRV_PCM_TRIGGER_STOP: |
968 | fsi_port_stop(fsi, is_play); | 1045 | fsi_port_stop(fsi, is_play); |
@@ -1224,6 +1301,13 @@ static struct snd_soc_platform_driver fsi_soc_platform = { | |||
1224 | /* | 1301 | /* |
1225 | * platform function | 1302 | * platform function |
1226 | */ | 1303 | */ |
1304 | static void fsi_handler_init(struct fsi_priv *fsi) | ||
1305 | { | ||
1306 | fsi->playback.handler = &fsi_pio_push_handler; /* default PIO */ | ||
1307 | fsi->playback.priv = fsi; | ||
1308 | fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ | ||
1309 | fsi->capture.priv = fsi; | ||
1310 | } | ||
1227 | 1311 | ||
1228 | static int fsi_probe(struct platform_device *pdev) | 1312 | static int fsi_probe(struct platform_device *pdev) |
1229 | { | 1313 | { |
@@ -1270,10 +1354,22 @@ static int fsi_probe(struct platform_device *pdev) | |||
1270 | /* FSI A setting */ | 1354 | /* FSI A setting */ |
1271 | master->fsia.base = master->base; | 1355 | master->fsia.base = master->base; |
1272 | master->fsia.master = master; | 1356 | master->fsia.master = master; |
1357 | fsi_handler_init(&master->fsia); | ||
1358 | ret = fsi_stream_probe(&master->fsia); | ||
1359 | if (ret < 0) { | ||
1360 | dev_err(&pdev->dev, "FSIA stream probe failed\n"); | ||
1361 | goto exit_iounmap; | ||
1362 | } | ||
1273 | 1363 | ||
1274 | /* FSI B setting */ | 1364 | /* FSI B setting */ |
1275 | master->fsib.base = master->base + 0x40; | 1365 | master->fsib.base = master->base + 0x40; |
1276 | master->fsib.master = master; | 1366 | master->fsib.master = master; |
1367 | fsi_handler_init(&master->fsib); | ||
1368 | ret = fsi_stream_probe(&master->fsib); | ||
1369 | if (ret < 0) { | ||
1370 | dev_err(&pdev->dev, "FSIB stream probe failed\n"); | ||
1371 | goto exit_fsia; | ||
1372 | } | ||
1277 | 1373 | ||
1278 | pm_runtime_enable(&pdev->dev); | 1374 | pm_runtime_enable(&pdev->dev); |
1279 | dev_set_drvdata(&pdev->dev, master); | 1375 | dev_set_drvdata(&pdev->dev, master); |
@@ -1282,7 +1378,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
1282 | id_entry->name, master); | 1378 | id_entry->name, master); |
1283 | if (ret) { | 1379 | if (ret) { |
1284 | dev_err(&pdev->dev, "irq request err\n"); | 1380 | dev_err(&pdev->dev, "irq request err\n"); |
1285 | goto exit_iounmap; | 1381 | goto exit_fsib; |
1286 | } | 1382 | } |
1287 | 1383 | ||
1288 | ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); | 1384 | ret = snd_soc_register_platform(&pdev->dev, &fsi_soc_platform); |
@@ -1304,6 +1400,10 @@ exit_snd_soc: | |||
1304 | snd_soc_unregister_platform(&pdev->dev); | 1400 | snd_soc_unregister_platform(&pdev->dev); |
1305 | exit_free_irq: | 1401 | exit_free_irq: |
1306 | free_irq(irq, master); | 1402 | free_irq(irq, master); |
1403 | exit_fsib: | ||
1404 | fsi_stream_remove(&master->fsib); | ||
1405 | exit_fsia: | ||
1406 | fsi_stream_remove(&master->fsia); | ||
1307 | exit_iounmap: | 1407 | exit_iounmap: |
1308 | iounmap(master->base); | 1408 | iounmap(master->base); |
1309 | pm_runtime_disable(&pdev->dev); | 1409 | pm_runtime_disable(&pdev->dev); |
@@ -1326,6 +1426,9 @@ static int fsi_remove(struct platform_device *pdev) | |||
1326 | snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); | 1426 | snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai)); |
1327 | snd_soc_unregister_platform(&pdev->dev); | 1427 | snd_soc_unregister_platform(&pdev->dev); |
1328 | 1428 | ||
1429 | fsi_stream_remove(&master->fsia); | ||
1430 | fsi_stream_remove(&master->fsib); | ||
1431 | |||
1329 | iounmap(master->base); | 1432 | iounmap(master->base); |
1330 | kfree(master); | 1433 | kfree(master); |
1331 | 1434 | ||