Hi, On Tue, Mar 10, 2009 at 4:47 PM, Daniel Mack <daniel@xxxxxxxx> wrote: > On Mon, Mar 09, 2009 at 05:44:46PM +0000, Mark Brown wrote: >> On Mon, Mar 09, 2009 at 04:36:29PM +0100, Daniel Mack wrote: >> >> > Mark says he'd rather like me to use/abuse the set_clk_div() interface >> > for that but IMO that's an evil hack. The next CPU would need a similar >> > thing to be used with this codec, so there should be a clean way to >> > achive that. >> >> The point here is that this is already fairly widely supported with some >> combination of that approach and network mode and adding a third method >> only makes things more complex, especially with more flexibile devices >> which are capable of supporting combinations of these options > > Ok, there might be an even more straight-forward solution for this > problem: As we know already from the DIV_SCR divider what our > BCLK/LRCLK ratio is, we can add a special case for the mode I need, as > implemented in the patch below. > > Philipp, could you test that again on your board, please? > Applies on top of the other one ("pxa-ssp: don't touch ssp registers > ...") I just posted. Tested-by me. Of course this still doesn't help me to enable 16-bit DMA transfers for stereo, but it doesn't hurt either. > Thanks, > Daniel > > > From cbd130dfeca4d65acd34cd6a3ca6d1a45885985f Mon Sep 17 00:00:00 2001 > From: Daniel Mack <daniel@xxxxxxxx> > Date: Tue, 10 Mar 2009 16:33:35 +0100 > Subject: [PATCH 1/2] pxa-ssp: switch from network mode to PSP > > This switches the pxa ssp port usage from network mode to PSP mode. > Removed some comments and checks for configured TDM channels. > A special case is added to support configuration where BCLK = 64fs. We > need to do some black magic in this case which doesn't look nice but > there is unfortunately no other option than that. > > Signed-off-by: Daniel Mack <daniel@xxxxxxxx> > --- > sound/soc/pxa/pxa-ssp.c | 56 ++++++++++++++++++++++++++++++---------------- > 1 files changed, 36 insertions(+), 20 deletions(-) > > diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c > index 7fc13f0..1b3a81c 100644 > --- a/sound/soc/pxa/pxa-ssp.c > +++ b/sound/soc/pxa/pxa-ssp.c > @@ -45,6 +45,7 @@ > struct ssp_priv { > struct ssp_dev dev; > unsigned int sysclk; > + unsigned int scr_div; Really needed? Or could we just check SSCR0 below? > int dai_fmt; > #ifdef CONFIG_PM > struct ssp_state state; > @@ -281,11 +282,13 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) > * ssp_set_clkdiv - set SSP clock divider > * @div: serial clock rate divider > */ > -static void ssp_set_scr(struct ssp_dev *dev, u32 div) > +static void ssp_set_scr(struct ssp_priv *priv, u32 div) > { > + struct ssp_dev *dev = &priv->dev; > struct ssp_device *ssp = dev->ssp; > u32 sscr0 = ssp_read_reg(dev->ssp, SSCR0) & ~SSCR0_SCR; > > + priv->scr_div = div; > ssp_write_reg(ssp, SSCR0, (sscr0 | SSCR0_SerClkDiv(div))); > } > > @@ -327,7 +330,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, > break; > case PXA_SSP_CLK_AUDIO: > priv->sysclk = 0; > - ssp_set_scr(&priv->dev, 1); > + ssp_set_scr(priv, 1); > sscr0 |= SSCR0_ACS; > break; > default: > @@ -388,7 +391,7 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, > ssp_write_reg(ssp, SSACD, val); > break; > case PXA_SSP_DIV_SCR: > - ssp_set_scr(&priv->dev, div); > + ssp_set_scr(priv, div); > break; > default: > return -ENODEV; > @@ -547,18 +550,17 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, > > switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { > case SND_SOC_DAIFMT_I2S: > - sscr0 |= SSCR0_MOD | SSCR0_PSP; > + sscr0 |= SSCR0_PSP; > sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; > > switch (fmt & SND_SOC_DAIFMT_INV_MASK) { > case SND_SOC_DAIFMT_NB_NF: > - sspsp |= SSPSP_FSRT; > break; > case SND_SOC_DAIFMT_NB_IF: > - sspsp |= SSPSP_SFRMP | SSPSP_FSRT; > + sspsp |= SSPSP_SFRMP; > break; > case SND_SOC_DAIFMT_IB_IF: > - sspsp |= SSPSP_SFRMP; > + sspsp |= SSPSP_SFRMP | SSPSP_SCMODE(3); > break; > default: > return -EINVAL; > @@ -644,37 +646,51 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, > sscr0 |= SSCR0_FPCKE; > #endif > sscr0 |= SSCR0_DataSize(16); > - /* use network mode (2 slots) for 16 bit stereo */ > break; > case SNDRV_PCM_FORMAT_S24_LE: > sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(8)); > - /* we must be in network mode (2 slots) for 24 bit stereo */ > break; > case SNDRV_PCM_FORMAT_S32_LE: > sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16)); > - /* we must be in network mode (2 slots) for 32 bit stereo */ > break; > } > ssp_write_reg(ssp, SSCR0, sscr0); > > switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { > case SND_SOC_DAIFMT_I2S: > - /* Cleared when the DAI format is set */ > - sspsp = ssp_read_reg(ssp, SSPSP) | SSPSP_SFRMWDTH(width); > + sspsp = ssp_read_reg(ssp, SSPSP); > + > + if ((priv->scr_div == 4) && (width == 16)) { sscr0 & SSCR0_SCR == SSCR0_SerClkDiv(4) instead? Probably not, it just replaces data bloat by code bloat. > + /* This is a special case where the bitclk is 64fs > + * and we're not dealing with 2*32 bits of audio > + * samples. > + * > + * The SSP values used for that are all found out by > + * trying and failing a lot; some of the registers > + * needed for that mode are only available on PXA3xx. > + */ > + > +#ifdef CONFIG_PXA3xx > + if (!cpu_is_pxa3xx()) > + return -EINVAL; > + > + sspsp |= SSPSP_SFRMWDTH(width * 2); > + sspsp |= SSPSP_SFRMDLY(width * 4); > + sspsp |= SSPSP_EDMYSTOP(3); > + sspsp |= SSPSP_DMYSTOP(3); > + sspsp |= SSPSP_DMYSTRT(1); > +#else > + return -EINVAL; > +#endif > + } else > + sspsp |= SSPSP_SFRMWDTH(width); > + > ssp_write_reg(ssp, SSPSP, sspsp); > break; > default: > break; > } > > - /* We always use a network mode so we always require TDM slots > - * - complain loudly and fail if they've not been set up yet. > - */ > - if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { > - dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); > - return -EINVAL; > - } > - I wonder if this check was useful in some case? If so, we could replace it with something like this: @@ -667,10 +667,11 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, break; } - /* We always use a network mode so we always require TDM slots + /* If we are using a network mode, require TDM slots * - complain loudly and fail if they've not been set up yet. */ - if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { + if ((ssp_read_reg(ssp, SSCR0) & SSCR0_MOD) && + !(ssp_read_reg(ssp, SSTSA) & 0xf)) { dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); return -EINVAL; } > dump_registers(ssp); > > return 0; > -- > 1.6.2 > > regards Philipp _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel