diff options
Diffstat (limited to 'sound/soc/sh/fsi.c')
-rw-r--r-- | sound/soc/sh/fsi.c | 271 |
1 files changed, 130 insertions, 141 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 44123248b630..9c49c11c43ce 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/clk.h> | 20 | #include <linux/pm_runtime.h> |
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | #include <sound/core.h> | 22 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
@@ -26,8 +26,6 @@ | |||
26 | #include <sound/pcm_params.h> | 26 | #include <sound/pcm_params.h> |
27 | #include <sound/sh_fsi.h> | 27 | #include <sound/sh_fsi.h> |
28 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
29 | #include <asm/dma.h> | ||
30 | #include <asm/dma-sh.h> | ||
31 | 29 | ||
32 | #define DO_FMT 0x0000 | 30 | #define DO_FMT 0x0000 |
33 | #define DOFF_CTL 0x0004 | 31 | #define DOFF_CTL 0x0004 |
@@ -97,7 +95,6 @@ struct fsi_priv { | |||
97 | 95 | ||
98 | int fifo_max; | 96 | int fifo_max; |
99 | int chan; | 97 | int chan; |
100 | int dma_chan; | ||
101 | 98 | ||
102 | int byte_offset; | 99 | int byte_offset; |
103 | int period_len; | 100 | int period_len; |
@@ -108,7 +105,6 @@ struct fsi_priv { | |||
108 | struct fsi_master { | 105 | struct fsi_master { |
109 | void __iomem *base; | 106 | void __iomem *base; |
110 | int irq; | 107 | int irq; |
111 | struct clk *clk; | ||
112 | struct fsi_priv fsia; | 108 | struct fsi_priv fsia; |
113 | struct fsi_priv fsib; | 109 | struct fsi_priv fsib; |
114 | struct sh_fsi_platform_info *info; | 110 | struct sh_fsi_platform_info *info; |
@@ -308,62 +304,6 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) | |||
308 | return residue; | 304 | return residue; |
309 | } | 305 | } |
310 | 306 | ||
311 | static int fsi_get_residue(struct fsi_priv *fsi, int is_play) | ||
312 | { | ||
313 | int residue; | ||
314 | int width; | ||
315 | struct snd_pcm_runtime *runtime; | ||
316 | |||
317 | runtime = fsi->substream->runtime; | ||
318 | |||
319 | /* get 1 channel data width */ | ||
320 | width = frames_to_bytes(runtime, 1) / fsi->chan; | ||
321 | |||
322 | if (2 == width) | ||
323 | residue = fsi_get_fifo_residue(fsi, is_play); | ||
324 | else | ||
325 | residue = get_dma_residue(fsi->dma_chan); | ||
326 | |||
327 | return residue; | ||
328 | } | ||
329 | |||
330 | /************************************************************************ | ||
331 | |||
332 | |||
333 | basic dma function | ||
334 | |||
335 | |||
336 | ************************************************************************/ | ||
337 | #define PORTA_DMA 0 | ||
338 | #define PORTB_DMA 1 | ||
339 | |||
340 | static int fsi_get_dma_chan(void) | ||
341 | { | ||
342 | if (0 != request_dma(PORTA_DMA, "fsia")) | ||
343 | return -EIO; | ||
344 | |||
345 | if (0 != request_dma(PORTB_DMA, "fsib")) { | ||
346 | free_dma(PORTA_DMA); | ||
347 | return -EIO; | ||
348 | } | ||
349 | |||
350 | master->fsia.dma_chan = PORTA_DMA; | ||
351 | master->fsib.dma_chan = PORTB_DMA; | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static void fsi_free_dma_chan(void) | ||
357 | { | ||
358 | dma_wait_for_completion(PORTA_DMA); | ||
359 | dma_wait_for_completion(PORTB_DMA); | ||
360 | free_dma(PORTA_DMA); | ||
361 | free_dma(PORTB_DMA); | ||
362 | |||
363 | master->fsia.dma_chan = -1; | ||
364 | master->fsib.dma_chan = -1; | ||
365 | } | ||
366 | |||
367 | /************************************************************************ | 307 | /************************************************************************ |
368 | 308 | ||
369 | 309 | ||
@@ -435,44 +375,6 @@ static void fsi_soft_all_reset(void) | |||
435 | mdelay(10); | 375 | mdelay(10); |
436 | } | 376 | } |
437 | 377 | ||
438 | static void fsi_16data_push(struct fsi_priv *fsi, | ||
439 | struct snd_pcm_runtime *runtime, | ||
440 | int send) | ||
441 | { | ||
442 | u16 *dma_start; | ||
443 | u32 snd; | ||
444 | int i; | ||
445 | |||
446 | /* get dma start position for FSI */ | ||
447 | dma_start = (u16 *)runtime->dma_area; | ||
448 | dma_start += fsi->byte_offset / 2; | ||
449 | |||
450 | /* | ||
451 | * soft dma | ||
452 | * FSI can not use DMA when 16bpp | ||
453 | */ | ||
454 | for (i = 0; i < send; i++) { | ||
455 | snd = (u32)dma_start[i]; | ||
456 | fsi_reg_write(fsi, DODT, snd << 8); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static void fsi_32data_push(struct fsi_priv *fsi, | ||
461 | struct snd_pcm_runtime *runtime, | ||
462 | int send) | ||
463 | { | ||
464 | u32 *dma_start; | ||
465 | |||
466 | /* get dma start position for FSI */ | ||
467 | dma_start = (u32 *)runtime->dma_area; | ||
468 | dma_start += fsi->byte_offset / 4; | ||
469 | |||
470 | dma_wait_for_completion(fsi->dma_chan); | ||
471 | dma_configure_channel(fsi->dma_chan, (SM_INC|0x400|TS_32|TM_BUR)); | ||
472 | dma_write(fsi->dma_chan, (u32)dma_start, | ||
473 | (u32)(fsi->base + DODT), send * 4); | ||
474 | } | ||
475 | |||
476 | /* playback interrupt */ | 378 | /* playback interrupt */ |
477 | static int fsi_data_push(struct fsi_priv *fsi) | 379 | static int fsi_data_push(struct fsi_priv *fsi) |
478 | { | 380 | { |
@@ -481,6 +383,8 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
481 | int send; | 383 | int send; |
482 | int fifo_free; | 384 | int fifo_free; |
483 | int width; | 385 | int width; |
386 | u8 *start; | ||
387 | int i; | ||
484 | 388 | ||
485 | if (!fsi || | 389 | if (!fsi || |
486 | !fsi->substream || | 390 | !fsi->substream || |
@@ -515,12 +419,22 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
515 | if (fifo_free < send) | 419 | if (fifo_free < send) |
516 | send = fifo_free; | 420 | send = fifo_free; |
517 | 421 | ||
518 | if (2 == width) | 422 | start = runtime->dma_area; |
519 | fsi_16data_push(fsi, runtime, send); | 423 | start += fsi->byte_offset; |
520 | else if (4 == width) | 424 | |
521 | fsi_32data_push(fsi, runtime, send); | 425 | switch (width) { |
522 | else | 426 | case 2: |
427 | for (i = 0; i < send; i++) | ||
428 | fsi_reg_write(fsi, DODT, | ||
429 | ((u32)*((u16 *)start + i) << 8)); | ||
430 | break; | ||
431 | case 4: | ||
432 | for (i = 0; i < send; i++) | ||
433 | fsi_reg_write(fsi, DODT, *((u32 *)start + i)); | ||
434 | break; | ||
435 | default: | ||
523 | return -EINVAL; | 436 | return -EINVAL; |
437 | } | ||
524 | 438 | ||
525 | fsi->byte_offset += send * width; | 439 | fsi->byte_offset += send * width; |
526 | 440 | ||
@@ -532,6 +446,75 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
532 | return 0; | 446 | return 0; |
533 | } | 447 | } |
534 | 448 | ||
449 | static int fsi_data_pop(struct fsi_priv *fsi) | ||
450 | { | ||
451 | struct snd_pcm_runtime *runtime; | ||
452 | struct snd_pcm_substream *substream = NULL; | ||
453 | int free; | ||
454 | int fifo_fill; | ||
455 | int width; | ||
456 | u8 *start; | ||
457 | int i; | ||
458 | |||
459 | if (!fsi || | ||
460 | !fsi->substream || | ||
461 | !fsi->substream->runtime) | ||
462 | return -EINVAL; | ||
463 | |||
464 | runtime = fsi->substream->runtime; | ||
465 | |||
466 | /* FSI FIFO has limit. | ||
467 | * So, this driver can not send periods data at a time | ||
468 | */ | ||
469 | if (fsi->byte_offset >= | ||
470 | fsi->period_len * (fsi->periods + 1)) { | ||
471 | |||
472 | substream = fsi->substream; | ||
473 | fsi->periods = (fsi->periods + 1) % runtime->periods; | ||
474 | |||
475 | if (0 == fsi->periods) | ||
476 | fsi->byte_offset = 0; | ||
477 | } | ||
478 | |||
479 | /* get 1 channel data width */ | ||
480 | width = frames_to_bytes(runtime, 1) / fsi->chan; | ||
481 | |||
482 | /* get free space for alsa */ | ||
483 | free = (fsi->buffer_len - fsi->byte_offset) / width; | ||
484 | |||
485 | /* get recv size */ | ||
486 | fifo_fill = fsi_get_fifo_residue(fsi, 0); | ||
487 | |||
488 | if (free < fifo_fill) | ||
489 | fifo_fill = free; | ||
490 | |||
491 | start = runtime->dma_area; | ||
492 | start += fsi->byte_offset; | ||
493 | |||
494 | switch (width) { | ||
495 | case 2: | ||
496 | for (i = 0; i < fifo_fill; i++) | ||
497 | *((u16 *)start + i) = | ||
498 | (u16)(fsi_reg_read(fsi, DIDT) >> 8); | ||
499 | break; | ||
500 | case 4: | ||
501 | for (i = 0; i < fifo_fill; i++) | ||
502 | *((u32 *)start + i) = fsi_reg_read(fsi, DIDT); | ||
503 | break; | ||
504 | default: | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | |||
508 | fsi->byte_offset += fifo_fill * width; | ||
509 | |||
510 | fsi_irq_enable(fsi, 0); | ||
511 | |||
512 | if (substream) | ||
513 | snd_pcm_period_elapsed(substream); | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | |||
535 | static irqreturn_t fsi_interrupt(int irq, void *data) | 518 | static irqreturn_t fsi_interrupt(int irq, void *data) |
536 | { | 519 | { |
537 | u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; | 520 | u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; |
@@ -545,6 +528,10 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
545 | fsi_data_push(&master->fsia); | 528 | fsi_data_push(&master->fsia); |
546 | if (int_st & INT_B_OUT) | 529 | if (int_st & INT_B_OUT) |
547 | fsi_data_push(&master->fsib); | 530 | fsi_data_push(&master->fsib); |
531 | if (int_st & INT_A_IN) | ||
532 | fsi_data_pop(&master->fsia); | ||
533 | if (int_st & INT_B_IN) | ||
534 | fsi_data_pop(&master->fsib); | ||
548 | 535 | ||
549 | fsi_master_write(INT_ST, 0x0000000); | 536 | fsi_master_write(INT_ST, 0x0000000); |
550 | 537 | ||
@@ -571,7 +558,7 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
571 | int is_master; | 558 | int is_master; |
572 | int ret = 0; | 559 | int ret = 0; |
573 | 560 | ||
574 | clk_enable(master->clk); | 561 | pm_runtime_get_sync(dai->dev); |
575 | 562 | ||
576 | /* CKG1 */ | 563 | /* CKG1 */ |
577 | data = is_play ? (1 << 0) : (1 << 4); | 564 | data = is_play ? (1 << 0) : (1 << 4); |
@@ -664,8 +651,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
664 | } | 651 | } |
665 | 652 | ||
666 | fsi_reg_write(fsi, reg, data); | 653 | fsi_reg_write(fsi, reg, data); |
667 | dev_dbg(dai->dev, "use %s format (%d channel) use %d DMAC\n", | ||
668 | msg, fsi->chan, fsi->dma_chan); | ||
669 | 654 | ||
670 | /* | 655 | /* |
671 | * clear clk reset if master mode | 656 | * clear clk reset if master mode |
@@ -688,7 +673,7 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
688 | fsi_irq_disable(fsi, is_play); | 673 | fsi_irq_disable(fsi, is_play); |
689 | fsi_clk_ctrl(fsi, 0); | 674 | fsi_clk_ctrl(fsi, 0); |
690 | 675 | ||
691 | clk_disable(master->clk); | 676 | pm_runtime_put_sync(dai->dev); |
692 | } | 677 | } |
693 | 678 | ||
694 | static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | 679 | static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
@@ -699,16 +684,12 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
699 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 684 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
700 | int ret = 0; | 685 | int ret = 0; |
701 | 686 | ||
702 | /* capture not supported */ | ||
703 | if (!is_play) | ||
704 | return -ENODEV; | ||
705 | |||
706 | switch (cmd) { | 687 | switch (cmd) { |
707 | case SNDRV_PCM_TRIGGER_START: | 688 | case SNDRV_PCM_TRIGGER_START: |
708 | fsi_stream_push(fsi, substream, | 689 | fsi_stream_push(fsi, substream, |
709 | frames_to_bytes(runtime, runtime->buffer_size), | 690 | frames_to_bytes(runtime, runtime->buffer_size), |
710 | frames_to_bytes(runtime, runtime->period_size)); | 691 | frames_to_bytes(runtime, runtime->period_size)); |
711 | ret = fsi_data_push(fsi); | 692 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); |
712 | break; | 693 | break; |
713 | case SNDRV_PCM_TRIGGER_STOP: | 694 | case SNDRV_PCM_TRIGGER_STOP: |
714 | fsi_irq_disable(fsi, is_play); | 695 | fsi_irq_disable(fsi, is_play); |
@@ -780,10 +761,9 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) | |||
780 | { | 761 | { |
781 | struct snd_pcm_runtime *runtime = substream->runtime; | 762 | struct snd_pcm_runtime *runtime = substream->runtime; |
782 | struct fsi_priv *fsi = fsi_get(substream); | 763 | struct fsi_priv *fsi = fsi_get(substream); |
783 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
784 | long location; | 764 | long location; |
785 | 765 | ||
786 | location = (fsi->byte_offset - 1) - fsi_get_residue(fsi, is_play); | 766 | location = (fsi->byte_offset - 1); |
787 | if (location < 0) | 767 | if (location < 0) |
788 | location = 0; | 768 | location = 0; |
789 | 769 | ||
@@ -845,7 +825,12 @@ struct snd_soc_dai fsi_soc_dai[] = { | |||
845 | .channels_min = 1, | 825 | .channels_min = 1, |
846 | .channels_max = 8, | 826 | .channels_max = 8, |
847 | }, | 827 | }, |
848 | /* capture not supported */ | 828 | .capture = { |
829 | .rates = FSI_RATES, | ||
830 | .formats = FSI_FMTS, | ||
831 | .channels_min = 1, | ||
832 | .channels_max = 8, | ||
833 | }, | ||
849 | .ops = &fsi_dai_ops, | 834 | .ops = &fsi_dai_ops, |
850 | }, | 835 | }, |
851 | { | 836 | { |
@@ -857,7 +842,12 @@ struct snd_soc_dai fsi_soc_dai[] = { | |||
857 | .channels_min = 1, | 842 | .channels_min = 1, |
858 | .channels_max = 8, | 843 | .channels_max = 8, |
859 | }, | 844 | }, |
860 | /* capture not supported */ | 845 | .capture = { |
846 | .rates = FSI_RATES, | ||
847 | .formats = FSI_FMTS, | ||
848 | .channels_min = 1, | ||
849 | .channels_max = 8, | ||
850 | }, | ||
861 | .ops = &fsi_dai_ops, | 851 | .ops = &fsi_dai_ops, |
862 | }, | 852 | }, |
863 | }; | 853 | }; |
@@ -881,7 +871,6 @@ EXPORT_SYMBOL_GPL(fsi_soc_platform); | |||
881 | static int fsi_probe(struct platform_device *pdev) | 871 | static int fsi_probe(struct platform_device *pdev) |
882 | { | 872 | { |
883 | struct resource *res; | 873 | struct resource *res; |
884 | char clk_name[8]; | ||
885 | unsigned int irq; | 874 | unsigned int irq; |
886 | int ret; | 875 | int ret; |
887 | 876 | ||
@@ -912,23 +901,8 @@ static int fsi_probe(struct platform_device *pdev) | |||
912 | master->fsia.base = master->base; | 901 | master->fsia.base = master->base; |
913 | master->fsib.base = master->base + 0x40; | 902 | master->fsib.base = master->base + 0x40; |
914 | 903 | ||
915 | master->fsia.dma_chan = -1; | 904 | pm_runtime_enable(&pdev->dev); |
916 | master->fsib.dma_chan = -1; | 905 | pm_runtime_resume(&pdev->dev); |
917 | |||
918 | ret = fsi_get_dma_chan(); | ||
919 | if (ret < 0) { | ||
920 | dev_err(&pdev->dev, "cannot get dma api\n"); | ||
921 | goto exit_iounmap; | ||
922 | } | ||
923 | |||
924 | /* FSI is based on SPU mstp */ | ||
925 | snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id); | ||
926 | master->clk = clk_get(NULL, clk_name); | ||
927 | if (IS_ERR(master->clk)) { | ||
928 | dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name); | ||
929 | ret = -EIO; | ||
930 | goto exit_free_dma; | ||
931 | } | ||
932 | 906 | ||
933 | fsi_soc_dai[0].dev = &pdev->dev; | 907 | fsi_soc_dai[0].dev = &pdev->dev; |
934 | fsi_soc_dai[1].dev = &pdev->dev; | 908 | fsi_soc_dai[1].dev = &pdev->dev; |
@@ -938,7 +912,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
938 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); | 912 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); |
939 | if (ret) { | 913 | if (ret) { |
940 | dev_err(&pdev->dev, "irq request err\n"); | 914 | dev_err(&pdev->dev, "irq request err\n"); |
941 | goto exit_free_dma; | 915 | goto exit_iounmap; |
942 | } | 916 | } |
943 | 917 | ||
944 | ret = snd_soc_register_platform(&fsi_soc_platform); | 918 | ret = snd_soc_register_platform(&fsi_soc_platform); |
@@ -951,10 +925,9 @@ static int fsi_probe(struct platform_device *pdev) | |||
951 | 925 | ||
952 | exit_free_irq: | 926 | exit_free_irq: |
953 | free_irq(irq, master); | 927 | free_irq(irq, master); |
954 | exit_free_dma: | ||
955 | fsi_free_dma_chan(); | ||
956 | exit_iounmap: | 928 | exit_iounmap: |
957 | iounmap(master->base); | 929 | iounmap(master->base); |
930 | pm_runtime_disable(&pdev->dev); | ||
958 | exit_kfree: | 931 | exit_kfree: |
959 | kfree(master); | 932 | kfree(master); |
960 | master = NULL; | 933 | master = NULL; |
@@ -967,9 +940,7 @@ static int fsi_remove(struct platform_device *pdev) | |||
967 | snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); | 940 | snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); |
968 | snd_soc_unregister_platform(&fsi_soc_platform); | 941 | snd_soc_unregister_platform(&fsi_soc_platform); |
969 | 942 | ||
970 | clk_put(master->clk); | 943 | pm_runtime_disable(&pdev->dev); |
971 | |||
972 | fsi_free_dma_chan(); | ||
973 | 944 | ||
974 | free_irq(master->irq, master); | 945 | free_irq(master->irq, master); |
975 | 946 | ||
@@ -979,9 +950,27 @@ static int fsi_remove(struct platform_device *pdev) | |||
979 | return 0; | 950 | return 0; |
980 | } | 951 | } |
981 | 952 | ||
953 | static int fsi_runtime_nop(struct device *dev) | ||
954 | { | ||
955 | /* Runtime PM callback shared between ->runtime_suspend() | ||
956 | * and ->runtime_resume(). Simply returns success. | ||
957 | * | ||
958 | * This driver re-initializes all registers after | ||
959 | * pm_runtime_get_sync() anyway so there is no need | ||
960 | * to save and restore registers here. | ||
961 | */ | ||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | static struct dev_pm_ops fsi_pm_ops = { | ||
966 | .runtime_suspend = fsi_runtime_nop, | ||
967 | .runtime_resume = fsi_runtime_nop, | ||
968 | }; | ||
969 | |||
982 | static struct platform_driver fsi_driver = { | 970 | static struct platform_driver fsi_driver = { |
983 | .driver = { | 971 | .driver = { |
984 | .name = "sh_fsi", | 972 | .name = "sh_fsi", |
973 | .pm = &fsi_pm_ops, | ||
985 | }, | 974 | }, |
986 | .probe = fsi_probe, | 975 | .probe = fsi_probe, |
987 | .remove = fsi_remove, | 976 | .remove = fsi_remove, |