diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-12-10 14:17:08 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-12-11 07:43:52 -0500 |
commit | 69fff9bbbc4d214ed22c8f89681af3871a128e35 (patch) | |
tree | fea11cd4718dfaa998add11a87e8f8eb5cd7b761 /sound/soc/codecs/wm8903.c | |
parent | f2c1fe090093ed62271473342f093df53c4f8a59 (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.c | 82 |
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 | ||
463 | static int wm8903_deemph[] = { 0, 32000, 44100, 48000 }; | ||
464 | |||
465 | static 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 | |||
494 | static 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 | |||
505 | static 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 */ |
461 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | 530 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); |
462 | 531 | ||
@@ -548,13 +617,6 @@ static const char *mute_mode_text[] = { | |||
548 | static const struct soc_enum mute_mode = | 617 | static 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 | ||
551 | static const char *dac_deemphasis_text[] = { | ||
552 | "Disabled", "32kHz", "44.1kHz", "48kHz" | ||
553 | }; | ||
554 | |||
555 | static const struct soc_enum dac_deemphasis = | ||
556 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 1, 4, dac_deemphasis_text); | ||
557 | |||
558 | static const char *companding_text[] = { | 620 | static 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, | |||
662 | SOC_ENUM("DAC Soft Mute Rate", soft_mute), | 724 | SOC_ENUM("DAC Soft Mute Rate", soft_mute), |
663 | SOC_ENUM("DAC Mute Mode", mute_mode), | 725 | SOC_ENUM("DAC Mute Mode", mute_mode), |
664 | SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), | 726 | SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0), |
665 | SOC_ENUM("DAC De-emphasis", dac_deemphasis), | ||
666 | SOC_ENUM("DAC Companding Mode", dac_companding), | 727 | SOC_ENUM("DAC Companding Mode", dac_companding), |
667 | SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), | 728 | SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0), |
729 | SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0, | ||
730 | wm8903_get_deemph, wm8903_put_deemph), | ||
668 | 731 | ||
669 | /* Headphones */ | 732 | /* Headphones */ |
670 | SOC_DOUBLE_R("Headphone Switch", | 733 | SOC_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); |