diff options
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/Kconfig | 17 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 7 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dma.c | 181 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 98 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.h | 2 | ||||
-rw-r--r-- | sound/soc/fsl/mpc5200_psc_i2s.c | 20 | ||||
-rw-r--r-- | sound/soc/fsl/mpc8610_hpcd.c | 5 |
7 files changed, 182 insertions, 148 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 95c12b26fe37..9fc908283371 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,17 +1,18 @@ | |||
1 | config SND_SOC_OF_SIMPLE | 1 | config SND_SOC_OF_SIMPLE |
2 | tristate | 2 | tristate |
3 | 3 | ||
4 | # ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers | ||
5 | # for the SSI and the Elo DMA controller. You will still need to select | ||
6 | # a platform driver and a codec driver. | ||
4 | config SND_SOC_MPC8610 | 7 | config SND_SOC_MPC8610 |
5 | bool "ALSA SoC support for the MPC8610 SOC" | 8 | tristate |
6 | depends on MPC8610_HPCD | 9 | depends on MPC8610 |
7 | default y if MPC8610 | ||
8 | help | ||
9 | Say Y if you want to add support for codecs attached to the SSI | ||
10 | device on an MPC8610. | ||
11 | 10 | ||
12 | config SND_SOC_MPC8610_HPCD | 11 | config SND_SOC_MPC8610_HPCD |
13 | bool "ALSA SoC support for the Freescale MPC8610 HPCD board" | 12 | tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" |
14 | depends on SND_SOC_MPC8610 | 13 | # I2C is necessary for the CS4270 driver |
14 | depends on MPC8610_HPCD && I2C | ||
15 | select SND_SOC_MPC8610 | ||
15 | select SND_SOC_CS4270 | 16 | select SND_SOC_CS4270 |
16 | select SND_SOC_CS4270_VD33_ERRATA | 17 | select SND_SOC_CS4270_VD33_ERRATA |
17 | default y if MPC8610_HPCD | 18 | default y if MPC8610_HPCD |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 035da4afec34..f85134c86387 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -2,10 +2,13 @@ | |||
2 | obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o | 2 | obj-$(CONFIG_SND_SOC_OF_SIMPLE) += soc-of-simple.o |
3 | 3 | ||
4 | # MPC8610 HPCD Machine Support | 4 | # MPC8610 HPCD Machine Support |
5 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += mpc8610_hpcd.o | 5 | snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o |
6 | obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o | ||
6 | 7 | ||
7 | # MPC8610 Platform Support | 8 | # MPC8610 Platform Support |
8 | obj-$(CONFIG_SND_SOC_MPC8610) += fsl_ssi.o fsl_dma.o | 9 | snd-soc-fsl-ssi-objs := fsl_ssi.o |
10 | snd-soc-fsl-dma-objs := fsl_dma.o | ||
11 | obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o | ||
9 | 12 | ||
10 | obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o | 13 | obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o |
11 | 14 | ||
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 64993eda5679..b3eb8570cd7b 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -142,7 +142,8 @@ static const struct snd_pcm_hardware fsl_dma_hardware = { | |||
142 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 142 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
143 | SNDRV_PCM_INFO_MMAP | | 143 | SNDRV_PCM_INFO_MMAP | |
144 | SNDRV_PCM_INFO_MMAP_VALID | | 144 | SNDRV_PCM_INFO_MMAP_VALID | |
145 | SNDRV_PCM_INFO_JOINT_DUPLEX, | 145 | SNDRV_PCM_INFO_JOINT_DUPLEX | |
146 | SNDRV_PCM_INFO_PAUSE, | ||
146 | .formats = FSLDMA_PCM_FORMATS, | 147 | .formats = FSLDMA_PCM_FORMATS, |
147 | .rates = FSLDMA_PCM_RATES, | 148 | .rates = FSLDMA_PCM_RATES, |
148 | .rate_min = 5512, | 149 | .rate_min = 5512, |
@@ -464,11 +465,7 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
464 | sizeof(struct fsl_dma_link_descriptor); | 465 | sizeof(struct fsl_dma_link_descriptor); |
465 | 466 | ||
466 | for (i = 0; i < NUM_DMA_LINKS; i++) { | 467 | for (i = 0; i < NUM_DMA_LINKS; i++) { |
467 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | 468 | dma_private->link[i].next = cpu_to_be64(temp_link); |
468 | |||
469 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
470 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
471 | link->next = cpu_to_be64(temp_link); | ||
472 | 469 | ||
473 | temp_link += sizeof(struct fsl_dma_link_descriptor); | 470 | temp_link += sizeof(struct fsl_dma_link_descriptor); |
474 | } | 471 | } |
@@ -525,79 +522,9 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) | |||
525 | * This function obtains hardware parameters about the opened stream and | 522 | * This function obtains hardware parameters about the opened stream and |
526 | * programs the DMA controller accordingly. | 523 | * programs the DMA controller accordingly. |
527 | * | 524 | * |
528 | * Note that due to a quirk of the SSI's STX register, the target address | 525 | * One drawback of big-endian is that when copying integers of different |
529 | * for the DMA operations depends on the sample size. So we don't program | 526 | * sizes to a fixed-sized register, the address to which the integer must be |
530 | * the dest_addr (for playback -- source_addr for capture) fields in the | 527 | * copied is dependent on the size of the integer. |
531 | * link descriptors here. We do that in fsl_dma_prepare() | ||
532 | */ | ||
533 | static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | ||
534 | struct snd_pcm_hw_params *hw_params) | ||
535 | { | ||
536 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
537 | struct fsl_dma_private *dma_private = runtime->private_data; | ||
538 | |||
539 | dma_addr_t temp_addr; /* Pointer to next period */ | ||
540 | |||
541 | unsigned int i; | ||
542 | |||
543 | /* Get all the parameters we need */ | ||
544 | size_t buffer_size = params_buffer_bytes(hw_params); | ||
545 | size_t period_size = params_period_bytes(hw_params); | ||
546 | |||
547 | /* Initialize our DMA tracking variables */ | ||
548 | dma_private->period_size = period_size; | ||
549 | dma_private->num_periods = params_periods(hw_params); | ||
550 | dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; | ||
551 | dma_private->dma_buf_next = dma_private->dma_buf_phys + | ||
552 | (NUM_DMA_LINKS * period_size); | ||
553 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
554 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
555 | |||
556 | /* | ||
557 | * The actual address in STX0 (destination for playback, source for | ||
558 | * capture) is based on the sample size, but we don't know the sample | ||
559 | * size in this function, so we'll have to adjust that later. See | ||
560 | * comments in fsl_dma_prepare(). | ||
561 | * | ||
562 | * The DMA controller does not have a cache, so the CPU does not | ||
563 | * need to tell it to flush its cache. However, the DMA | ||
564 | * controller does need to tell the CPU to flush its cache. | ||
565 | * That's what the SNOOP bit does. | ||
566 | * | ||
567 | * Also, even though the DMA controller supports 36-bit addressing, for | ||
568 | * simplicity we currently support only 32-bit addresses for the audio | ||
569 | * buffer itself. | ||
570 | */ | ||
571 | temp_addr = substream->dma_buffer.addr; | ||
572 | |||
573 | for (i = 0; i < NUM_DMA_LINKS; i++) { | ||
574 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | ||
575 | |||
576 | link->count = cpu_to_be32(period_size); | ||
577 | |||
578 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
579 | link->source_addr = cpu_to_be32(temp_addr); | ||
580 | else | ||
581 | link->dest_addr = cpu_to_be32(temp_addr); | ||
582 | |||
583 | temp_addr += period_size; | ||
584 | } | ||
585 | |||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | /** | ||
590 | * fsl_dma_prepare - prepare the DMA registers for playback. | ||
591 | * | ||
592 | * This function is called after the specifics of the audio data are known, | ||
593 | * i.e. snd_pcm_runtime is initialized. | ||
594 | * | ||
595 | * In this function, we finish programming the registers of the DMA | ||
596 | * controller that are dependent on the sample size. | ||
597 | * | ||
598 | * One of the drawbacks with big-endian is that when copying integers of | ||
599 | * different sizes to a fixed-sized register, the address to which the | ||
600 | * integer must be copied is dependent on the size of the integer. | ||
601 | * | 528 | * |
602 | * For example, if P is the address of a 32-bit register, and X is a 32-bit | 529 | * For example, if P is the address of a 32-bit register, and X is a 32-bit |
603 | * integer, then X should be copied to address P. However, if X is a 16-bit | 530 | * integer, then X should be copied to address P. However, if X is a 16-bit |
@@ -613,22 +540,58 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, | |||
613 | * and 8 bytes at a time). So we do not support packed 24-bit samples. | 540 | * and 8 bytes at a time). So we do not support packed 24-bit samples. |
614 | * 24-bit data must be padded to 32 bits. | 541 | * 24-bit data must be padded to 32 bits. |
615 | */ | 542 | */ |
616 | static int fsl_dma_prepare(struct snd_pcm_substream *substream) | 543 | static int fsl_dma_hw_params(struct snd_pcm_substream *substream, |
544 | struct snd_pcm_hw_params *hw_params) | ||
617 | { | 545 | { |
618 | struct snd_pcm_runtime *runtime = substream->runtime; | 546 | struct snd_pcm_runtime *runtime = substream->runtime; |
619 | struct fsl_dma_private *dma_private = runtime->private_data; | 547 | struct fsl_dma_private *dma_private = runtime->private_data; |
548 | |||
549 | /* Number of bits per sample */ | ||
550 | unsigned int sample_size = | ||
551 | snd_pcm_format_physical_width(params_format(hw_params)); | ||
552 | |||
553 | /* Number of bytes per frame */ | ||
554 | unsigned int frame_size = 2 * (sample_size / 8); | ||
555 | |||
556 | /* Bus address of SSI STX register */ | ||
557 | dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys; | ||
558 | |||
559 | /* Size of the DMA buffer, in bytes */ | ||
560 | size_t buffer_size = params_buffer_bytes(hw_params); | ||
561 | |||
562 | /* Number of bytes per period */ | ||
563 | size_t period_size = params_period_bytes(hw_params); | ||
564 | |||
565 | /* Pointer to next period */ | ||
566 | dma_addr_t temp_addr = substream->dma_buffer.addr; | ||
567 | |||
568 | /* Pointer to DMA controller */ | ||
620 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; | 569 | struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; |
621 | u32 mr; | 570 | |
571 | u32 mr; /* DMA Mode Register */ | ||
572 | |||
622 | unsigned int i; | 573 | unsigned int i; |
623 | dma_addr_t ssi_sxx_phys; /* Bus address of SSI STX register */ | ||
624 | unsigned int frame_size; /* Number of bytes per frame */ | ||
625 | 574 | ||
626 | ssi_sxx_phys = dma_private->ssi_sxx_phys; | 575 | /* Initialize our DMA tracking variables */ |
576 | dma_private->period_size = period_size; | ||
577 | dma_private->num_periods = params_periods(hw_params); | ||
578 | dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; | ||
579 | dma_private->dma_buf_next = dma_private->dma_buf_phys + | ||
580 | (NUM_DMA_LINKS * period_size); | ||
581 | |||
582 | if (dma_private->dma_buf_next >= dma_private->dma_buf_end) | ||
583 | /* This happens if the number of periods == NUM_DMA_LINKS */ | ||
584 | dma_private->dma_buf_next = dma_private->dma_buf_phys; | ||
627 | 585 | ||
628 | mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | | 586 | mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | |
629 | CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); | 587 | CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); |
630 | 588 | ||
631 | switch (runtime->sample_bits) { | 589 | /* Due to a quirk of the SSI's STX register, the target address |
590 | * for the DMA operations depends on the sample size. So we calculate | ||
591 | * that offset here. While we're at it, also tell the DMA controller | ||
592 | * how much data to transfer per sample. | ||
593 | */ | ||
594 | switch (sample_size) { | ||
632 | case 8: | 595 | case 8: |
633 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; | 596 | mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; |
634 | ssi_sxx_phys += 3; | 597 | ssi_sxx_phys += 3; |
@@ -641,12 +604,12 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
641 | mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; | 604 | mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; |
642 | break; | 605 | break; |
643 | default: | 606 | default: |
607 | /* We should never get here */ | ||
644 | dev_err(substream->pcm->card->dev, | 608 | dev_err(substream->pcm->card->dev, |
645 | "unsupported sample size %u\n", runtime->sample_bits); | 609 | "unsupported sample size %u\n", sample_size); |
646 | return -EINVAL; | 610 | return -EINVAL; |
647 | } | 611 | } |
648 | 612 | ||
649 | frame_size = runtime->frame_bits / 8; | ||
650 | /* | 613 | /* |
651 | * BWC should always be a multiple of the frame size. BWC determines | 614 | * BWC should always be a multiple of the frame size. BWC determines |
652 | * how many bytes are sent/received before the DMA controller checks the | 615 | * how many bytes are sent/received before the DMA controller checks the |
@@ -655,7 +618,6 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
655 | * capture, the receive FIFO is triggered when it contains one frame, so | 618 | * capture, the receive FIFO is triggered when it contains one frame, so |
656 | * we want to receive one frame at a time. | 619 | * we want to receive one frame at a time. |
657 | */ | 620 | */ |
658 | |||
659 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 621 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
660 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); | 622 | mr |= CCSR_DMA_MR_BWC(2 * frame_size); |
661 | else | 623 | else |
@@ -663,16 +625,48 @@ static int fsl_dma_prepare(struct snd_pcm_substream *substream) | |||
663 | 625 | ||
664 | out_be32(&dma_channel->mr, mr); | 626 | out_be32(&dma_channel->mr, mr); |
665 | 627 | ||
666 | /* | ||
667 | * Program the address of the DMA transfer to/from the SSI. | ||
668 | */ | ||
669 | for (i = 0; i < NUM_DMA_LINKS; i++) { | 628 | for (i = 0; i < NUM_DMA_LINKS; i++) { |
670 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; | 629 | struct fsl_dma_link_descriptor *link = &dma_private->link[i]; |
671 | 630 | ||
672 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 631 | link->count = cpu_to_be32(period_size); |
632 | |||
633 | /* Even though the DMA controller supports 36-bit addressing, | ||
634 | * for simplicity we allow only 32-bit addresses for the audio | ||
635 | * buffer itself. This was enforced in fsl_dma_new() with the | ||
636 | * DMA mask. | ||
637 | * | ||
638 | * The snoop bit tells the DMA controller whether it should tell | ||
639 | * the ECM to snoop during a read or write to an address. For | ||
640 | * audio, we use DMA to transfer data between memory and an I/O | ||
641 | * device (the SSI's STX0 or SRX0 register). Snooping is only | ||
642 | * needed if there is a cache, so we need to snoop memory | ||
643 | * addresses only. For playback, that means we snoop the source | ||
644 | * but not the destination. For capture, we snoop the | ||
645 | * destination but not the source. | ||
646 | * | ||
647 | * Note that failing to snoop properly is unlikely to cause | ||
648 | * cache incoherency if the period size is larger than the | ||
649 | * size of L1 cache. This is because filling in one period will | ||
650 | * flush out the data for the previous period. So if you | ||
651 | * increased period_bytes_min to a large enough size, you might | ||
652 | * get more performance by not snooping, and you'll still be | ||
653 | * okay. | ||
654 | */ | ||
655 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
656 | link->source_addr = cpu_to_be32(temp_addr); | ||
657 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
658 | |||
673 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); | 659 | link->dest_addr = cpu_to_be32(ssi_sxx_phys); |
674 | else | 660 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); |
661 | } else { | ||
675 | link->source_addr = cpu_to_be32(ssi_sxx_phys); | 662 | link->source_addr = cpu_to_be32(ssi_sxx_phys); |
663 | link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP); | ||
664 | |||
665 | link->dest_addr = cpu_to_be32(temp_addr); | ||
666 | link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP); | ||
667 | } | ||
668 | |||
669 | temp_addr += period_size; | ||
676 | } | 670 | } |
677 | 671 | ||
678 | return 0; | 672 | return 0; |
@@ -808,7 +802,6 @@ static struct snd_pcm_ops fsl_dma_ops = { | |||
808 | .ioctl = snd_pcm_lib_ioctl, | 802 | .ioctl = snd_pcm_lib_ioctl, |
809 | .hw_params = fsl_dma_hw_params, | 803 | .hw_params = fsl_dma_hw_params, |
810 | .hw_free = fsl_dma_hw_free, | 804 | .hw_free = fsl_dma_hw_free, |
811 | .prepare = fsl_dma_prepare, | ||
812 | .pointer = fsl_dma_pointer, | 805 | .pointer = fsl_dma_pointer, |
813 | }; | 806 | }; |
814 | 807 | ||
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c6d6eb71dc1d..169bca295b78 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -72,6 +72,7 @@ | |||
72 | * @dev: struct device pointer | 72 | * @dev: struct device pointer |
73 | * @playback: the number of playback streams opened | 73 | * @playback: the number of playback streams opened |
74 | * @capture: the number of capture streams opened | 74 | * @capture: the number of capture streams opened |
75 | * @asynchronous: 0=synchronous mode, 1=asynchronous mode | ||
75 | * @cpu_dai: the CPU DAI for this device | 76 | * @cpu_dai: the CPU DAI for this device |
76 | * @dev_attr: the sysfs device attribute structure | 77 | * @dev_attr: the sysfs device attribute structure |
77 | * @stats: SSI statistics | 78 | * @stats: SSI statistics |
@@ -86,6 +87,7 @@ struct fsl_ssi_private { | |||
86 | struct device *dev; | 87 | struct device *dev; |
87 | unsigned int playback; | 88 | unsigned int playback; |
88 | unsigned int capture; | 89 | unsigned int capture; |
90 | int asynchronous; | ||
89 | struct snd_soc_dai cpu_dai; | 91 | struct snd_soc_dai cpu_dai; |
90 | struct device_attribute dev_attr; | 92 | struct device_attribute dev_attr; |
91 | 93 | ||
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
301 | * | 303 | * |
302 | * FIXME: Little-endian samples require a different shift dir | 304 | * FIXME: Little-endian samples require a different shift dir |
303 | */ | 305 | */ |
304 | clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK, | 306 | clrsetbits_be32(&ssi->scr, |
305 | CCSR_SSI_SCR_TFR_CLK_DIS | | 307 | CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, |
306 | CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN); | 308 | CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE |
309 | | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN)); | ||
307 | 310 | ||
308 | out_be32(&ssi->stcr, | 311 | out_be32(&ssi->stcr, |
309 | CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | | 312 | CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
382 | SNDRV_PCM_HW_PARAM_RATE, | 385 | SNDRV_PCM_HW_PARAM_RATE, |
383 | first_runtime->rate, first_runtime->rate); | 386 | first_runtime->rate, first_runtime->rate); |
384 | 387 | ||
385 | snd_pcm_hw_constraint_minmax(substream->runtime, | 388 | /* If we're in synchronous mode, then we need to constrain |
386 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | 389 | * the sample size as well. We don't support independent sample |
387 | first_runtime->sample_bits, | 390 | * rates in asynchronous mode. |
388 | first_runtime->sample_bits); | 391 | */ |
392 | if (!ssi_private->asynchronous) | ||
393 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
394 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
395 | first_runtime->sample_bits, | ||
396 | first_runtime->sample_bits); | ||
389 | 397 | ||
390 | ssi_private->second_stream = substream; | 398 | ssi_private->second_stream = substream; |
391 | } | 399 | } |
@@ -400,7 +408,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
400 | } | 408 | } |
401 | 409 | ||
402 | /** | 410 | /** |
403 | * fsl_ssi_prepare: prepare the SSI. | 411 | * fsl_ssi_hw_params - program the sample size |
404 | * | 412 | * |
405 | * Most of the SSI registers have been programmed in the startup function, | 413 | * Most of the SSI registers have been programmed in the startup function, |
406 | * but the word length must be programmed here. Unfortunately, programming | 414 | * but the word length must be programmed here. Unfortunately, programming |
@@ -412,23 +420,27 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
412 | * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the | 420 | * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the |
413 | * clock master. | 421 | * clock master. |
414 | */ | 422 | */ |
415 | static int fsl_ssi_prepare(struct snd_pcm_substream *substream, | 423 | static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, |
416 | struct snd_soc_dai *dai) | 424 | struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai) |
417 | { | 425 | { |
418 | struct snd_pcm_runtime *runtime = substream->runtime; | 426 | struct fsl_ssi_private *ssi_private = cpu_dai->private_data; |
419 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
420 | struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; | ||
421 | |||
422 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | ||
423 | 427 | ||
424 | if (substream == ssi_private->first_stream) { | 428 | if (substream == ssi_private->first_stream) { |
425 | u32 wl; | 429 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
430 | unsigned int sample_size = | ||
431 | snd_pcm_format_width(params_format(hw_params)); | ||
432 | u32 wl = CCSR_SSI_SxCCR_WL(sample_size); | ||
426 | 433 | ||
427 | /* The SSI should always be disabled at this points (SSIEN=0) */ | 434 | /* The SSI should always be disabled at this points (SSIEN=0) */ |
428 | wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format)); | ||
429 | 435 | ||
430 | /* In synchronous mode, the SSI uses STCCR for capture */ | 436 | /* In synchronous mode, the SSI uses STCCR for capture */ |
431 | clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); | 437 | if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) || |
438 | !ssi_private->asynchronous) | ||
439 | clrsetbits_be32(&ssi->stccr, | ||
440 | CCSR_SSI_SxCCR_WL_MASK, wl); | ||
441 | else | ||
442 | clrsetbits_be32(&ssi->srccr, | ||
443 | CCSR_SSI_SxCCR_WL_MASK, wl); | ||
432 | } | 444 | } |
433 | 445 | ||
434 | return 0; | 446 | return 0; |
@@ -452,28 +464,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
452 | 464 | ||
453 | switch (cmd) { | 465 | switch (cmd) { |
454 | case SNDRV_PCM_TRIGGER_START: | 466 | case SNDRV_PCM_TRIGGER_START: |
455 | case SNDRV_PCM_TRIGGER_RESUME: | 467 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); |
456 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 468 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
457 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 469 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
458 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | ||
459 | setbits32(&ssi->scr, | 470 | setbits32(&ssi->scr, |
460 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); | 471 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); |
461 | } else { | 472 | } else { |
462 | clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); | 473 | long timeout = jiffies + 10; |
474 | |||
463 | setbits32(&ssi->scr, | 475 | setbits32(&ssi->scr, |
464 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); | 476 | CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); |
465 | 477 | ||
466 | /* | 478 | /* Wait until the SSI has filled its FIFO. Without this |
467 | * I think we need this delay to allow time for the SSI | 479 | * delay, ALSA complains about overruns. When the FIFO |
468 | * to put data into its FIFO. Without it, ALSA starts | 480 | * is full, the DMA controller initiates its first |
469 | * to complain about overruns. | 481 | * transfer. Until then, however, the DMA's DAR |
482 | * register is zero, which translates to an | ||
483 | * out-of-bounds pointer. This makes ALSA think an | ||
484 | * overrun has occurred. | ||
470 | */ | 485 | */ |
471 | mdelay(1); | 486 | while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) && |
487 | (jiffies < timeout)); | ||
488 | if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0)) | ||
489 | return -EIO; | ||
472 | } | 490 | } |
473 | break; | 491 | break; |
474 | 492 | ||
475 | case SNDRV_PCM_TRIGGER_STOP: | 493 | case SNDRV_PCM_TRIGGER_STOP: |
476 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
477 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 494 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
478 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 495 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
479 | clrbits32(&ssi->scr, CCSR_SSI_SCR_TE); | 496 | clrbits32(&ssi->scr, CCSR_SSI_SCR_TE); |
@@ -563,6 +580,15 @@ static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) | |||
563 | /** | 580 | /** |
564 | * fsl_ssi_dai_template: template CPU DAI for the SSI | 581 | * fsl_ssi_dai_template: template CPU DAI for the SSI |
565 | */ | 582 | */ |
583 | static struct snd_soc_dai_ops fsl_ssi_dai_ops = { | ||
584 | .startup = fsl_ssi_startup, | ||
585 | .hw_params = fsl_ssi_hw_params, | ||
586 | .shutdown = fsl_ssi_shutdown, | ||
587 | .trigger = fsl_ssi_trigger, | ||
588 | .set_sysclk = fsl_ssi_set_sysclk, | ||
589 | .set_fmt = fsl_ssi_set_fmt, | ||
590 | }; | ||
591 | |||
566 | static struct snd_soc_dai fsl_ssi_dai_template = { | 592 | static struct snd_soc_dai fsl_ssi_dai_template = { |
567 | .playback = { | 593 | .playback = { |
568 | /* The SSI does not support monaural audio. */ | 594 | /* The SSI does not support monaural audio. */ |
@@ -577,14 +603,7 @@ static struct snd_soc_dai fsl_ssi_dai_template = { | |||
577 | .rates = FSLSSI_I2S_RATES, | 603 | .rates = FSLSSI_I2S_RATES, |
578 | .formats = FSLSSI_I2S_FORMATS, | 604 | .formats = FSLSSI_I2S_FORMATS, |
579 | }, | 605 | }, |
580 | .ops = { | 606 | .ops = &fsl_ssi_dai_ops, |
581 | .startup = fsl_ssi_startup, | ||
582 | .prepare = fsl_ssi_prepare, | ||
583 | .shutdown = fsl_ssi_shutdown, | ||
584 | .trigger = fsl_ssi_trigger, | ||
585 | .set_sysclk = fsl_ssi_set_sysclk, | ||
586 | .set_fmt = fsl_ssi_set_fmt, | ||
587 | }, | ||
588 | }; | 607 | }; |
589 | 608 | ||
590 | /** | 609 | /** |
@@ -654,6 +673,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info) | |||
654 | ssi_private->ssi_phys = ssi_info->ssi_phys; | 673 | ssi_private->ssi_phys = ssi_info->ssi_phys; |
655 | ssi_private->irq = ssi_info->irq; | 674 | ssi_private->irq = ssi_info->irq; |
656 | ssi_private->dev = ssi_info->dev; | 675 | ssi_private->dev = ssi_info->dev; |
676 | ssi_private->asynchronous = ssi_info->asynchronous; | ||
657 | 677 | ||
658 | ssi_private->dev->driver_data = fsl_ssi_dai; | 678 | ssi_private->dev->driver_data = fsl_ssi_dai; |
659 | 679 | ||
@@ -704,6 +724,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai) | |||
704 | } | 724 | } |
705 | EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); | 725 | EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); |
706 | 726 | ||
727 | static int __init fsl_ssi_init(void) | ||
728 | { | ||
729 | printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n"); | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | module_init(fsl_ssi_init); | ||
734 | |||
707 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | 735 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); |
708 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); | 736 | MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); |
709 | MODULE_LICENSE("GPL"); | 737 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index 83b44d700e33..eade01feaab6 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h | |||
@@ -208,6 +208,7 @@ struct ccsr_ssi { | |||
208 | * ssi_phys: physical address of the SSI registers | 208 | * ssi_phys: physical address of the SSI registers |
209 | * irq: IRQ of this SSI | 209 | * irq: IRQ of this SSI |
210 | * dev: struct device, used to create the sysfs statistics file | 210 | * dev: struct device, used to create the sysfs statistics file |
211 | * asynchronous: 0=synchronous mode, 1=asynchronous mode | ||
211 | */ | 212 | */ |
212 | struct fsl_ssi_info { | 213 | struct fsl_ssi_info { |
213 | unsigned int id; | 214 | unsigned int id; |
@@ -215,6 +216,7 @@ struct fsl_ssi_info { | |||
215 | dma_addr_t ssi_phys; | 216 | dma_addr_t ssi_phys; |
216 | unsigned int irq; | 217 | unsigned int irq; |
217 | struct device *dev; | 218 | struct device *dev; |
219 | int asynchronous; | ||
218 | }; | 220 | }; |
219 | 221 | ||
220 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); | 222 | struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info); |
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 9eb1ce185bd0..3aa729df27b5 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c | |||
@@ -468,6 +468,16 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format) | |||
468 | /** | 468 | /** |
469 | * psc_i2s_dai_template: template CPU Digital Audio Interface | 469 | * psc_i2s_dai_template: template CPU Digital Audio Interface |
470 | */ | 470 | */ |
471 | static struct snd_soc_dai_ops psc_i2s_dai_ops = { | ||
472 | .startup = psc_i2s_startup, | ||
473 | .hw_params = psc_i2s_hw_params, | ||
474 | .hw_free = psc_i2s_hw_free, | ||
475 | .shutdown = psc_i2s_shutdown, | ||
476 | .trigger = psc_i2s_trigger, | ||
477 | .set_sysclk = psc_i2s_set_sysclk, | ||
478 | .set_fmt = psc_i2s_set_fmt, | ||
479 | }; | ||
480 | |||
471 | static struct snd_soc_dai psc_i2s_dai_template = { | 481 | static struct snd_soc_dai psc_i2s_dai_template = { |
472 | .playback = { | 482 | .playback = { |
473 | .channels_min = 2, | 483 | .channels_min = 2, |
@@ -481,15 +491,7 @@ static struct snd_soc_dai psc_i2s_dai_template = { | |||
481 | .rates = PSC_I2S_RATES, | 491 | .rates = PSC_I2S_RATES, |
482 | .formats = PSC_I2S_FORMATS, | 492 | .formats = PSC_I2S_FORMATS, |
483 | }, | 493 | }, |
484 | .ops = { | 494 | .ops = &psc_i2s_dai_ops, |
485 | .startup = psc_i2s_startup, | ||
486 | .hw_params = psc_i2s_hw_params, | ||
487 | .hw_free = psc_i2s_hw_free, | ||
488 | .shutdown = psc_i2s_shutdown, | ||
489 | .trigger = psc_i2s_trigger, | ||
490 | .set_sysclk = psc_i2s_set_sysclk, | ||
491 | .set_fmt = psc_i2s_set_fmt, | ||
492 | }, | ||
493 | }; | 495 | }; |
494 | 496 | ||
495 | /* --------------------------------------------------------------------- | 497 | /* --------------------------------------------------------------------- |
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index acf39a646b2f..ef67d1cdffe7 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -353,6 +353,11 @@ static int mpc8610_hpcd_probe(struct of_device *ofdev, | |||
353 | } | 353 | } |
354 | ssi_info.irq = machine_data->ssi_irq; | 354 | ssi_info.irq = machine_data->ssi_irq; |
355 | 355 | ||
356 | /* Do we want to use asynchronous mode? */ | ||
357 | ssi_info.asynchronous = | ||
358 | of_find_property(np, "fsl,ssi-asynchronous", NULL) ? 1 : 0; | ||
359 | if (ssi_info.asynchronous) | ||
360 | dev_info(&ofdev->dev, "using asynchronous mode\n"); | ||
356 | 361 | ||
357 | /* Map the global utilities registers. */ | 362 | /* Map the global utilities registers. */ |
358 | guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); | 363 | guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts"); |