Em Qui, 2009-06-11 às 21:34 +0800, Eric Miao escreveu: > > We already use FSRT for DSP_A, and if this works on littleton I2S we > > should just stick with FSRT (and frame_width = sample_width * channels) > > to keep the code simple. > > > > I hope so, but the assumption of frame_width == sample_width * 2 should > hold true first. Ok, here is what I think that should work for I2S after my 2 patches to sort the TDM thing. 2 Patches are inline, first version assumes that frame_width = sample_width * 2(channels), and just increases the SFRM duration to emulate the LRCLK. Second version uses Eric and Paul code only for pxa3xx. In this version, frame_width = sample_width * 2(channels) * 2(envelope). This was only compile tested, I dont have PXA3XX hardware to test this. It applies after the 3 patches I sent earlier. First version: --- sound/soc/pxa/pxa-ssp.c | 76 ++++++++++++++++------------------------------- 1 files changed, 26 insertions(+), 50 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 7e72c41..631eca4 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -487,17 +487,14 @@ 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_PSP; - sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; - /* See hw_params() */ - break; - case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_I2S: sspsp |= SSPSP_FSRT; case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_LEFT_J: sscr0 |= SSCR0_PSP; sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; + /* See hw_params() for I2S and LEFT_J */ break; default: @@ -565,6 +562,29 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, sscr0 |= SSCR0_FPCKE; #endif + switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + /* + * We can't support network mode with I2S or LEFT_J, + * SSPFRM is asserted only for the first slot. + */ + if (frame_width == 0 || chn > 2) + return -EINVAL; + + /* + * I2S and LEFT_J are stereo only, we have to send data for + * both channels. + */ + if (chn == 1) + frame_width *= 2; + + sspsp |= SSPSP_SFRMWDTH(frame_width / 2); + break; + default: + break; + } + if (frame_width > 0) { /* Not using network mode */ if (frame_width > 16) @@ -602,50 +622,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, ssp_write_reg(ssp, SSCR0, sscr0); - switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - sspsp = ssp_read_reg(ssp, SSPSP); - - if ((ssp_get_scr(ssp) == 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; - } - dump_registers(ssp); return 0; -- tg: (99ef28c..) asoc/leftj-and-i2s (depends on: asoc/ssp-internals) Second version: --- arch/arm/mach-pxa/include/mach/regs-ssp.h | 14 ++-- sound/soc/pxa/pxa-ssp.c | 99 ++++++++++++++--------------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/arch/arm/mach-pxa/include/mach/regs-ssp.h b/arch/arm/mach-pxa/include/mach/regs-ssp.h index 6a2ed35..060e23b 100644 --- a/arch/arm/mach-pxa/include/mach/regs-ssp.h +++ b/arch/arm/mach-pxa/include/mach/regs-ssp.h @@ -108,21 +108,21 @@ #define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */ #define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */ -#if defined(CONFIG_PXA3xx) -#define SSPSP_EDMYSTOP(x) ((x) << 28) /* Extended Dummy Stop */ -#define SSPSP_EDMYSTRT(x) ((x) << 26) /* Extended Dummy Start */ -#endif - #define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */ -#define SSPSP_DMYSTOP(x) ((x) << 23) /* Dummy Stop */ #define SSPSP_SFRMWDTH(x) ((x) << 16) /* Serial Frame Width */ #define SSPSP_SFRMDLY(x) ((x) << 9) /* Serial Frame Delay */ -#define SSPSP_DMYSTRT(x) ((x) << 7) /* Dummy Start */ #define SSPSP_STRTDLY(x) ((x) << 4) /* Start Delay */ #define SSPSP_ETDS (1 << 3) /* End of Transfer data State */ #define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */ #define SSPSP_SCMODE(x) ((x) << 0) /* Serial Bit Rate Clock Mode */ +/* NOTE: PXA3xx extends the bit number of dummy start and stop, the macros + * below are compatible with PXA25x/27x as long as the parameter is within + * the correct limits, driver code has to take care of this. + */ +#define SSPSP_DMYSTRT(x) ((((x) & 3) << 7) | ((((x) >> 2) & 3) << 26)) +#define SSPSP_DMYSTOP(x) ((((x) & 3) << 23) | ((((x) >> 2) & 7) << 28)) + #define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */ #define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */ #define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */ diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 7e72c41..a14ce77 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -487,17 +487,14 @@ 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_PSP; - sscr1 |= SSCR1_RWOT | SSCR1_TRAIL; - /* See hw_params() */ - break; - case SND_SOC_DAIFMT_DSP_A: sspsp |= SSPSP_FSRT; case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_I2S: sscr0 |= SSCR0_PSP; sscr1 |= SSCR1_TRAIL | SSCR1_RWOT; + /* See hw_params() for I2S and LEFT_J */ break; default: @@ -565,6 +562,52 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, sscr0 |= SSCR0_FPCKE; #endif + switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* + * We can't support network mode with I2S or LEFT_J, + * SSPFRM is asserted only for the first slot. + */ + if (frame_width == 0 || chn > 2) + return -EINVAL; + + /* + * I2S and LEFT_J are stereo only, we have to send data for + * both channels. + */ + if (chn == 1) + frame_width *= 2; + + /* For pxa2xx we have to stick with FSRT */ + if (cpu_is_pxa25x() || cpu_is_pxa27x()) + sspsp |= SSPSP_FSRT; + + /* For pxa3xx we use Paul's code */ + if (cpu_is_pxa3xx()) { + /* We double the frame_width to envelope the sample */ + frame_width *= 2; + + sspsp |= SSPSP_DMYSTRT(1); + sspsp |= SSPSP_DMYSTOP(frame_width / 2 - width - 1); + sspsp |= SSPSP_SFRMWDTH(frame_width / 2); + } + + break; + + case SND_SOC_DAIFMT_LEFT_J: + if (frame_width == 0 || chn > 2) + return -EINVAL; + + if (chn == 1) + frame_width *= 2; + + /* No need to envelope the frame for LEFT_J */ + sspsp |= SSPSP_SFRMWDTH(frame_width / 2); + break; + default: + break; + } + if (frame_width > 0) { /* Not using network mode */ if (frame_width > 16) @@ -602,50 +645,6 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, ssp_write_reg(ssp, SSCR0, sscr0); - switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - sspsp = ssp_read_reg(ssp, SSPSP); - - if ((ssp_get_scr(ssp) == 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; - } - dump_registers(ssp); return 0; -- tg: (99ef28c..) asoc/leftj-and-i2s (depends on: asoc/ssp-internals) -- Daniel Ribeiro
Attachment:
signature.asc
Description: Esta =?ISO-8859-1?Q?=E9?= uma parte de mensagem assinada digitalmente
_______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel