diff options
| -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); |
