diff options
author | Shengjiu Wang <b02247@freescale.com> | 2014-07-02 05:24:45 -0400 |
---|---|---|
committer | Shengjiu Wang <b02247@freescale.com> | 2014-07-03 07:18:47 -0400 |
commit | 6b6b0f49dadbb2fa312f6ea29af0918f0da74f93 (patch) | |
tree | f615a6077e6b65ac9f233d629e3bcbbef843b4a9 /sound/soc/codecs | |
parent | edcbe8af9bd3a0c0f7db321da94a1cc6ffbea293 (diff) |
ENGR00320849-1 ASoC: cs4xx8: fix the setting of Functional mode
Failed case:
arecord -Dhw:0,1 -f S16_LE -r 96000 -c 2 -traw | aplay -Dhw:0,0 -f
S16_LE -r 96000 -c 2 -traw.
There is no sound when use this case.The reason is that the setting
of Functional mode is not correct.
Signed-off-by: Shengjiu Wang <b02247@freescale.com>
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/cs42xx8.c | 108 |
1 files changed, 89 insertions, 19 deletions
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 561a35b0b58f..1cd0aa42dfec 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c | |||
@@ -44,6 +44,7 @@ struct cs42xx8_priv { | |||
44 | 44 | ||
45 | bool slave_mode; | 45 | bool slave_mode; |
46 | unsigned long sysclk; | 46 | unsigned long sysclk; |
47 | int rate[2]; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* -127.5dB to 0dB with step of 0.5dB */ | 50 | /* -127.5dB to 0dB with step of 0.5dB */ |
@@ -185,21 +186,18 @@ static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = { | |||
185 | }; | 186 | }; |
186 | 187 | ||
187 | struct cs42xx8_ratios { | 188 | struct cs42xx8_ratios { |
188 | unsigned int ratio; | 189 | unsigned int mfreq; |
189 | unsigned char speed; | 190 | unsigned int min_mclk; |
190 | unsigned char mclk; | 191 | unsigned int max_mclk; |
192 | unsigned int ratio[3]; | ||
191 | }; | 193 | }; |
192 | 194 | ||
193 | static const struct cs42xx8_ratios cs42xx8_ratios[] = { | 195 | static const struct cs42xx8_ratios cs42xx8_ratios[] = { |
194 | { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) }, | 196 | { 0, 1029000, 12800000, {256, 128, 64} }, |
195 | { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) }, | 197 | { 2, 1536000, 19200000, {384, 192, 96} }, |
196 | { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) }, | 198 | { 4, 2048000, 25600000, {512, 256, 128} }, |
197 | { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) }, | 199 | { 6, 3072000, 38400000, {768, 384, 192} }, |
198 | { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) }, | 200 | { 8, 4096000, 51200000, {1024, 512, 256} }, |
199 | { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) }, | ||
200 | { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) }, | ||
201 | { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) }, | ||
202 | { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) } | ||
203 | }; | 201 | }; |
204 | 202 | ||
205 | static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 203 | static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
@@ -267,12 +265,67 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, | |||
267 | struct snd_soc_codec *codec = rtd->codec; | 265 | struct snd_soc_codec *codec = rtd->codec; |
268 | struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); | 266 | struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); |
269 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 267 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
270 | u32 ratio = cs42xx8->sysclk / params_rate(params); | 268 | u32 rate = params_rate(params); |
269 | u32 ratio_tx, ratio_rx; | ||
270 | u32 rate_tx, rate_rx; | ||
271 | u32 fm_tx, fm_rx; | ||
271 | u32 i, fm, val, mask; | 272 | u32 i, fm, val, mask; |
272 | 273 | ||
273 | for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { | 274 | rate_tx = tx ? rate : cs42xx8->rate[0]; |
274 | if (cs42xx8_ratios[i].ratio == ratio) | 275 | rate_rx = tx ? cs42xx8->rate[1] : rate; |
275 | break; | 276 | |
277 | ratio_tx = rate_tx > 0 ? cs42xx8->sysclk / rate_tx : 0; | ||
278 | ratio_rx = rate_rx > 0 ? cs42xx8->sysclk / rate_rx : 0; | ||
279 | |||
280 | if (cs42xx8->slave_mode) { | ||
281 | fm_rx = CS42XX8_FM_AUTO; | ||
282 | fm_tx = CS42XX8_FM_AUTO; | ||
283 | } else { | ||
284 | if (rate_tx >= 0 && rate_tx < 50000) | ||
285 | fm_tx = CS42XX8_FM_SINGLE; | ||
286 | else if (rate_tx > 50000 && rate_tx < 100000) | ||
287 | fm_tx = CS42XX8_FM_DOUBLE; | ||
288 | else if (rate_tx > 100000 && rate_tx < 200000) | ||
289 | fm_tx = CS42XX8_FM_QUAD; | ||
290 | else { | ||
291 | dev_err(codec->dev, "unsupported sample rate or rate combine\n"); | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | |||
295 | if (rate_rx >= 0 && rate_rx < 50000) | ||
296 | fm_rx = CS42XX8_FM_SINGLE; | ||
297 | else if (rate_rx > 50000 && rate_rx < 100000) | ||
298 | fm_rx = CS42XX8_FM_DOUBLE; | ||
299 | else if (rate_rx > 100000 && rate_rx < 200000) | ||
300 | fm_rx = CS42XX8_FM_QUAD; | ||
301 | else { | ||
302 | dev_err(codec->dev, "unsupported sample rate or rate combine\n"); | ||
303 | return -EINVAL; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | fm = tx ? fm_tx : fm_rx; | ||
308 | |||
309 | if (fm == CS42XX8_FM_AUTO) { | ||
310 | for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { | ||
311 | if ((ratio_tx > 0 ? (cs42xx8_ratios[i].ratio[0] == ratio_tx || | ||
312 | cs42xx8_ratios[i].ratio[1] == ratio_tx || | ||
313 | cs42xx8_ratios[i].ratio[2] == ratio_tx) : true) && | ||
314 | (ratio_rx > 0 ? (cs42xx8_ratios[i].ratio[0] == ratio_rx || | ||
315 | cs42xx8_ratios[i].ratio[1] == ratio_rx || | ||
316 | cs42xx8_ratios[i].ratio[2] == ratio_rx) : true) && | ||
317 | cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk && | ||
318 | cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk) | ||
319 | break; | ||
320 | } | ||
321 | } else { | ||
322 | for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { | ||
323 | if ((ratio_tx > 0 ? (cs42xx8_ratios[i].ratio[fm_tx] == ratio_tx) : true) && | ||
324 | (ratio_rx > 0 ? (cs42xx8_ratios[i].ratio[fm_rx] == ratio_rx) : true) && | ||
325 | cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk && | ||
326 | cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk) | ||
327 | break; | ||
328 | } | ||
276 | } | 329 | } |
277 | 330 | ||
278 | if (i == ARRAY_SIZE(cs42xx8_ratios)) { | 331 | if (i == ARRAY_SIZE(cs42xx8_ratios)) { |
@@ -280,10 +333,10 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, | |||
280 | return -EINVAL; | 333 | return -EINVAL; |
281 | } | 334 | } |
282 | 335 | ||
283 | mask = CS42XX8_FUNCMOD_MFREQ_MASK; | 336 | cs42xx8->rate[substream->stream] = rate; |
284 | val = cs42xx8_ratios[i].mclk; | ||
285 | 337 | ||
286 | fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed; | 338 | mask = CS42XX8_FUNCMOD_MFREQ_MASK; |
339 | val = cs42xx8_ratios[i].mfreq; | ||
287 | 340 | ||
288 | regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, | 341 | regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, |
289 | CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask, | 342 | CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask, |
@@ -292,6 +345,22 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, | |||
292 | return 0; | 345 | return 0; |
293 | } | 346 | } |
294 | 347 | ||
348 | static int cs42xx8_hw_free(struct snd_pcm_substream *substream, | ||
349 | struct snd_soc_dai *dai) | ||
350 | { | ||
351 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
352 | struct snd_soc_codec *codec = rtd->codec; | ||
353 | struct cs42xx8_priv *cs42xx8 = snd_soc_codec_get_drvdata(codec); | ||
354 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
355 | |||
356 | cs42xx8->rate[substream->stream] = 0; | ||
357 | |||
358 | regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, | ||
359 | CS42XX8_FUNCMOD_xC_FM_MASK(tx), | ||
360 | CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO)); | ||
361 | return 0; | ||
362 | } | ||
363 | |||
295 | static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute) | 364 | static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute) |
296 | { | 365 | { |
297 | struct snd_soc_codec *codec = dai->codec; | 366 | struct snd_soc_codec *codec = dai->codec; |
@@ -307,6 +376,7 @@ static const struct snd_soc_dai_ops cs42xx8_dai_ops = { | |||
307 | .set_fmt = cs42xx8_set_dai_fmt, | 376 | .set_fmt = cs42xx8_set_dai_fmt, |
308 | .set_sysclk = cs42xx8_set_dai_sysclk, | 377 | .set_sysclk = cs42xx8_set_dai_sysclk, |
309 | .hw_params = cs42xx8_hw_params, | 378 | .hw_params = cs42xx8_hw_params, |
379 | .hw_free = cs42xx8_hw_free, | ||
310 | .digital_mute = cs42xx8_digital_mute, | 380 | .digital_mute = cs42xx8_digital_mute, |
311 | }; | 381 | }; |
312 | 382 | ||