aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs
diff options
context:
space:
mode:
authorShengjiu Wang <b02247@freescale.com>2014-07-02 05:24:45 -0400
committerShengjiu Wang <b02247@freescale.com>2014-07-03 07:18:47 -0400
commit6b6b0f49dadbb2fa312f6ea29af0918f0da74f93 (patch)
treef615a6077e6b65ac9f233d629e3bcbbef843b4a9 /sound/soc/codecs
parentedcbe8af9bd3a0c0f7db321da94a1cc6ffbea293 (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.c108
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
187struct cs42xx8_ratios { 188struct 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
193static const struct cs42xx8_ratios cs42xx8_ratios[] = { 195static 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
205static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, 203static 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
348static 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
295static int cs42xx8_digital_mute(struct snd_soc_dai *dai, int mute) 364static 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