aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8903.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-06-12 14:16:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-12 14:16:27 -0400
commite349792a385ed47390d156155b1a1e19af1bf163 (patch)
treef9dc4e3e42769950230eaa58ecdd056eb27b23e8 /sound/soc/codecs/wm8903.c
parent6d21491838a2a9f22843c7530b118596ee9f4d77 (diff)
parente3f86d3d3ce350144562d9bd035dc8a274fce58e (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (290 commits) ALSA: pcm - Update document about xrun_debug proc file ALSA: lx6464es - support standard alsa module parameters ALSA: snd_usb_caiaq: set mixername ALSA: hda - add quirk for STAC92xx (SigmaTel STAC9205) ALSA: use card device as parent for jack input-devices ALSA: sound/ps3: Correct existing and add missing annotations ALSA: sound/ps3: Restructure driver source ALSA: sound/ps3: Fix checkpatch issues ASoC: Fix lm4857 control ALSA: ctxfi - Clear PCM resources at hw_params and hw_free ALSA: ctxfi - Check the presence of SRC instance in PCM pointer callbacks ALSA: ctxfi - Add missing start check in atc_pcm_playback_start() ALSA: ctxfi - Add use_system_timer module option ALSA: usb - Add boot quirk for C-Media 6206 USB Audio ALSA: ctxfi - Fix wrong model id for UAA ALSA: ctxfi - Clean up probe routines ALSA: hda - Fix the previous tagra-8ch patch ALSA: hda - Add 7.1 support for MSI GX620 ALSA: pcm - A helper function to compose PCM stream name for debug prints ALSA: emu10k1 - Fix minimum periods for efx playback ...
Diffstat (limited to 'sound/soc/codecs/wm8903.c')
-rw-r--r--sound/soc/codecs/wm8903.c119
1 files changed, 78 insertions, 41 deletions
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index 8cf571f1a803..d8a9222fbf74 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -217,7 +217,6 @@ struct wm8903_priv {
217 int sysclk; 217 int sysclk;
218 218
219 /* Reference counts */ 219 /* Reference counts */
220 int charge_pump_users;
221 int class_w_users; 220 int class_w_users;
222 int playback_active; 221 int playback_active;
223 int capture_active; 222 int capture_active;
@@ -373,6 +372,15 @@ static void wm8903_reset(struct snd_soc_codec *codec)
373#define WM8903_OUTPUT_INT 0x2 372#define WM8903_OUTPUT_INT 0x2
374#define WM8903_OUTPUT_IN 0x1 373#define WM8903_OUTPUT_IN 0x1
375 374
375static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
376 struct snd_kcontrol *kcontrol, int event)
377{
378 WARN_ON(event != SND_SOC_DAPM_POST_PMU);
379 mdelay(4);
380
381 return 0;
382}
383
376/* 384/*
377 * Event for headphone and line out amplifier power changes. Special 385 * Event for headphone and line out amplifier power changes. Special
378 * power up/down sequences are required in order to maximise pop/click 386 * power up/down sequences are required in order to maximise pop/click
@@ -382,19 +390,20 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
382 struct snd_kcontrol *kcontrol, int event) 390 struct snd_kcontrol *kcontrol, int event)
383{ 391{
384 struct snd_soc_codec *codec = w->codec; 392 struct snd_soc_codec *codec = w->codec;
385 struct wm8903_priv *wm8903 = codec->private_data;
386 struct i2c_client *i2c = codec->control_data;
387 u16 val; 393 u16 val;
388 u16 reg; 394 u16 reg;
395 u16 dcs_reg;
396 u16 dcs_bit;
389 int shift; 397 int shift;
390 u16 cp_reg = wm8903_read(codec, WM8903_CHARGE_PUMP_0);
391 398
392 switch (w->reg) { 399 switch (w->reg) {
393 case WM8903_POWER_MANAGEMENT_2: 400 case WM8903_POWER_MANAGEMENT_2:
394 reg = WM8903_ANALOGUE_HP_0; 401 reg = WM8903_ANALOGUE_HP_0;
402 dcs_bit = 0 + w->shift;
395 break; 403 break;
396 case WM8903_POWER_MANAGEMENT_3: 404 case WM8903_POWER_MANAGEMENT_3:
397 reg = WM8903_ANALOGUE_LINEOUT_0; 405 reg = WM8903_ANALOGUE_LINEOUT_0;
406 dcs_bit = 2 + w->shift;
398 break; 407 break;
399 default: 408 default:
400 BUG(); 409 BUG();
@@ -419,18 +428,6 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
419 /* Short the output */ 428 /* Short the output */
420 val &= ~(WM8903_OUTPUT_SHORT << shift); 429 val &= ~(WM8903_OUTPUT_SHORT << shift);
421 wm8903_write(codec, reg, val); 430 wm8903_write(codec, reg, val);
422
423 wm8903->charge_pump_users++;
424
425 dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
426 wm8903->charge_pump_users);
427
428 if (wm8903->charge_pump_users == 1) {
429 dev_dbg(&i2c->dev, "Enabling charge pump\n");
430 wm8903_write(codec, WM8903_CHARGE_PUMP_0,
431 cp_reg | WM8903_CP_ENA);
432 mdelay(4);
433 }
434 } 431 }
435 432
436 if (event & SND_SOC_DAPM_POST_PMU) { 433 if (event & SND_SOC_DAPM_POST_PMU) {
@@ -446,6 +443,11 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
446 val |= (WM8903_OUTPUT_OUT << shift); 443 val |= (WM8903_OUTPUT_OUT << shift);
447 wm8903_write(codec, reg, val); 444 wm8903_write(codec, reg, val);
448 445
446 /* Enable the DC servo */
447 dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
448 dcs_reg |= dcs_bit;
449 wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
450
449 /* Remove the short */ 451 /* Remove the short */
450 val |= (WM8903_OUTPUT_SHORT << shift); 452 val |= (WM8903_OUTPUT_SHORT << shift);
451 wm8903_write(codec, reg, val); 453 wm8903_write(codec, reg, val);
@@ -458,25 +460,17 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w,
458 val &= ~(WM8903_OUTPUT_SHORT << shift); 460 val &= ~(WM8903_OUTPUT_SHORT << shift);
459 wm8903_write(codec, reg, val); 461 wm8903_write(codec, reg, val);
460 462
463 /* Disable the DC servo */
464 dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0);
465 dcs_reg &= ~dcs_bit;
466 wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg);
467
461 /* Then disable the intermediate and output stages */ 468 /* Then disable the intermediate and output stages */
462 val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | 469 val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT |
463 WM8903_OUTPUT_IN) << shift); 470 WM8903_OUTPUT_IN) << shift);
464 wm8903_write(codec, reg, val); 471 wm8903_write(codec, reg, val);
465 } 472 }
466 473
467 if (event & SND_SOC_DAPM_POST_PMD) {
468 wm8903->charge_pump_users--;
469
470 dev_dbg(&i2c->dev, "Charge pump use count now %d\n",
471 wm8903->charge_pump_users);
472
473 if (wm8903->charge_pump_users == 0) {
474 dev_dbg(&i2c->dev, "Disabling charge pump\n");
475 wm8903_write(codec, WM8903_CHARGE_PUMP_0,
476 cp_reg & ~WM8903_CP_ENA);
477 }
478 }
479
480 return 0; 474 return 0;
481} 475}
482 476
@@ -539,6 +533,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
539/* ALSA can only do steps of .01dB */ 533/* ALSA can only do steps of .01dB */
540static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); 534static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
541 535
536static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
542static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0); 537static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
543 538
544static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0); 539static const DECLARE_TLV_DB_SCALE(drc_tlv_thresh, 0, 75, 0);
@@ -657,6 +652,16 @@ static const struct soc_enum rinput_inv_enum =
657 SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text); 652 SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text);
658 653
659 654
655static const char *sidetone_text[] = {
656 "None", "Left", "Right"
657};
658
659static const struct soc_enum lsidetone_enum =
660 SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text);
661
662static const struct soc_enum rsidetone_enum =
663 SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
664
660static const struct snd_kcontrol_new wm8903_snd_controls[] = { 665static const struct snd_kcontrol_new wm8903_snd_controls[] = {
661 666
662/* Input PGAs - No TLV since the scale depends on PGA mode */ 667/* Input PGAs - No TLV since the scale depends on PGA mode */
@@ -700,6 +705,9 @@ SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
700SOC_ENUM("ADC Companding Mode", adc_companding), 705SOC_ENUM("ADC Companding Mode", adc_companding),
701SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0), 706SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
702 707
708SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8903_DAC_DIGITAL_0, 4, 8,
709 12, 0, digital_sidetone_tlv),
710
703/* DAC */ 711/* DAC */
704SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT, 712SOC_DOUBLE_R_TLV("Digital Playback Volume", WM8903_DAC_DIGITAL_VOLUME_LEFT,
705 WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv), 713 WM8903_DAC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
@@ -762,6 +770,12 @@ static const struct snd_kcontrol_new rinput_mux =
762static const struct snd_kcontrol_new rinput_inv_mux = 770static const struct snd_kcontrol_new rinput_inv_mux =
763 SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum); 771 SOC_DAPM_ENUM("Right Inverting Input Mux", rinput_inv_enum);
764 772
773static const struct snd_kcontrol_new lsidetone_mux =
774 SOC_DAPM_ENUM("DACL Sidetone Mux", lsidetone_enum);
775
776static const struct snd_kcontrol_new rsidetone_mux =
777 SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
778
765static const struct snd_kcontrol_new left_output_mixer[] = { 779static const struct snd_kcontrol_new left_output_mixer[] = {
766SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), 780SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0),
767SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), 781SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0),
@@ -828,6 +842,9 @@ SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
828SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0), 842SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0),
829SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0), 843SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0),
830 844
845SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux),
846SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux),
847
831SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0), 848SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0),
832SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0), 849SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0),
833 850
@@ -844,26 +861,29 @@ SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0,
844SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, 861SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
845 1, 0, NULL, 0, wm8903_output_event, 862 1, 0, NULL, 0, wm8903_output_event,
846 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 863 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
847 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 864 SND_SOC_DAPM_PRE_PMD),
848SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, 865SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2,
849 0, 0, NULL, 0, wm8903_output_event, 866 0, 0, NULL, 0, wm8903_output_event,
850 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 867 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
851 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 868 SND_SOC_DAPM_PRE_PMD),
852 869
853SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0, 870SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0,
854 NULL, 0, wm8903_output_event, 871 NULL, 0, wm8903_output_event,
855 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 872 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
856 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 873 SND_SOC_DAPM_PRE_PMD),
857SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0, 874SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0,
858 NULL, 0, wm8903_output_event, 875 NULL, 0, wm8903_output_event,
859 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 876 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
860 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 877 SND_SOC_DAPM_PRE_PMD),
861 878
862SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0, 879SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0,
863 NULL, 0), 880 NULL, 0),
864SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0, 881SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0,
865 NULL, 0), 882 NULL, 0),
866 883
884SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0,
885 wm8903_cp_event, SND_SOC_DAPM_POST_PMU),
886SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
867}; 887};
868 888
869static const struct snd_soc_dapm_route intercon[] = { 889static const struct snd_soc_dapm_route intercon[] = {
@@ -909,7 +929,19 @@ static const struct snd_soc_dapm_route intercon[] = {
909 { "Right Input PGA", NULL, "Right Input Mode Mux" }, 929 { "Right Input PGA", NULL, "Right Input Mode Mux" },
910 930
911 { "ADCL", NULL, "Left Input PGA" }, 931 { "ADCL", NULL, "Left Input PGA" },
932 { "ADCL", NULL, "CLK_DSP" },
912 { "ADCR", NULL, "Right Input PGA" }, 933 { "ADCR", NULL, "Right Input PGA" },
934 { "ADCR", NULL, "CLK_DSP" },
935
936 { "DACL Sidetone", "Left", "ADCL" },
937 { "DACL Sidetone", "Right", "ADCR" },
938 { "DACR Sidetone", "Left", "ADCL" },
939 { "DACR Sidetone", "Right", "ADCR" },
940
941 { "DACL", NULL, "DACL Sidetone" },
942 { "DACL", NULL, "CLK_DSP" },
943 { "DACR", NULL, "DACR Sidetone" },
944 { "DACR", NULL, "CLK_DSP" },
913 945
914 { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" }, 946 { "Left Output Mixer", "Left Bypass Switch", "Left Input PGA" },
915 { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" }, 947 { "Left Output Mixer", "Right Bypass Switch", "Right Input PGA" },
@@ -951,6 +983,11 @@ static const struct snd_soc_dapm_route intercon[] = {
951 983
952 { "ROP", NULL, "Right Speaker PGA" }, 984 { "ROP", NULL, "Right Speaker PGA" },
953 { "RON", NULL, "Right Speaker PGA" }, 985 { "RON", NULL, "Right Speaker PGA" },
986
987 { "Left Headphone Output PGA", NULL, "Charge Pump" },
988 { "Right Headphone Output PGA", NULL, "Charge Pump" },
989 { "Left Line Output PGA", NULL, "Charge Pump" },
990 { "Right Line Output PGA", NULL, "Charge Pump" },
954}; 991};
955 992
956static int wm8903_add_widgets(struct snd_soc_codec *codec) 993static int wm8903_add_widgets(struct snd_soc_codec *codec)
@@ -985,6 +1022,11 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
985 wm8903_write(codec, WM8903_CLOCK_RATES_2, 1022 wm8903_write(codec, WM8903_CLOCK_RATES_2,
986 WM8903_CLK_SYS_ENA); 1023 WM8903_CLK_SYS_ENA);
987 1024
1025 /* Change DC servo dither level in startup sequence */
1026 wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11);
1027 wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257);
1028 wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2);
1029
988 wm8903_run_sequence(codec, 0); 1030 wm8903_run_sequence(codec, 0);
989 wm8903_sync_reg_cache(codec, codec->reg_cache); 1031 wm8903_sync_reg_cache(codec, codec->reg_cache);
990 1032
@@ -1277,14 +1319,8 @@ static int wm8903_startup(struct snd_pcm_substream *substream,
1277 if (wm8903->master_substream) { 1319 if (wm8903->master_substream) {
1278 master_runtime = wm8903->master_substream->runtime; 1320 master_runtime = wm8903->master_substream->runtime;
1279 1321
1280 dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n", 1322 dev_dbg(&i2c->dev, "Constraining to %d bits\n",
1281 master_runtime->sample_bits, 1323 master_runtime->sample_bits);
1282 master_runtime->rate);
1283
1284 snd_pcm_hw_constraint_minmax(substream->runtime,
1285 SNDRV_PCM_HW_PARAM_RATE,
1286 master_runtime->rate,
1287 master_runtime->rate);
1288 1324
1289 snd_pcm_hw_constraint_minmax(substream->runtime, 1325 snd_pcm_hw_constraint_minmax(substream->runtime,
1290 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 1326 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
@@ -1523,6 +1559,7 @@ struct snd_soc_dai wm8903_dai = {
1523 .formats = WM8903_FORMATS, 1559 .formats = WM8903_FORMATS,
1524 }, 1560 },
1525 .ops = &wm8903_dai_ops, 1561 .ops = &wm8903_dai_ops,
1562 .symmetric_rates = 1,
1526}; 1563};
1527EXPORT_SYMBOL_GPL(wm8903_dai); 1564EXPORT_SYMBOL_GPL(wm8903_dai);
1528 1565