diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-08-20 12:19:27 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-08-20 12:19:27 -0400 |
commit | bf557a50f59fc62dfd89fa5bf08c6f5d96fb2f45 (patch) | |
tree | 81a2cd45044970ccceec9ae4e1547e8f5dee850d /sound/soc/fsl | |
parent | 26b01ccdc8ded270a1a65721b99acacf0c44e088 (diff) | |
parent | 3fabe089ad8b8f238bc9de3e7586ae8d2a81f57c (diff) |
Merge branch 'for-2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc-2.6 into for-2.6.37
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/fsl_dma.c | 67 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 25 |
2 files changed, 73 insertions, 19 deletions
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 5a6f56d63756..f039e8db0765 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -60,6 +60,7 @@ struct dma_object { | |||
60 | struct snd_soc_platform_driver dai; | 60 | struct snd_soc_platform_driver dai; |
61 | dma_addr_t ssi_stx_phys; | 61 | dma_addr_t ssi_stx_phys; |
62 | dma_addr_t ssi_srx_phys; | 62 | dma_addr_t ssi_srx_phys; |
63 | unsigned int ssi_fifo_depth; | ||
63 | struct ccsr_dma_channel __iomem *channel; | 64 | struct ccsr_dma_channel __iomem *channel; |
64 | unsigned int irq; | 65 | unsigned int irq; |
65 | bool assigned; | 66 | bool assigned; |
@@ -99,6 +100,7 @@ struct fsl_dma_private { | |||
99 | unsigned int irq; | 100 | unsigned int irq; |
100 | struct snd_pcm_substream *substream; | 101 | struct snd_pcm_substream *substream; |
101 | dma_addr_t ssi_sxx_phys; | 102 | dma_addr_t ssi_sxx_phys; |
103 | unsigned int ssi_fifo_depth; | ||
102 | dma_addr_t ld_buf_phys; | 104 | dma_addr_t ld_buf_phys; |
103 | unsigned int current_link; | 105 | unsigned int current_link; |
104 | dma_addr_t dma_buf_phys; | 106 | dma_addr_t dma_buf_phys; |
@@ -439,6 +441,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
439 | else | 441 | else |
440 | dma_private->ssi_sxx_phys = dma->ssi_srx_phys; | 442 | dma_private->ssi_sxx_phys = dma->ssi_srx_phys; |
441 | 443 | ||
444 | dma_private->ssi_fifo_depth = dma->ssi_fifo_depth; | ||
442 | dma_private->dma_channel = dma->channel; | 445 | dma_private->dma_channel = dma->channel; |
443 | dma_private->irq = dma->irq; | 446 | dma_private->irq = dma->irq; |
444 | dma_private->substream = substream; | 447 | dma_private->substream = substream; |
@@ -552,11 +555,11 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
552 | struct device *dev = rtd->platform->dev; | 555 | struct device *dev = rtd->platform->dev; |
553 | 556 | ||
554 | /* Number of bits per sample */ | 557 | /* Number of bits per sample */ |
555 | unsigned int sample_size = | 558 | unsigned int sample_bits = |
556 | snd_pcm_format_physical_width(params_format(hw_params)); | 559 | snd_pcm_format_physical_width(params_format(hw_params)); |
557 | 560 | ||
558 | /* Number of bytes per frame */ | 561 | /* Number of bytes per frame */ |
559 | unsigned int frame_size = 2 * (sample_size / 8); | 562 | unsigned int sample_bytes = sample_bits / 8; |
560 | 563 | ||
561 | /* Bus address of SSI STX register */ | 564 | /* Bus address of SSI STX register */ |
562 | dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys; | 565 | dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys; |
@@ -596,7 +599,7 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
596 | * that offset here. While we're at it, also tell the DMA controller | 599 | * that offset here. While we're at it, also tell the DMA controller |
597 | * how much data to transfer per sample. | 600 | * how much data to transfer per sample. |
598 | */ | 601 | */ |
599 | switch (sample_size) { | 602 | switch (sample_bits) { |
600 | case 8: | 603 | case 8: |
601 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; | 604 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; |
602 | ssi_sxx_phys += 3; | 605 | ssi_sxx_phys += 3; |
@@ -610,22 +613,42 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
610 | break; | 613 | break; |
611 | default: | 614 | default: |
612 | /* We should never get here */ | 615 | /* We should never get here */ |
613 | dev_err(dev, "unsupported sample size %u\n", sample_size); | 616 | dev_err(dev, "unsupported sample size %u\n", sample_bits); |
614 | return -EINVAL; | 617 | return -EINVAL; |
615 | } | 618 | } |
616 | 619 | ||
617 | /* | 620 | /* |
618 | * BWC should always be a multiple of the frame size. BWC determines | 621 | * BWC determines how many bytes are sent/received before the DMA |
619 | * how many bytes are sent/received before the DMA controller checks the | 622 | * controller checks the SSI to see if it needs to stop. BWC should |
620 | * SSI to see if it needs to stop. For playback, the transmit FIFO can | 623 | * always be a multiple of the frame size, so that we always transmit |
621 | * hold three frames, so we want to send two frames at a time. For | 624 | * whole frames. Each frame occupies two slots in the FIFO. The |
622 | * capture, the receive FIFO is triggered when it contains one frame, so | 625 | * parameter for CCSR_DMA_MR_BWC() is rounded down the next power of two |
623 | * we want to receive one frame at a time. | 626 | * (MR[BWC] can only represent even powers of two). |
627 | * | ||
628 | * To simplify the process, we set BWC to the largest value that is | ||
629 | * less than or equal to the FIFO watermark. For playback, this ensures | ||
630 | * that we transfer the maximum amount without overrunning the FIFO. | ||
631 | * For capture, this ensures that we transfer the maximum amount without | ||
632 | * underrunning the FIFO. | ||
633 | * | ||
634 | * f = SSI FIFO depth | ||
635 | * w = SSI watermark value (which equals f - 2) | ||
636 | * b = DMA bandwidth count (in bytes) | ||
637 | * s = sample size (in bytes, which equals frame_size * 2) | ||
638 | * | ||
639 | * For playback, we never transmit more than the transmit FIFO | ||
640 | * watermark, otherwise we might write more data than the FIFO can hold. | ||
641 | * The watermark is equal to the FIFO depth minus two. | ||
642 | * | ||
643 | * For capture, two equations must hold: | ||
644 | * w > f - (b / s) | ||
645 | * w >= b / s | ||
646 | * | ||
647 | * So, b > 2 * s, but b must also be <= s * w. To simplify, we set | ||
648 | * b = s * w, which is equal to | ||
649 | * (dma_private->ssi_fifo_depth - 2) * sample_bytes. | ||
624 | */ | 650 | */ |
625 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 651 | mr |= CCSR_DMA_MR_BWC((dma_private->ssi_fifo_depth - 2) * sample_bytes); |
626 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); | ||
627 | else | ||
628 | mr |= CCSR_DMA_MR_BWC(frame_size); | ||
629 | 652 | ||
630 | out_be32(&dma_channel->mr, mr); | 653 | out_be32(&dma_channel->mr, mr); |
631 | 654 | ||
@@ -879,6 +902,7 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev, | |||
879 | struct device_node *np = of_dev->dev.of_node; | 902 | struct device_node *np = of_dev->dev.of_node; |
880 | struct device_node *ssi_np; | 903 | struct device_node *ssi_np; |
881 | struct resource res; | 904 | struct resource res; |
905 | const uint32_t *iprop; | ||
882 | int ret; | 906 | int ret; |
883 | 907 | ||
884 | /* Find the SSI node that points to us. */ | 908 | /* Find the SSI node that points to us. */ |
@@ -889,15 +913,17 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev, | |||
889 | } | 913 | } |
890 | 914 | ||
891 | ret = of_address_to_resource(ssi_np, 0, &res); | 915 | ret = of_address_to_resource(ssi_np, 0, &res); |
892 | of_node_put(ssi_np); | ||
893 | if (ret) { | 916 | if (ret) { |
894 | dev_err(&of_dev->dev, "could not determine device resources\n"); | 917 | dev_err(&of_dev->dev, "could not determine resources for %s\n", |
918 | ssi_np->full_name); | ||
919 | of_node_put(ssi_np); | ||
895 | return ret; | 920 | return ret; |
896 | } | 921 | } |
897 | 922 | ||
898 | dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL); | 923 | dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL); |
899 | if (!dma) { | 924 | if (!dma) { |
900 | dev_err(&of_dev->dev, "could not allocate dma object\n"); | 925 | dev_err(&of_dev->dev, "could not allocate dma object\n"); |
926 | of_node_put(ssi_np); | ||
901 | return -ENOMEM; | 927 | return -ENOMEM; |
902 | } | 928 | } |
903 | 929 | ||
@@ -910,6 +936,15 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev, | |||
910 | dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0); | 936 | dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0); |
911 | dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0); | 937 | dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0); |
912 | 938 | ||
939 | iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); | ||
940 | if (iprop) | ||
941 | dma->ssi_fifo_depth = *iprop; | ||
942 | else | ||
943 | /* Older 8610 DTs didn't have the fifo-depth property */ | ||
944 | dma->ssi_fifo_depth = 8; | ||
945 | |||
946 | of_node_put(ssi_np); | ||
947 | |||
913 | ret = snd_soc_register_platform(&of_dev->dev, &dma->dai); | 948 | ret = snd_soc_register_platform(&of_dev->dev, &dma->dai); |
914 | if (ret) { | 949 | if (ret) { |
915 | dev_err(&of_dev->dev, "could not register platform\n"); | 950 | dev_err(&of_dev->dev, "could not register platform\n"); |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 7939c337ed9d..d1c855ade8fb 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -93,6 +93,7 @@ struct fsl_ssi_private { | |||
93 | unsigned int playback; | 93 | unsigned int playback; |
94 | unsigned int capture; | 94 | unsigned int capture; |
95 | int asynchronous; | 95 | int asynchronous; |
96 | unsigned int fifo_depth; | ||
96 | struct snd_soc_dai_driver cpu_dai_drv; | 97 | struct snd_soc_dai_driver cpu_dai_drv; |
97 | struct device_attribute dev_attr; | 98 | struct device_attribute dev_attr; |
98 | struct platform_device *pdev; | 99 | struct platform_device *pdev; |
@@ -337,11 +338,20 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
337 | 338 | ||
338 | /* | 339 | /* |
339 | * Set the watermark for transmit FIFI 0 and receive FIFO 0. We | 340 | * Set the watermark for transmit FIFI 0 and receive FIFO 0. We |
340 | * don't use FIFO 1. Since the SSI only supports stereo, the | 341 | * don't use FIFO 1. We program the transmit water to signal a |
341 | * watermark should never be an odd number. | 342 | * DMA transfer if there are only two (or fewer) elements left |
343 | * in the FIFO. Two elements equals one frame (left channel, | ||
344 | * right channel). This value, however, depends on the depth of | ||
345 | * the transmit buffer. | ||
346 | * | ||
347 | * We program the receive FIFO to notify us if at least two | ||
348 | * elements (one frame) have been written to the FIFO. We could | ||
349 | * make this value larger (and maybe we should), but this way | ||
350 | * data will be written to memory as soon as it's available. | ||
342 | */ | 351 | */ |
343 | out_be32(&ssi->sfcsr, | 352 | out_be32(&ssi->sfcsr, |
344 | CCSR_SSI_SFCSR_TFWM0(6) | CCSR_SSI_SFCSR_RFWM0(2)); | 353 | CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) | |
354 | CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2)); | ||
345 | 355 | ||
346 | /* | 356 | /* |
347 | * We keep the SSI disabled because if we enable it, then the | 357 | * We keep the SSI disabled because if we enable it, then the |
@@ -622,6 +632,7 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev, | |||
622 | struct device_attribute *dev_attr = NULL; | 632 | struct device_attribute *dev_attr = NULL; |
623 | struct device_node *np = of_dev->dev.of_node; | 633 | struct device_node *np = of_dev->dev.of_node; |
624 | const char *p, *sprop; | 634 | const char *p, *sprop; |
635 | const uint32_t *iprop; | ||
625 | struct resource res; | 636 | struct resource res; |
626 | char name[64]; | 637 | char name[64]; |
627 | 638 | ||
@@ -678,6 +689,14 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev, | |||
678 | else | 689 | else |
679 | ssi_private->cpu_dai_drv.symmetric_rates = 1; | 690 | ssi_private->cpu_dai_drv.symmetric_rates = 1; |
680 | 691 | ||
692 | /* Determine the FIFO depth. */ | ||
693 | iprop = of_get_property(np, "fsl,fifo-depth", NULL); | ||
694 | if (iprop) | ||
695 | ssi_private->fifo_depth = *iprop; | ||
696 | else | ||
697 | /* Older 8610 DTs didn't have the fifo-depth property */ | ||
698 | ssi_private->fifo_depth = 8; | ||
699 | |||
681 | /* Initialize the the device_attribute structure */ | 700 | /* Initialize the the device_attribute structure */ |
682 | dev_attr = &ssi_private->dev_attr; | 701 | dev_attr = &ssi_private->dev_attr; |
683 | dev_attr->attr.name = "statistics"; | 702 | dev_attr->attr.name = "statistics"; |