diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-03-17 19:07:26 +0000 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-03-17 19:07:26 +0000 |
commit | da88b48b84e1a504b6a19aff9d5b8236a59e228a (patch) | |
tree | 1ec0fc6ecf51c7baf7bf6cfbd9250c3fee16a09b /sound/soc | |
parent | d2314e0e27566f8830ebed3587cc049e07e6a4ee (diff) | |
parent | 85fab7802a4bc00cc752f430e22a0d9fc41fe199 (diff) |
Merge branch 'pxa-ssp' into for-2.6.30
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/pxa/pxa-ssp.c | 55 | ||||
-rw-r--r-- | sound/soc/pxa/zylonite.c | 55 |
2 files changed, 68 insertions, 42 deletions
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index d3fa6357a9f..b0bf40973d5 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -1,4 +1,3 @@ -#define DEBUG /* * pxa-ssp.c -- ALSA Soc Audio Layer * @@ -558,18 +557,18 @@ 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; + /* See hw_params() */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: - sspsp |= SSPSP_FSRT; + sspsp |= SSPSP_SFRMP; break; case SND_SOC_DAIFMT_NB_IF: - sspsp |= SSPSP_SFRMP | SSPSP_FSRT; break; case SND_SOC_DAIFMT_IB_IF: - sspsp |= SSPSP_SFRMP; + sspsp |= SSPSP_SCMODE(3); break; default: return -EINVAL; @@ -655,33 +654,65 @@ 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 (((sscr0 & SSCR0_SCR) == SSCR0_SerClkDiv(4)) && + (width == 16)) { + /* 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 { + /* The frame width is the width the LRCLK is + * asserted for; the delay is expressed in + * half cycle units. We need the extra cycle + * because the data starts clocking out one BCLK + * after LRCLK changes polarity. + */ + sspsp |= SSPSP_SFRMWDTH(width + 1); + sspsp |= SSPSP_SFRMDLY((width + 1) * 2); + sspsp |= SSPSP_DMYSTRT(1); + } + ssp_write_reg(ssp, SSPSP, sspsp); break; default: break; } - /* We always use a network mode so we always require TDM slots + /* When we use a network mode, we always require TDM slots * - complain loudly and fail if they've not been set up yet. */ - if (!(ssp_read_reg(ssp, SSTSA) & 0xf)) { + if ((sscr0 & SSCR0_MOD) && !(ssp_read_reg(ssp, SSTSA) & 0xf)) { dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n"); return -EINVAL; } diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 9f6116edbb8..9a386b4c4ed 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -96,42 +96,35 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int pll_out = 0; - unsigned int acds = 0; unsigned int wm9713_div = 0; int ret = 0; - - switch (params_rate(params)) { + int rate = params_rate(params); + int width = snd_pcm_format_physical_width(params_format(params)); + + /* Only support ratios that we can generate neatly from the AC97 + * based master clock - in particular, this excludes 44.1kHz. + * In most applications the voice DAC will be used for telephony + * data so multiples of 8kHz will be the common case. + */ + switch (rate) { case 8000: wm9713_div = 12; - pll_out = 2048000; break; case 16000: wm9713_div = 6; - pll_out = 4096000; break; case 48000: - default: wm9713_div = 2; - pll_out = 12288000; - acds = 1; break; + default: + /* Don't support OSS emulation */ + return -EINVAL; } - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - if (ret < 0) - return ret; + /* Add 1 to the width for the leading clock cycle */ + pll_out = rate * (width + 1) * 8; - /* Use network mode for stereo, one slot per channel. */ - if (params_channels(params) > 1) - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 2); - else - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1); + ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); if (ret < 0) return ret; @@ -139,14 +132,6 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_AUDIO_DIV_ACDS, acds); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); - if (ret < 0) - return ret; - if (clk_pout) ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, WM9713_PCMDIV(wm9713_div)); @@ -156,6 +141,16 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + if (ret < 0) + return ret; + return 0; } |