diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/sh/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/sh/fsi.c | 141 |
2 files changed, 20 insertions, 122 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 9154b4363db3..9e6976586554 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -23,7 +23,6 @@ config SND_SOC_SH4_SSI | |||
23 | config SND_SOC_SH4_FSI | 23 | config SND_SOC_SH4_FSI |
24 | tristate "SH4 FSI support" | 24 | tristate "SH4 FSI support" |
25 | depends on CPU_SUBTYPE_SH7724 | 25 | depends on CPU_SUBTYPE_SH7724 |
26 | select SH_DMA | ||
27 | help | 26 | help |
28 | This option enables FSI sound support | 27 | This option enables FSI sound support |
29 | 28 | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 44123248b630..9742a280ba15 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -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; |
@@ -308,62 +305,6 @@ static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) | |||
308 | return residue; | 305 | return residue; |
309 | } | 306 | } |
310 | 307 | ||
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 | /************************************************************************ | 308 | /************************************************************************ |
368 | 309 | ||
369 | 310 | ||
@@ -435,44 +376,6 @@ static void fsi_soft_all_reset(void) | |||
435 | mdelay(10); | 376 | mdelay(10); |
436 | } | 377 | } |
437 | 378 | ||
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 */ | 379 | /* playback interrupt */ |
477 | static int fsi_data_push(struct fsi_priv *fsi) | 380 | static int fsi_data_push(struct fsi_priv *fsi) |
478 | { | 381 | { |
@@ -481,6 +384,8 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
481 | int send; | 384 | int send; |
482 | int fifo_free; | 385 | int fifo_free; |
483 | int width; | 386 | int width; |
387 | u8 *start; | ||
388 | int i; | ||
484 | 389 | ||
485 | if (!fsi || | 390 | if (!fsi || |
486 | !fsi->substream || | 391 | !fsi->substream || |
@@ -515,12 +420,22 @@ static int fsi_data_push(struct fsi_priv *fsi) | |||
515 | if (fifo_free < send) | 420 | if (fifo_free < send) |
516 | send = fifo_free; | 421 | send = fifo_free; |
517 | 422 | ||
518 | if (2 == width) | 423 | start = runtime->dma_area; |
519 | fsi_16data_push(fsi, runtime, send); | 424 | start += fsi->byte_offset; |
520 | else if (4 == width) | 425 | |
521 | fsi_32data_push(fsi, runtime, send); | 426 | switch (width) { |
522 | else | 427 | case 2: |
428 | for (i = 0; i < send; i++) | ||
429 | fsi_reg_write(fsi, DODT, | ||
430 | ((u32)*((u16 *)start + i) << 8)); | ||
431 | break; | ||
432 | case 4: | ||
433 | for (i = 0; i < send; i++) | ||
434 | fsi_reg_write(fsi, DODT, *((u32 *)start + i)); | ||
435 | break; | ||
436 | default: | ||
523 | return -EINVAL; | 437 | return -EINVAL; |
438 | } | ||
524 | 439 | ||
525 | fsi->byte_offset += send * width; | 440 | fsi->byte_offset += send * width; |
526 | 441 | ||
@@ -664,8 +579,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
664 | } | 579 | } |
665 | 580 | ||
666 | fsi_reg_write(fsi, reg, data); | 581 | 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 | 582 | ||
670 | /* | 583 | /* |
671 | * clear clk reset if master mode | 584 | * clear clk reset if master mode |
@@ -780,10 +693,9 @@ static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) | |||
780 | { | 693 | { |
781 | struct snd_pcm_runtime *runtime = substream->runtime; | 694 | struct snd_pcm_runtime *runtime = substream->runtime; |
782 | struct fsi_priv *fsi = fsi_get(substream); | 695 | struct fsi_priv *fsi = fsi_get(substream); |
783 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
784 | long location; | 696 | long location; |
785 | 697 | ||
786 | location = (fsi->byte_offset - 1) - fsi_get_residue(fsi, is_play); | 698 | location = (fsi->byte_offset - 1); |
787 | if (location < 0) | 699 | if (location < 0) |
788 | location = 0; | 700 | location = 0; |
789 | 701 | ||
@@ -912,22 +824,13 @@ static int fsi_probe(struct platform_device *pdev) | |||
912 | master->fsia.base = master->base; | 824 | master->fsia.base = master->base; |
913 | master->fsib.base = master->base + 0x40; | 825 | master->fsib.base = master->base + 0x40; |
914 | 826 | ||
915 | master->fsia.dma_chan = -1; | ||
916 | master->fsib.dma_chan = -1; | ||
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 */ | 827 | /* FSI is based on SPU mstp */ |
925 | snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id); | 828 | snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id); |
926 | master->clk = clk_get(NULL, clk_name); | 829 | master->clk = clk_get(NULL, clk_name); |
927 | if (IS_ERR(master->clk)) { | 830 | if (IS_ERR(master->clk)) { |
928 | dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name); | 831 | dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name); |
929 | ret = -EIO; | 832 | ret = -EIO; |
930 | goto exit_free_dma; | 833 | goto exit_iounmap; |
931 | } | 834 | } |
932 | 835 | ||
933 | fsi_soc_dai[0].dev = &pdev->dev; | 836 | fsi_soc_dai[0].dev = &pdev->dev; |
@@ -938,7 +841,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
938 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); | 841 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); |
939 | if (ret) { | 842 | if (ret) { |
940 | dev_err(&pdev->dev, "irq request err\n"); | 843 | dev_err(&pdev->dev, "irq request err\n"); |
941 | goto exit_free_dma; | 844 | goto exit_iounmap; |
942 | } | 845 | } |
943 | 846 | ||
944 | ret = snd_soc_register_platform(&fsi_soc_platform); | 847 | ret = snd_soc_register_platform(&fsi_soc_platform); |
@@ -951,8 +854,6 @@ static int fsi_probe(struct platform_device *pdev) | |||
951 | 854 | ||
952 | exit_free_irq: | 855 | exit_free_irq: |
953 | free_irq(irq, master); | 856 | free_irq(irq, master); |
954 | exit_free_dma: | ||
955 | fsi_free_dma_chan(); | ||
956 | exit_iounmap: | 857 | exit_iounmap: |
957 | iounmap(master->base); | 858 | iounmap(master->base); |
958 | exit_kfree: | 859 | exit_kfree: |
@@ -969,8 +870,6 @@ static int fsi_remove(struct platform_device *pdev) | |||
969 | 870 | ||
970 | clk_put(master->clk); | 871 | clk_put(master->clk); |
971 | 872 | ||
972 | fsi_free_dma_chan(); | ||
973 | |||
974 | free_irq(master->irq, master); | 873 | free_irq(master->irq, master); |
975 | 874 | ||
976 | iounmap(master->base); | 875 | iounmap(master->base); |