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