aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8903.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-12-10 14:17:08 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-12-11 07:43:52 -0500
commit69fff9bbbc4d214ed22c8f89681af3871a128e35 (patch)
treefea11cd4718dfaa998add11a87e8f8eb5cd7b761 /sound/soc/codecs/wm8903.c
parentf2c1fe090093ed62271473342f093df53c4f8a59 (diff)
ASoC: Automatically manage WM8903 deemphasis rate
Provide the user with a boolean control then automatically select the deemphasis filter most closely matching the sample rate. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm8903.c')
-rw-r--r--sound/soc/codecs/wm8903.c82
1 files changed, 74 insertions, 8 deletions
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index f9ae403715c6..d015745a886b 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -218,6 +218,9 @@ struct wm8903_priv {
218 int sysclk; 218 int sysclk;
219 int irq; 219 int irq;
220 220
221 int fs;
222 int deemph;
223
221 /* Reference count */ 224 /* Reference count */
222 int class_w_users; 225 int class_w_users;
223 226
@@ -457,6 +460,72 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
457 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } 460 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
458 461
459 462
463static int wm8903_deemph[] = { 0, 32000, 44100, 48000 };
464
465static int wm8903_set_deemph(struct snd_soc_codec *codec)
466{
467 struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
468 int val, i, best;
469
470 /* If we're using deemphasis select the nearest available sample
471 * rate.
472 */
473 if (wm8903->deemph) {
474 best = 1;
475 for (i = 2; i < ARRAY_SIZE(wm8903_deemph); i++) {
476 if (abs(wm8903_deemph[i] - wm8903->fs) <
477 abs(wm8903_deemph[best] - wm8903->fs))
478 best = i;
479 }
480
481 val = best << WM8903_DEEMPH_SHIFT;
482 } else {
483 best = 0;
484 val = 0;
485 }
486
487 dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
488 best, wm8903_deemph[best]);
489
490 return snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1,
491 WM8903_DEEMPH_MASK, val);
492}
493
494static int wm8903_get_deemph(struct snd_kcontrol *kcontrol,
495 struct snd_ctl_elem_value *ucontrol)
496{
497 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
498 struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
499
500 ucontrol->value.enumerated.item[0] = wm8903->deemph;
501
502 return 0;
503}
504
505static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
506 struct snd_ctl_elem_value *ucontrol)
507{
508 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
509 struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
510 int deemph = ucontrol->value.enumerated.item[0];
511 int ret = 0;
512
513 if (deemph > 1)
514 return -EINVAL;
515
516 mutex_lock(&codec->mutex);
517 if (wm8903->deemph != deemph) {
518 wm8903->deemph = deemph;
519
520 wm8903_set_deemph(codec);
521
522 ret = 1;
523 }
524 mutex_unlock(&codec->mutex);
525
526 return ret;
527}
528
460/* ALSA can only do steps of .01dB */ 529/* ALSA can only do steps of .01dB */
461static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); 530static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
462 531
@@ -548,13 +617,6 @@ static const char *mute_mode_text[] = {
548static const struct soc_enum mute_mode = 617static const struct soc_enum mute_mode =
549 SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text); 618 SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text);
550 619
551static const char *dac_deemphasis_text[] = {
552 "Disabled", "32kHz", "44.1kHz", "48kHz"
553};
554
555static const struct soc_enum dac_deemphasis =
556 SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 1, 4, dac_deemphasis_text);
557
558static const char *companding_text[] = { 620static const char *companding_text[] = {
559 "ulaw", "alaw" 621 "ulaw", "alaw"
560}; 622};
@@ -662,9 +724,10 @@ SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
662SOC_ENUM("DAC Soft Mute Rate", soft_mute), 724SOC_ENUM("DAC Soft Mute Rate", soft_mute),
663SOC_ENUM("DAC Mute Mode", mute_mode), 725SOC_ENUM("DAC Mute Mode", mute_mode),
664SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), 726SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
665SOC_ENUM("DAC De-emphasis", dac_deemphasis),
666SOC_ENUM("DAC Companding Mode", dac_companding), 727SOC_ENUM("DAC Companding Mode", dac_companding),
667SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), 728SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
729SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
730 wm8903_get_deemph, wm8903_put_deemph),
668 731
669/* Headphones */ 732/* Headphones */
670SOC_DOUBLE_R("Headphone Switch", 733SOC_DOUBLE_R("Headphone Switch",
@@ -1374,6 +1437,9 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
1374 aif2 |= bclk_divs[bclk_div].div; 1437 aif2 |= bclk_divs[bclk_div].div;
1375 aif3 |= bclk / fs; 1438 aif3 |= bclk / fs;
1376 1439
1440 wm8903->fs = params_rate(params);
1441 wm8903_set_deemph(codec);
1442
1377 snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0); 1443 snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0);
1378 snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1); 1444 snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1);
1379 snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); 1445 snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);