[alsa-devel] [PATCH] ASoC: Automatically set TDM if needed on pxa-ssp and allow frame width override when using TDM.
* 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@gmail.com
--- 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;
- /* 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; }
2009/6/10 Daniel Ribeiro drwyrm@gmail.com:
- 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@gmail.com
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?
- /* 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
On Wed, Jun 10, 2009 at 1:44 PM, Paul Shenboshen9@gmail.com wrote:
2009/6/10 Daniel Ribeiro drwyrm@gmail.com:
- 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@gmail.com
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
Em Qua, 2009-06-10 às 14:05 +0200, pHilipp Zabel escreveu:
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.
Ack.
Naming it frame_width was not a good idea. Im using frame_width for the distance between each SFRM assertion when not networked and for the duration of each slot when networked. I will name it slot_width instead.
Em Qua, 2009-06-10 às 19:44 +0800, Paul Shen escreveu:
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
No, the example above would be DataSize(32), SFRMWDTH(16). (LEFT_J?)
Or it could be DataSize(16) and 2 active TDM Slots.
But the point here is to not use SSCR0_MOD when its not needed (sample * chn <= 32), we need to support real networked configurations, set_tdm_slot() should only be called if you are really using network mode. eg:
set_tdm_slots(3, 2) shouldn't ever be needed.
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?
Sure you can waste bitclocks.. But we should try to only waste bitclocks when it is really needed, eg for I2S. The patch is not considering I2S yet.
On Tue, Jun 09, 2009 at 02:13:10PM -0300, Daniel Ribeiro wrote:
- 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()
Please split out the API change from the use of it in the PXA SSP driver - just include enough to keep it building, then send a second patch changing the internals of the SSP driver. At the minute there's two different changes in here.
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:
This is wrong, the WM9081 is a DAC only part so it should be paying attention to the RX mask, not the TX one. We also need to handle the sample size here.
I've not checked the SSP code yet.
Em Qua, 2009-06-10 às 13:18 +0100, Mark Brown escreveu:
Please split out the API change from the use of it in the PXA SSP driver
- just include enough to keep it building, then send a second patch
changing the internals of the SSP driver. At the minute there's two different changes in here.
Ok.
This is wrong, the WM9081 is a DAC only part so it should be paying attention to the RX mask, not the TX one. We also need to handle the sample size here.
Ok, but I dont know how to handle slot_width for wm9081. Is a FIXME comment here enough for a first version? Its hard for me to get this working correctly on wm9081 as I dont have such hardware and PCAP2 only supports 16bits slots.
I've not checked the SSP code yet.
On Wed, Jun 10, 2009 at 11:39:54AM -0300, Daniel Ribeiro wrote:
Em Qua, 2009-06-10 às 13:18 +0100, Mark Brown escreveu:
This is wrong, the WM9081 is a DAC only part so it should be paying attention to the RX mask, not the TX one. We also need to handle the sample size here.
Ok, but I dont know how to handle slot_width for wm9081. Is a FIXME comment here enough for a first version? Its hard for me to get this working correctly on wm9081 as I dont have such hardware and PCAP2 only supports 16bits slots.
The sample size code from the hw_params() function should be copied in here and the sample size remembered in the wm9081_priv structure. Then in hw_params() the sample size would get ignored if one had been configured via set_tdm_slot(). A size of zero should be supported there to allow dropping of TDM mode.
On Wed, Jun 10, 2009 at 11:39:54AM -0300, Daniel Ribeiro wrote:
Ok, but I dont know how to handle slot_width for wm9081. Is a FIXME comment here enough for a first version? Its hard for me to get this working correctly on wm9081 as I dont have such hardware and PCAP2 only supports 16bits slots.
Oh, and it's probably OK if you just leave bits of this undone - I'll amend the code before applying it.
2009/6/9 Daniel Ribeiro drwyrm@gmail.com:
- 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@gmail.com
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);
This will have to depend on the sample width. For S24_LE/S32_LE, slot_width should be 32. Also the rx mask could be empty, the SSP link is tx only on magician
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;
- /* 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
participants (4)
-
Daniel Ribeiro
-
Mark Brown
-
Paul Shen
-
pHilipp Zabel