On Wed, Jun 10, 2009 at 1:44 PM, Paul Shen<boshen9@xxxxxxxxx> wrote: > 2009/6/10 Daniel Ribeiro <drwyrm@xxxxxxxxx>: >> * Extend set_tdm_slot to allow the user to arbitrarily set the frame >> width and active TX/RX slots. >> * Reset SSCR0_EDSS and SSCR0_DSS on pxa_ssp_set_dai_fmt. >> * Makes SSCR0_MOD optional. >> * Automatically sets network mode when needed if set_tdm_slot was >> never called. >> * Clears SSCR1_RWOT case SSCR0_MOD is set. >> * Updates magician.c and wm9081.c for the new set_tdm_slot() >> >> (Patch is based on Mark's for-2.6.32 branch) >> >> Signed-off-by: Daniel Ribeiro <drwyrm@xxxxxxxxx> >> >> --- >> include/sound/soc-dai.h | 5 + >> sound/soc/codecs/wm9081.c | 4 - >> sound/soc/pxa/magician.c | 2 >> sound/soc/pxa/pxa-ssp.c | 119 ++++++++++++++++++++++++++++------------------ >> sound/soc/soc-core.c | 9 ++- >> 5 files changed, 85 insertions(+), 54 deletions(-) >> >> diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h >> index 352d7ee..f96cc36 100644 >> --- a/include/sound/soc-dai.h >> +++ b/include/sound/soc-dai.h >> @@ -106,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, >> int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); >> >> int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, >> - unsigned int mask, int slots); >> + unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width); >> >> int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); >> >> @@ -140,7 +140,8 @@ struct snd_soc_dai_ops { >> */ >> int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); >> int (*set_tdm_slot)(struct snd_soc_dai *dai, >> - unsigned int mask, int slots); >> + unsigned int tx_mask, unsigned int rx_mask, >> + int slots, int frame_width); >> int (*set_tristate)(struct snd_soc_dai *dai, int tristate); >> >> /* >> diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c >> index 86fc57e..85c720a 100644 >> --- a/sound/soc/codecs/wm9081.c >> +++ b/sound/soc/codecs/wm9081.c >> @@ -1207,7 +1207,7 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai, >> } >> >> static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, >> - unsigned int mask, int slots) >> + unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width) >> { >> struct snd_soc_codec *codec = dai->codec; >> unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); >> @@ -1219,7 +1219,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, >> >> aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT; >> >> - switch (mask) { >> + switch (tx_mask) { >> case 1: >> break; >> case 2: >> diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c >> index c89a3cd..2345869 100644 >> --- a/sound/soc/pxa/magician.c >> +++ b/sound/soc/pxa/magician.c >> @@ -188,7 +188,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, >> if (ret < 0) >> return ret; >> >> - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1); >> + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1, 1, 16); >> if (ret < 0) >> return ret; >> >> diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c >> index 46d14f3..f0931e7 100644 >> --- a/sound/soc/pxa/pxa-ssp.c >> +++ b/sound/soc/pxa/pxa-ssp.c >> @@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, >> * Set the active slots in TDM/Network mode >> */ >> static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, >> - unsigned int mask, int slots) >> + unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width) >> { >> struct ssp_priv *priv = cpu_dai->private_data; >> struct ssp_device *ssp = priv->dev.ssp; >> u32 sscr0; >> >> - sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7); >> + sscr0 = ssp_read_reg(ssp, SSCR0); >> + sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(7) | SSCR0_EDSS | SSCR0_DSS); >> + >> + /* set frame width */ >> + if (frame_width > 16) >> + sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16); >> + else >> + sscr0 |= SSCR0_DataSize(frame_width); >> + >> + if (slots > 1) { >> + /* enable network mode */ >> + sscr0 |= SSCR0_MOD; >> > Seems the frame_width has no such relations with sampe width, the > sample width is defined on runtime by the audio files. > Make a example sample with paly a often used 16bit sample width > stereo aduio file. > > When you play 16bit audio sample with 2*16 bit frame , > frame --|____________|------------------|_____________|--- > data --<======>-<======>-<======>- > here the datasize should be SSCR0_DataSize(16), the frame size is 32 > > also you can play 16bit audio sample with 2*32 frame, > frame > --|_________________________|------------------------------------|____ > data --<======>-------------------<======>-------------------<== > here the datasize is also DataSize(16), but the frame size is 64. > > Do I misunderstand you? Hmm right, the real frame width is DataSize * slots. So maybe /* set data size */ data_size = frame_width/slots; if (data_size > 16) sscr0 |= SSCR0_EDSS | SSCR0_DataSize(data_size - 16); else sscr0 |= SSCR0_DataSize(data_size); would be more appropriate. Or have that parameter be sample_width instead, as Mark initially proposed. >> - /* set number of active slots */ >> - sscr0 |= SSCR0_SlotsPerFrm(slots); >> + /* set number of active slots */ >> + sscr0 |= SSCR0_SlotsPerFrm(slots); >> + >> + /* set active slot mask */ >> + ssp_write_reg(ssp, SSTSA, tx_mask); >> + ssp_write_reg(ssp, SSRSA, rx_mask); >> + } >> ssp_write_reg(ssp, SSCR0, sscr0); >> >> - /* set active slot mask */ >> - ssp_write_reg(ssp, SSTSA, mask); >> - ssp_write_reg(ssp, SSRSA, mask); >> return 0; >> } >> >> @@ -439,8 +452,8 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, >> } >> >> /* reset port settings */ >> - sscr0 = ssp_read_reg(ssp, SSCR0) & >> - (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); >> + sscr0 = ssp_read_reg(ssp, SSCR0) & (SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | >> + SSCR0_ACS | SSCR0_EDSS | SSCR0_DSS); >> sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7); >> sspsp = 0; >> >> @@ -487,7 +500,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, >> case SND_SOC_DAIFMT_DSP_A: >> sspsp |= SSPSP_FSRT; >> case SND_SOC_DAIFMT_DSP_B: >> - sscr0 |= SSCR0_MOD | SSCR0_PSP; >> + sscr0 |= SSCR0_PSP; >> sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; >> >> switch (fmt & SND_SOC_DAIFMT_INV_MASK) { >> @@ -537,48 +550,70 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, >> struct ssp_priv *priv = cpu_dai->private_data; >> struct ssp_device *ssp = priv->dev.ssp; >> int chn = params_channels(params); >> - u32 sscr0; >> - u32 sspsp; >> + u32 sscr0, sscr1, sspsp; >> int width = snd_pcm_format_physical_width(params_format(params)); >> - int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf; >> + int frame_width; >> + >> + /* check if the user explicitly set a frame_width */ >> + sscr0 = ssp_read_reg(ssp, SSCR0); >> + >> + if (sscr0 & (SSCR0_EDSS | SSCR0_DSS)) >> + frame_width = (sscr0 & SSCR0_DSS) + >> + (sscr0 & SSCR0_EDSS ? 17 : 1); >> + else >> + frame_width = width * chn; >> >> /* generate correct DMA params */ >> if (cpu_dai->dma_data) >> kfree(cpu_dai->dma_data); >> >> - /* Network mode with one active slot (ttsa == 1) can be used >> - * to force 16-bit frame width on the wire (for S16_LE), even >> - * with two channels. Use 16-bit DMA transfers for this case. >> - */ >> - cpu_dai->dma_data = ssp_get_dma_params(ssp, >> - ((chn == 2) && (ttsa != 1)) || (width == 32), >> + cpu_dai->dma_data = ssp_get_dma_params(ssp, frame_width > 16, >> substream->stream == SNDRV_PCM_STREAM_PLAYBACK); >> >> /* we can only change the settings if the port is not in use */ >> - if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) >> + if (sscr0 & SSCR0_SSE) >> return 0; >> >> - /* clear selected SSP bits */ >> - sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS); >> - ssp_write_reg(ssp, SSCR0, sscr0); >> - >> - /* bit size */ >> - sscr0 = ssp_read_reg(ssp, SSCR0); >> - switch (params_format(params)) { >> - case SNDRV_PCM_FORMAT_S16_LE: >> + /* FIXME: What this is for? */ >> #ifdef CONFIG_PXA3xx >> - if (cpu_is_pxa3xx()) >> - sscr0 |= SSCR0_FPCKE; >> + if (width == 16 && cpu_is_pxa3xx()) >> + sscr0 |= SSCR0_FPCKE; >> #endif >> - sscr0 |= SSCR0_DataSize(16); >> - break; >> - case SNDRV_PCM_FORMAT_S24_LE: >> - sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); >> - break; >> - case SNDRV_PCM_FORMAT_S32_LE: >> - sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); >> - break; >> + >> + if (!(sscr0 & (SSCR0_EDSS | SSCR0_DSS))) { >> + /* Frame width not set yet, we are not using network mode */ >> + if (frame_width > 16) >> + sscr0 |= SSCR0_EDSS | SSCR0_DataSize(frame_width - 16); >> + else >> + sscr0 |= SSCR0_DataSize(frame_width); >> + >> + if (frame_width > 32) { >> + /* >> + * Network mode is needed to support this frame_width >> + * We assume that the wire is not networked and setup >> + * a "fake" network mode here. >> + */ >> + int slots = frame_width / 32; >> + >> + sscr0 |= SSCR0_MOD; >> + sscr0 |= SSCR0_SlotsPerFrm(slots); >> + >> + /* >> + * Set active slots. Only set an active TX slot >> + * if we are going to use it. >> + */ >> + ssp_write_reg(ssp, SSRSA, slots - 1); >> + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) >> + ssp_write_reg(ssp, SSTSA, slots - 1); >> + } >> } >> + >> + /* If SSCR0_MOD is set we can't use SSCR1_RWOT */ >> + if (sscr0 & SSCR0_MOD) { >> + sscr1 = ssp_read_reg(ssp, SSCR1); >> + ssp_write_reg(ssp, SSCR1, sscr1 & ~SSCR1_RWOT); >> + } >> + >> ssp_write_reg(ssp, SSCR0, sscr0); >> >> switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { >> @@ -625,14 +660,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, >> break; >> } >> >> - /* When we use a network mode, we always require TDM slots >> - * - complain loudly and fail if they've not been set up yet. >> - */ >> - if ((sscr0 & SSCR0_MOD) && !ttsa) { >> - dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); >> - return -EINVAL; >> - } >> - >> dump_registers(ssp); >> >> return 0; >> diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c >> index e1a920c..69becf2 100644 >> --- a/sound/soc/soc-core.c >> +++ b/sound/soc/soc-core.c >> @@ -2133,17 +2133,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); >> /** >> * snd_soc_dai_set_tdm_slot - configure DAI TDM. >> * @dai: DAI >> - * @mask: DAI specific mask representing used slots. >> + * @tx_mask: bitmask representing active TX slots. >> + * @rx_mask: bitmask representing active RX slots. >> * @slots: Number of slots in use. >> + * @frame_width: Width in bits for each slot. >> * >> * Configures a DAI for TDM operation. Both mask and slots are codec and DAI >> * specific. >> */ >> int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, >> - unsigned int mask, int slots) >> + unsigned int tx_mask, unsigned int rx_mask, int slots, int frame_width) >> { >> if (dai->ops && dai->ops->set_tdm_slot) >> - return dai->ops->set_tdm_slot(dai, mask, slots); >> + return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask, >> + slots, frame_width); >> else >> return -EINVAL; >> } >> >> -- >> Daniel Ribeiro >> > > > > -- > Paul Shen > regards Philipp _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel