cs4270: wrong sample rate when CONFIG_SND_SOC_CS4270_VD33_ERRATA is set
Subsystems (3)
PATCH 1/1 cs4270: wrong sample rate when CONFIG_SND_SOC_CS4270_VD33_ERRATA is set
When CONFIG_SND_SOC_CS4270_VD33_ERRATA is set, there was a mismatch between the mclk_ratios[] and cs4270_mode_ratios[] arrays. The two arrays have been merged and code has been shuffled. One side effect is that the cs4270_set_dai_sysclk() and cs4270_set_dai_fmt() functions are available only if I2C has been enabled.
--- sound/soc/codecs/cs4270.c | 261 ++++++++++++++++++++++----------------------- 1 files changed, 128 insertions(+), 133 deletions(-)
sound/soc/codecs/cs4270.c +128 -133
@@ -48,12 +48,130 @@ struct cs4270_private {unsigned int mode;/* The mode (I2S or left-justified) */ }; -/* The number of MCLK/LRCK ratios supported by the CS4270 */ -#define NUM_MCLK_RATIOS 9 +/* +* The codec isn't really big-endian or little-endian, since the I2S +* interface requires data to be sent serially with the MSbit first. +* However, to support BE and LE I2S devices, we specify both here. That +* way, ALSA will always match the bit patterns. +*/ +#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) + +#ifdef USE_I2C + +/* CS4270 registers addresses */ +#define CS4270_CHIPID 0x01/* Chip ID */ +#define CS4270_PWRCTL 0x02/* Power Control */ +#define CS4270_MODE 0x03/* Mode Control */ +#define CS4270_FORMAT 0x04/* Serial Format, ADC/DAC Control */ +#define CS4270_TRANS 0x05/* Transition Control */ +#define CS4270_MUTE 0x06/* Mute Control */ +#define CS4270_VOLA 0x07/* DAC Channel A Volume Control */ +#define CS4270_VOLB 0x08/* DAC Channel B Volume Control */ + +#define CS4270_FIRSTREG 0x01 +#define CS4270_LASTREG 0x08 +#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) -/* The actual MCLK/LRCK ratios, in increasing numerical order */ -static unsigned int mclk_ratios[NUM_MCLK_RATIOS ] = - {64 ,96 ,128 ,192 ,256 ,384 ,512 ,768 ,1024 }; +/* Bit masks for the CS4270 registers */ +#define CS4270_CHIPID_ID 0xF0 +#define CS4270_CHIPID_REV 0x0F +#define CS4270_PWRCTL_FREEZE 0x80 +#define CS4270_PWRCTL_PDN_ADC 0x20 +#define CS4270_PWRCTL_PDN_DAC 0x02 +#define CS4270_PWRCTL_PDN 0x01 +#define CS4270_MODE_SPEED_MASK 0x30 +#define CS4270_MODE_1X 0x00 +#define CS4270_MODE_2X 0x10 +#define CS4270_MODE_4X 0x20 +#define CS4270_MODE_SLAVE 0x30 +#define CS4270_MODE_DIV_MASK 0x0E +#define CS4270_MODE_DIV1 0x00 +#define CS4270_MODE_DIV15 0x02 +#define CS4270_MODE_DIV2 0x04 +#define CS4270_MODE_DIV3 0x06 +#define CS4270_MODE_DIV4 0x08 +#define CS4270_MODE_POPGUARD 0x01 +#define CS4270_FORMAT_FREEZE_A 0x80 +#define CS4270_FORMAT_FREEZE_B 0x40 +#define CS4270_FORMAT_LOOPBACK 0x20 +#define CS4270_FORMAT_DAC_MASK 0x18 +#define CS4270_FORMAT_DAC_LJ 0x00 +#define CS4270_FORMAT_DAC_I2S 0x08 +#define CS4270_FORMAT_DAC_RJ16 0x18 +#define CS4270_FORMAT_DAC_RJ24 0x10 +#define CS4270_FORMAT_ADC_MASK 0x01 +#define CS4270_FORMAT_ADC_LJ 0x00 +#define CS4270_FORMAT_ADC_I2S 0x01 +#define CS4270_TRANS_ONE_VOL 0x80 +#define CS4270_TRANS_SOFT 0x40 +#define CS4270_TRANS_ZERO 0x20 +#define CS4270_TRANS_INV_ADC_A 0x08 +#define CS4270_TRANS_INV_ADC_B 0x10 +#define CS4270_TRANS_INV_DAC_A 0x02 +#define CS4270_TRANS_INV_DAC_B 0x04 +#define CS4270_TRANS_DEEMPH 0x01 +#define CS4270_MUTE_AUTO 0x20 +#define CS4270_MUTE_ADC_A 0x08 +#define CS4270_MUTE_ADC_B 0x10 +#define CS4270_MUTE_POLARITY 0x04 +#define CS4270_MUTE_DAC_A 0x01 +#define CS4270_MUTE_DAC_B 0x02 + +/* +* Clock Ratio Selection for Master Mode with I2C enabled +* +* The data for this chart is taken from Table 5 of the CS4270 reference +* manual. +* +* This table is used to determine how to program the Mode Control register. +* It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling +* rates the CS4270 currently supports. +* +* Each element in this array corresponds to the ratios in mclk_ratios[]. +* These two arrays need to be in sync. +* +* 'speed_mode' is the corresponding bit pattern to be written to the +* MODE bits of the Mode Control Register +* +* 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of +* the Mode Control Register. +* +* In situations where a single ratio is represented by multiple speed +* modes, we favor the slowest speed. E.g, for a ratio of 128, we pick +* double-speed instead of quad-speed. However, the CS4270 errata states +* that Divide-By-1.5 can cause failures, so we avoid that mode where +* possible. +* +* ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not +* work if VD = 3.3V. If this effects you, select the +* CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will +* never select any sample rates that require divide-by-1.5. +*/ +static struct { +unsigned int ratio; +u8 speed_mode; +u8 mclk; +} cs4270_mode_ratios[] = { + {64 ,CS4270_MODE_4X ,CS4270_MODE_DIV1 }, +#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA + {96 ,CS4270_MODE_4X ,CS4270_MODE_DIV15 }, +#endif + {128 ,CS4270_MODE_2X ,CS4270_MODE_DIV1 }, + {192 ,CS4270_MODE_4X ,CS4270_MODE_DIV3 }, + {256 ,CS4270_MODE_1X ,CS4270_MODE_DIV1 }, + {384 ,CS4270_MODE_2X ,CS4270_MODE_DIV3 }, + {512 ,CS4270_MODE_1X ,CS4270_MODE_DIV2 }, + {768 ,CS4270_MODE_1X ,CS4270_MODE_DIV3 }, + {1024 ,CS4270_MODE_1X ,CS4270_MODE_DIV4 } +}; + +/* The number of MCLK/LRCK ratios supported by the CS4270 */ +#define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios)/* * Determine the CS4270 samples rates.
@@ -97,7 +215,7 @@ static int cs4270_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, cs4270->mclk = freq;for (i =0 ; i <NUM_MCLK_RATIOS ; i++) { -unsigned int rate = freq / mclk_ratios[i]; +unsigned int rate = freq / cs4270_mode_ratios[i].ratio; rates |=snd_pcm_rate_to_rate_bit (rate);if (rate < rate_min) rate_min = rate;
@@ -155,80 +273,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, }/* -* The codec isn't really big-endian or little-endian, since the I2S -* interface requires data to be sent serially with the MSbit first. -* However, to support BE and LE I2S devices, we specify both here. That -* way, ALSA will always match the bit patterns. -*/ -#define CS4270_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ - SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ - SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) - -#ifdef USE_I2C - -/* CS4270 registers addresses */ -#define CS4270_CHIPID 0x01/* Chip ID */ -#define CS4270_PWRCTL 0x02/* Power Control */ -#define CS4270_MODE 0x03/* Mode Control */ -#define CS4270_FORMAT 0x04/* Serial Format, ADC/DAC Control */ -#define CS4270_TRANS 0x05/* Transition Control */ -#define CS4270_MUTE 0x06/* Mute Control */ -#define CS4270_VOLA 0x07/* DAC Channel A Volume Control */ -#define CS4270_VOLB 0x08/* DAC Channel B Volume Control */ - -#define CS4270_FIRSTREG 0x01 -#define CS4270_LASTREG 0x08 -#define CS4270_NUMREGS (CS4270_LASTREG - CS4270_FIRSTREG + 1) - -/* Bit masks for the CS4270 registers */ -#define CS4270_CHIPID_ID 0xF0 -#define CS4270_CHIPID_REV 0x0F -#define CS4270_PWRCTL_FREEZE 0x80 -#define CS4270_PWRCTL_PDN_ADC 0x20 -#define CS4270_PWRCTL_PDN_DAC 0x02 -#define CS4270_PWRCTL_PDN 0x01 -#define CS4270_MODE_SPEED_MASK 0x30 -#define CS4270_MODE_1X 0x00 -#define CS4270_MODE_2X 0x10 -#define CS4270_MODE_4X 0x20 -#define CS4270_MODE_SLAVE 0x30 -#define CS4270_MODE_DIV_MASK 0x0E -#define CS4270_MODE_DIV1 0x00 -#define CS4270_MODE_DIV15 0x02 -#define CS4270_MODE_DIV2 0x04 -#define CS4270_MODE_DIV3 0x06 -#define CS4270_MODE_DIV4 0x08 -#define CS4270_MODE_POPGUARD 0x01 -#define CS4270_FORMAT_FREEZE_A 0x80 -#define CS4270_FORMAT_FREEZE_B 0x40 -#define CS4270_FORMAT_LOOPBACK 0x20 -#define CS4270_FORMAT_DAC_MASK 0x18 -#define CS4270_FORMAT_DAC_LJ 0x00 -#define CS4270_FORMAT_DAC_I2S 0x08 -#define CS4270_FORMAT_DAC_RJ16 0x18 -#define CS4270_FORMAT_DAC_RJ24 0x10 -#define CS4270_FORMAT_ADC_MASK 0x01 -#define CS4270_FORMAT_ADC_LJ 0x00 -#define CS4270_FORMAT_ADC_I2S 0x01 -#define CS4270_TRANS_ONE_VOL 0x80 -#define CS4270_TRANS_SOFT 0x40 -#define CS4270_TRANS_ZERO 0x20 -#define CS4270_TRANS_INV_ADC_A 0x08 -#define CS4270_TRANS_INV_ADC_B 0x10 -#define CS4270_TRANS_INV_DAC_A 0x02 -#define CS4270_TRANS_INV_DAC_B 0x04 -#define CS4270_TRANS_DEEMPH 0x01 -#define CS4270_MUTE_AUTO 0x20 -#define CS4270_MUTE_ADC_A 0x08 -#define CS4270_MUTE_ADC_B 0x10 -#define CS4270_MUTE_POLARITY 0x04 -#define CS4270_MUTE_DAC_A 0x01 -#define CS4270_MUTE_DAC_B 0x02 - -/* * A list of addresses on which this CS4270 could use. I2C addresses are * 7 bits. For the CS4270, the upper four bits are always 1001, and the * lower three bits are determined via the AD2, AD1, and AD0 pins
@@ -315,53 +359,6 @@ static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg, }/* -* Clock Ratio Selection for Master Mode with I2C enabled -* -* The data for this chart is taken from Table 5 of the CS4270 reference -* manual. -* -* This table is used to determine how to program the Mode Control register. -* It is also used by cs4270_set_dai_sysclk() to tell ALSA which sampling -* rates the CS4270 currently supports. -* -* Each element in this array corresponds to the ratios in mclk_ratios[]. -* These two arrays need to be in sync. -* -* 'speed_mode' is the corresponding bit pattern to be written to the -* MODE bits of the Mode Control Register -* -* 'mclk' is the corresponding bit pattern to be wirten to the MCLK bits of -* the Mode Control Register. -* -* In situations where a single ratio is represented by multiple speed -* modes, we favor the slowest speed. E.g, for a ratio of 128, we pick -* double-speed instead of quad-speed. However, the CS4270 errata states -* that Divide-By-1.5 can cause failures, so we avoid that mode where -* possible. -* -* ERRATA: There is an errata for the CS4270 where divide-by-1.5 does not -* work if VD = 3.3V. If this effects you, select the -* CONFIG_SND_SOC_CS4270_VD33_ERRATA Kconfig option, and the driver will -* never select any sample rates that require divide-by-1.5. -*/ -static struct { -u8 speed_mode; -u8 mclk; -} cs4270_mode_ratios[NUM_MCLK_RATIOS ] = { - {CS4270_MODE_4X ,CS4270_MODE_DIV1 },/* 64 */ -#ifndef CONFIG_SND_SOC_CS4270_VD33_ERRATA - {CS4270_MODE_4X ,CS4270_MODE_DIV15 },/* 96 */ -#endif - {CS4270_MODE_2X ,CS4270_MODE_DIV1 },/* 128 */ - {CS4270_MODE_4X ,CS4270_MODE_DIV3 },/* 192 */ - {CS4270_MODE_1X ,CS4270_MODE_DIV1 },/* 256 */ - {CS4270_MODE_2X ,CS4270_MODE_DIV3 },/* 384 */ - {CS4270_MODE_1X ,CS4270_MODE_DIV2 },/* 512 */ - {CS4270_MODE_1X ,CS4270_MODE_DIV3 },/* 768 */ - {CS4270_MODE_1X ,CS4270_MODE_DIV4 }/* 1024 */ -}; - -/* * Program the CS4270 with the given hardware parameters. * * The .dai_ops functions are used to provide board-specific data, like
@@ -388,7 +385,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream, ratio = cs4270->mclk / rate;/* MCLK/LRCK ratio */ for (i =0 ; i <NUM_MCLK_RATIOS ; i++) { -if (mclk_ratios[i] == ratio) +if (cs4270_mode_ratios[i].ratio == ratio)break ; }
@@ -669,7 +666,7 @@ error:return ret; } -#endif +#endif /* USE_I2C*/ struct snd_soc_codec_dai cs4270_dai = { .name ="CS4270" ,
@@ -687,10 +684,6 @@ struct snd_soc_codec_dai cs4270_dai = { .rates = 0, .formats = CS4270_FORMATS, }, - .dai_ops = { - .set_sysclk = cs4270_set_dai_sysclk, - .set_fmt = cs4270_set_dai_fmt, - } };EXPORT_SYMBOL_GPL (cs4270_dai);
@@ -752,6 +745,8 @@ static int cs4270_probe(struct platform_device *pdev)if (codec->control_data) {/* Initialize codec ops */ cs4270_dai.ops.hw_params = cs4270_hw_params; + cs4270_dai.dai_ops.set_sysclk = cs4270_set_dai_sysclk; + cs4270_dai.dai_ops.set_fmt = cs4270_set_dai_fmt;#ifdef CONFIG_SND_SOC_CS4270_HWMUTE cs4270_dai.dai_ops.digital_mute = cs4270_mute;#endif
Signature · 1 line
1.5.2.4
Takashi Iwai
AppliedAt Mon, 17 Dec 2007 11:01:20 -0600,
Quoted 8 lines · Timur Tabi
When
CONFIG_SND_SOC_CS4270_VD33_ERRATAis set, there was a mismatch between the mclk_ratios[] and cs4270_mode_ratios[] arrays. The two arrays have been merged and code has been shuffled. One side effect is that thecs4270_set_dai_sysclk()andcs4270_set_dai_fmt()functions are available only if I2C has been enabled.Signed-off-by Timur Tabi <[email protected]>
Applied to ALSA HG tree. Thanks.
Takashi