diff options
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 260 |
1 files changed, 173 insertions, 87 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 4dbb853eef5a..4df7c6c61c76 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -225,55 +225,11 @@ static void twl4030_codec_mute(struct snd_soc_codec *codec, int mute) | |||
225 | return; | 225 | return; |
226 | 226 | ||
227 | if (mute) { | 227 | if (mute) { |
228 | /* Bypass the reg_cache and mute the volumes | ||
229 | * Headset mute is done in it's own event handler | ||
230 | * Things to mute: Earpiece, PreDrivL/R, CarkitL/R | ||
231 | */ | ||
232 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL); | ||
233 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
234 | reg_val & (~TWL4030_EAR_GAIN), | ||
235 | TWL4030_REG_EAR_CTL); | ||
236 | |||
237 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL); | ||
238 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
239 | reg_val & (~TWL4030_PREDL_GAIN), | ||
240 | TWL4030_REG_PREDL_CTL); | ||
241 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL); | ||
242 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
243 | reg_val & (~TWL4030_PREDR_GAIN), | ||
244 | TWL4030_REG_PREDL_CTL); | ||
245 | |||
246 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL); | ||
247 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
248 | reg_val & (~TWL4030_PRECKL_GAIN), | ||
249 | TWL4030_REG_PRECKL_CTL); | ||
250 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL); | ||
251 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, | ||
252 | reg_val & (~TWL4030_PRECKR_GAIN), | ||
253 | TWL4030_REG_PRECKR_CTL); | ||
254 | |||
255 | /* Disable PLL */ | 228 | /* Disable PLL */ |
256 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); | 229 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); |
257 | reg_val &= ~TWL4030_APLL_EN; | 230 | reg_val &= ~TWL4030_APLL_EN; |
258 | twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val); | 231 | twl4030_write(codec, TWL4030_REG_APLL_CTL, reg_val); |
259 | } else { | 232 | } else { |
260 | /* Restore the volumes | ||
261 | * Headset mute is done in it's own event handler | ||
262 | * Things to restore: Earpiece, PreDrivL/R, CarkitL/R | ||
263 | */ | ||
264 | twl4030_write(codec, TWL4030_REG_EAR_CTL, | ||
265 | twl4030_read_reg_cache(codec, TWL4030_REG_EAR_CTL)); | ||
266 | |||
267 | twl4030_write(codec, TWL4030_REG_PREDL_CTL, | ||
268 | twl4030_read_reg_cache(codec, TWL4030_REG_PREDL_CTL)); | ||
269 | twl4030_write(codec, TWL4030_REG_PREDR_CTL, | ||
270 | twl4030_read_reg_cache(codec, TWL4030_REG_PREDR_CTL)); | ||
271 | |||
272 | twl4030_write(codec, TWL4030_REG_PRECKL_CTL, | ||
273 | twl4030_read_reg_cache(codec, TWL4030_REG_PRECKL_CTL)); | ||
274 | twl4030_write(codec, TWL4030_REG_PRECKR_CTL, | ||
275 | twl4030_read_reg_cache(codec, TWL4030_REG_PRECKR_CTL)); | ||
276 | |||
277 | /* Enable PLL */ | 233 | /* Enable PLL */ |
278 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); | 234 | reg_val = twl4030_read_reg_cache(codec, TWL4030_REG_APLL_CTL); |
279 | reg_val |= TWL4030_APLL_EN; | 235 | reg_val |= TWL4030_APLL_EN; |
@@ -443,16 +399,20 @@ SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); | |||
443 | 399 | ||
444 | /* Left analog microphone selection */ | 400 | /* Left analog microphone selection */ |
445 | static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = { | 401 | static const struct snd_kcontrol_new twl4030_dapm_analoglmic_controls[] = { |
446 | SOC_DAPM_SINGLE("Main mic", TWL4030_REG_ANAMICL, 0, 1, 0), | 402 | SOC_DAPM_SINGLE("Main Mic Capture Switch", |
447 | SOC_DAPM_SINGLE("Headset mic", TWL4030_REG_ANAMICL, 1, 1, 0), | 403 | TWL4030_REG_ANAMICL, 0, 1, 0), |
448 | SOC_DAPM_SINGLE("AUXL", TWL4030_REG_ANAMICL, 2, 1, 0), | 404 | SOC_DAPM_SINGLE("Headset Mic Capture Switch", |
449 | SOC_DAPM_SINGLE("Carkit mic", TWL4030_REG_ANAMICL, 3, 1, 0), | 405 | TWL4030_REG_ANAMICL, 1, 1, 0), |
406 | SOC_DAPM_SINGLE("AUXL Capture Switch", | ||
407 | TWL4030_REG_ANAMICL, 2, 1, 0), | ||
408 | SOC_DAPM_SINGLE("Carkit Mic Capture Switch", | ||
409 | TWL4030_REG_ANAMICL, 3, 1, 0), | ||
450 | }; | 410 | }; |
451 | 411 | ||
452 | /* Right analog microphone selection */ | 412 | /* Right analog microphone selection */ |
453 | static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = { | 413 | static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = { |
454 | SOC_DAPM_SINGLE("Sub mic", TWL4030_REG_ANAMICR, 0, 1, 0), | 414 | SOC_DAPM_SINGLE("Sub Mic Capture Switch", TWL4030_REG_ANAMICR, 0, 1, 0), |
455 | SOC_DAPM_SINGLE("AUXR", TWL4030_REG_ANAMICR, 2, 1, 0), | 415 | SOC_DAPM_SINGLE("AUXR Capture Switch", TWL4030_REG_ANAMICR, 2, 1, 0), |
456 | }; | 416 | }; |
457 | 417 | ||
458 | /* TX1 L/R Analog/Digital microphone selection */ | 418 | /* TX1 L/R Analog/Digital microphone selection */ |
@@ -560,6 +520,41 @@ static int micpath_event(struct snd_soc_dapm_widget *w, | |||
560 | return 0; | 520 | return 0; |
561 | } | 521 | } |
562 | 522 | ||
523 | /* | ||
524 | * Output PGA builder: | ||
525 | * Handle the muting and unmuting of the given output (turning off the | ||
526 | * amplifier associated with the output pin) | ||
527 | * On mute bypass the reg_cache and mute the volume | ||
528 | * On unmute: restore the register content | ||
529 | * Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R | ||
530 | */ | ||
531 | #define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \ | ||
532 | static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ | ||
533 | struct snd_kcontrol *kcontrol, int event) \ | ||
534 | { \ | ||
535 | u8 reg_val; \ | ||
536 | \ | ||
537 | switch (event) { \ | ||
538 | case SND_SOC_DAPM_POST_PMU: \ | ||
539 | twl4030_write(w->codec, reg, \ | ||
540 | twl4030_read_reg_cache(w->codec, reg)); \ | ||
541 | break; \ | ||
542 | case SND_SOC_DAPM_POST_PMD: \ | ||
543 | reg_val = twl4030_read_reg_cache(w->codec, reg); \ | ||
544 | twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \ | ||
545 | reg_val & (~mask), \ | ||
546 | reg); \ | ||
547 | break; \ | ||
548 | } \ | ||
549 | return 0; \ | ||
550 | } | ||
551 | |||
552 | TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN); | ||
553 | TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN); | ||
554 | TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN); | ||
555 | TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN); | ||
556 | TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN); | ||
557 | |||
563 | static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) | 558 | static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) |
564 | { | 559 | { |
565 | unsigned char hs_ctl; | 560 | unsigned char hs_ctl; |
@@ -620,6 +615,9 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w, | |||
620 | 615 | ||
621 | static void headset_ramp(struct snd_soc_codec *codec, int ramp) | 616 | static void headset_ramp(struct snd_soc_codec *codec, int ramp) |
622 | { | 617 | { |
618 | struct snd_soc_device *socdev = codec->socdev; | ||
619 | struct twl4030_setup_data *setup = socdev->codec_data; | ||
620 | |||
623 | unsigned char hs_gain, hs_pop; | 621 | unsigned char hs_gain, hs_pop; |
624 | struct twl4030_priv *twl4030 = codec->private_data; | 622 | struct twl4030_priv *twl4030 = codec->private_data; |
625 | /* Base values for ramp delay calculation: 2^19 - 2^26 */ | 623 | /* Base values for ramp delay calculation: 2^19 - 2^26 */ |
@@ -629,6 +627,17 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) | |||
629 | hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); | 627 | hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); |
630 | hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | 628 | hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); |
631 | 629 | ||
630 | /* Enable external mute control, this dramatically reduces | ||
631 | * the pop-noise */ | ||
632 | if (setup && setup->hs_extmute) { | ||
633 | if (setup->set_hs_extmute) { | ||
634 | setup->set_hs_extmute(1); | ||
635 | } else { | ||
636 | hs_pop |= TWL4030_EXTMUTE; | ||
637 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
638 | } | ||
639 | } | ||
640 | |||
632 | if (ramp) { | 641 | if (ramp) { |
633 | /* Headset ramp-up according to the TRM */ | 642 | /* Headset ramp-up according to the TRM */ |
634 | hs_pop |= TWL4030_VMID_EN; | 643 | hs_pop |= TWL4030_VMID_EN; |
@@ -636,6 +645,9 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) | |||
636 | twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain); | 645 | twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain); |
637 | hs_pop |= TWL4030_RAMP_EN; | 646 | hs_pop |= TWL4030_RAMP_EN; |
638 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | 647 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); |
648 | /* Wait ramp delay time + 1, so the VMID can settle */ | ||
649 | mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / | ||
650 | twl4030->sysclk) + 1); | ||
639 | } else { | 651 | } else { |
640 | /* Headset ramp-down _not_ according to | 652 | /* Headset ramp-down _not_ according to |
641 | * the TRM, but in a way that it is working */ | 653 | * the TRM, but in a way that it is working */ |
@@ -652,6 +664,16 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) | |||
652 | hs_pop &= ~TWL4030_VMID_EN; | 664 | hs_pop &= ~TWL4030_VMID_EN; |
653 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | 665 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); |
654 | } | 666 | } |
667 | |||
668 | /* Disable external mute */ | ||
669 | if (setup && setup->hs_extmute) { | ||
670 | if (setup->set_hs_extmute) { | ||
671 | setup->set_hs_extmute(0); | ||
672 | } else { | ||
673 | hs_pop &= ~TWL4030_EXTMUTE; | ||
674 | twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
675 | } | ||
676 | } | ||
655 | } | 677 | } |
656 | 678 | ||
657 | static int headsetlpga_event(struct snd_soc_dapm_widget *w, | 679 | static int headsetlpga_event(struct snd_soc_dapm_widget *w, |
@@ -712,7 +734,19 @@ static int bypass_event(struct snd_soc_dapm_widget *w, | |||
712 | 734 | ||
713 | reg = twl4030_read_reg_cache(w->codec, m->reg); | 735 | reg = twl4030_read_reg_cache(w->codec, m->reg); |
714 | 736 | ||
715 | if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { | 737 | /* |
738 | * bypass_state[0:3] - analog HiFi bypass | ||
739 | * bypass_state[4] - analog voice bypass | ||
740 | * bypass_state[5] - digital voice bypass | ||
741 | * bypass_state[6:7] - digital HiFi bypass | ||
742 | */ | ||
743 | if (m->reg == TWL4030_REG_VSTPGA) { | ||
744 | /* Voice digital bypass */ | ||
745 | if (reg) | ||
746 | twl4030->bypass_state |= (1 << 5); | ||
747 | else | ||
748 | twl4030->bypass_state &= ~(1 << 5); | ||
749 | } else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) { | ||
716 | /* Analog bypass */ | 750 | /* Analog bypass */ |
717 | if (reg & (1 << m->shift)) | 751 | if (reg & (1 << m->shift)) |
718 | twl4030->bypass_state |= | 752 | twl4030->bypass_state |= |
@@ -726,12 +760,6 @@ static int bypass_event(struct snd_soc_dapm_widget *w, | |||
726 | twl4030->bypass_state |= (1 << 4); | 760 | twl4030->bypass_state |= (1 << 4); |
727 | else | 761 | else |
728 | twl4030->bypass_state &= ~(1 << 4); | 762 | twl4030->bypass_state &= ~(1 << 4); |
729 | } else if (m->reg == TWL4030_REG_VSTPGA) { | ||
730 | /* Voice digital bypass */ | ||
731 | if (reg) | ||
732 | twl4030->bypass_state |= (1 << 5); | ||
733 | else | ||
734 | twl4030->bypass_state &= ~(1 << 5); | ||
735 | } else { | 763 | } else { |
736 | /* Digital bypass */ | 764 | /* Digital bypass */ |
737 | if (reg & (0x7 << m->shift)) | 765 | if (reg & (0x7 << m->shift)) |
@@ -924,7 +952,7 @@ static const struct soc_enum twl4030_op_modes_enum = | |||
924 | ARRAY_SIZE(twl4030_op_modes_texts), | 952 | ARRAY_SIZE(twl4030_op_modes_texts), |
925 | twl4030_op_modes_texts); | 953 | twl4030_op_modes_texts); |
926 | 954 | ||
927 | int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, | 955 | static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, |
928 | struct snd_ctl_elem_value *ucontrol) | 956 | struct snd_ctl_elem_value *ucontrol) |
929 | { | 957 | { |
930 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 958 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -1005,6 +1033,16 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0); | |||
1005 | */ | 1033 | */ |
1006 | static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); | 1034 | static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0); |
1007 | 1035 | ||
1036 | /* AVADC clock priority */ | ||
1037 | static const char *twl4030_avadc_clk_priority_texts[] = { | ||
1038 | "Voice high priority", "HiFi high priority" | ||
1039 | }; | ||
1040 | |||
1041 | static const struct soc_enum twl4030_avadc_clk_priority_enum = | ||
1042 | SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2, | ||
1043 | ARRAY_SIZE(twl4030_avadc_clk_priority_texts), | ||
1044 | twl4030_avadc_clk_priority_texts); | ||
1045 | |||
1008 | static const char *twl4030_rampdelay_texts[] = { | 1046 | static const char *twl4030_rampdelay_texts[] = { |
1009 | "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", | 1047 | "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", |
1010 | "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms", | 1048 | "437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms", |
@@ -1106,6 +1144,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = { | |||
1106 | SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, | 1144 | SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN, |
1107 | 0, 3, 5, 0, input_gain_tlv), | 1145 | 0, 3, 5, 0, input_gain_tlv), |
1108 | 1146 | ||
1147 | SOC_ENUM("AVADC Clock Priority", twl4030_avadc_clk_priority_enum), | ||
1148 | |||
1109 | SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), | 1149 | SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum), |
1110 | 1150 | ||
1111 | SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum), | 1151 | SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum), |
@@ -1208,13 +1248,22 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1208 | SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, | 1248 | SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, |
1209 | &twl4030_dapm_earpiece_controls[0], | 1249 | &twl4030_dapm_earpiece_controls[0], |
1210 | ARRAY_SIZE(twl4030_dapm_earpiece_controls)), | 1250 | ARRAY_SIZE(twl4030_dapm_earpiece_controls)), |
1251 | SND_SOC_DAPM_PGA_E("Earpiece PGA", SND_SOC_NOPM, | ||
1252 | 0, 0, NULL, 0, earpiecepga_event, | ||
1253 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), | ||
1211 | /* PreDrivL/R */ | 1254 | /* PreDrivL/R */ |
1212 | SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0, | 1255 | SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0, |
1213 | &twl4030_dapm_predrivel_controls[0], | 1256 | &twl4030_dapm_predrivel_controls[0], |
1214 | ARRAY_SIZE(twl4030_dapm_predrivel_controls)), | 1257 | ARRAY_SIZE(twl4030_dapm_predrivel_controls)), |
1258 | SND_SOC_DAPM_PGA_E("PredriveL PGA", SND_SOC_NOPM, | ||
1259 | 0, 0, NULL, 0, predrivelpga_event, | ||
1260 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), | ||
1215 | SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0, | 1261 | SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0, |
1216 | &twl4030_dapm_predriver_controls[0], | 1262 | &twl4030_dapm_predriver_controls[0], |
1217 | ARRAY_SIZE(twl4030_dapm_predriver_controls)), | 1263 | ARRAY_SIZE(twl4030_dapm_predriver_controls)), |
1264 | SND_SOC_DAPM_PGA_E("PredriveR PGA", SND_SOC_NOPM, | ||
1265 | 0, 0, NULL, 0, predriverpga_event, | ||
1266 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), | ||
1218 | /* HeadsetL/R */ | 1267 | /* HeadsetL/R */ |
1219 | SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0, | 1268 | SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0, |
1220 | &twl4030_dapm_hsol_controls[0], | 1269 | &twl4030_dapm_hsol_controls[0], |
@@ -1232,22 +1281,28 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1232 | SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0, | 1281 | SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0, |
1233 | &twl4030_dapm_carkitl_controls[0], | 1282 | &twl4030_dapm_carkitl_controls[0], |
1234 | ARRAY_SIZE(twl4030_dapm_carkitl_controls)), | 1283 | ARRAY_SIZE(twl4030_dapm_carkitl_controls)), |
1284 | SND_SOC_DAPM_PGA_E("CarkitL PGA", SND_SOC_NOPM, | ||
1285 | 0, 0, NULL, 0, carkitlpga_event, | ||
1286 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), | ||
1235 | SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0, | 1287 | SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0, |
1236 | &twl4030_dapm_carkitr_controls[0], | 1288 | &twl4030_dapm_carkitr_controls[0], |
1237 | ARRAY_SIZE(twl4030_dapm_carkitr_controls)), | 1289 | ARRAY_SIZE(twl4030_dapm_carkitr_controls)), |
1290 | SND_SOC_DAPM_PGA_E("CarkitR PGA", SND_SOC_NOPM, | ||
1291 | 0, 0, NULL, 0, carkitrpga_event, | ||
1292 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), | ||
1238 | 1293 | ||
1239 | /* Output MUX controls */ | 1294 | /* Output MUX controls */ |
1240 | /* HandsfreeL/R */ | 1295 | /* HandsfreeL/R */ |
1241 | SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0, | 1296 | SND_SOC_DAPM_MUX("HandsfreeL Mux", SND_SOC_NOPM, 0, 0, |
1242 | &twl4030_dapm_handsfreel_control), | 1297 | &twl4030_dapm_handsfreel_control), |
1243 | SND_SOC_DAPM_SWITCH("HandsfreeL Switch", SND_SOC_NOPM, 0, 0, | 1298 | SND_SOC_DAPM_SWITCH("HandsfreeL", SND_SOC_NOPM, 0, 0, |
1244 | &twl4030_dapm_handsfreelmute_control), | 1299 | &twl4030_dapm_handsfreelmute_control), |
1245 | SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM, | 1300 | SND_SOC_DAPM_PGA_E("HandsfreeL PGA", SND_SOC_NOPM, |
1246 | 0, 0, NULL, 0, handsfreelpga_event, | 1301 | 0, 0, NULL, 0, handsfreelpga_event, |
1247 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), | 1302 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD), |
1248 | SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0, | 1303 | SND_SOC_DAPM_MUX("HandsfreeR Mux", SND_SOC_NOPM, 5, 0, |
1249 | &twl4030_dapm_handsfreer_control), | 1304 | &twl4030_dapm_handsfreer_control), |
1250 | SND_SOC_DAPM_SWITCH("HandsfreeR Switch", SND_SOC_NOPM, 0, 0, | 1305 | SND_SOC_DAPM_SWITCH("HandsfreeR", SND_SOC_NOPM, 0, 0, |
1251 | &twl4030_dapm_handsfreermute_control), | 1306 | &twl4030_dapm_handsfreermute_control), |
1252 | SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM, | 1307 | SND_SOC_DAPM_PGA_E("HandsfreeR PGA", SND_SOC_NOPM, |
1253 | 0, 0, NULL, 0, handsfreerpga_event, | 1308 | 0, 0, NULL, 0, handsfreerpga_event, |
@@ -1282,11 +1337,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1282 | SND_SOC_DAPM_POST_REG), | 1337 | SND_SOC_DAPM_POST_REG), |
1283 | 1338 | ||
1284 | /* Analog input mixers for the capture amplifiers */ | 1339 | /* Analog input mixers for the capture amplifiers */ |
1285 | SND_SOC_DAPM_MIXER("Analog Left Capture Route", | 1340 | SND_SOC_DAPM_MIXER("Analog Left", |
1286 | TWL4030_REG_ANAMICL, 4, 0, | 1341 | TWL4030_REG_ANAMICL, 4, 0, |
1287 | &twl4030_dapm_analoglmic_controls[0], | 1342 | &twl4030_dapm_analoglmic_controls[0], |
1288 | ARRAY_SIZE(twl4030_dapm_analoglmic_controls)), | 1343 | ARRAY_SIZE(twl4030_dapm_analoglmic_controls)), |
1289 | SND_SOC_DAPM_MIXER("Analog Right Capture Route", | 1344 | SND_SOC_DAPM_MIXER("Analog Right", |
1290 | TWL4030_REG_ANAMICR, 4, 0, | 1345 | TWL4030_REG_ANAMICR, 4, 0, |
1291 | &twl4030_dapm_analogrmic_controls[0], | 1346 | &twl4030_dapm_analogrmic_controls[0], |
1292 | ARRAY_SIZE(twl4030_dapm_analogrmic_controls)), | 1347 | ARRAY_SIZE(twl4030_dapm_analogrmic_controls)), |
@@ -1326,16 +1381,19 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1326 | {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"}, | 1381 | {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"}, |
1327 | {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"}, | 1382 | {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"}, |
1328 | {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"}, | 1383 | {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"}, |
1384 | {"Earpiece PGA", NULL, "Earpiece Mixer"}, | ||
1329 | /* PreDrivL */ | 1385 | /* PreDrivL */ |
1330 | {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"}, | 1386 | {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"}, |
1331 | {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, | 1387 | {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, |
1332 | {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, | 1388 | {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, |
1333 | {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"}, | 1389 | {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"}, |
1390 | {"PredriveL PGA", NULL, "PredriveL Mixer"}, | ||
1334 | /* PreDrivR */ | 1391 | /* PreDrivR */ |
1335 | {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"}, | 1392 | {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"}, |
1336 | {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, | 1393 | {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, |
1337 | {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, | 1394 | {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, |
1338 | {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"}, | 1395 | {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"}, |
1396 | {"PredriveR PGA", NULL, "PredriveR Mixer"}, | ||
1339 | /* HeadsetL */ | 1397 | /* HeadsetL */ |
1340 | {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"}, | 1398 | {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"}, |
1341 | {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, | 1399 | {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, |
@@ -1350,24 +1408,26 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1350 | {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"}, | 1408 | {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"}, |
1351 | {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, | 1409 | {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, |
1352 | {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, | 1410 | {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, |
1411 | {"CarkitL PGA", NULL, "CarkitL Mixer"}, | ||
1353 | /* CarkitR */ | 1412 | /* CarkitR */ |
1354 | {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"}, | 1413 | {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"}, |
1355 | {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, | 1414 | {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, |
1356 | {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, | 1415 | {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, |
1416 | {"CarkitR PGA", NULL, "CarkitR Mixer"}, | ||
1357 | /* HandsfreeL */ | 1417 | /* HandsfreeL */ |
1358 | {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"}, | 1418 | {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"}, |
1359 | {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"}, | 1419 | {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"}, |
1360 | {"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"}, | 1420 | {"HandsfreeL Mux", "AudioL2", "Analog L2 Playback Mixer"}, |
1361 | {"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"}, | 1421 | {"HandsfreeL Mux", "AudioR2", "Analog R2 Playback Mixer"}, |
1362 | {"HandsfreeL Switch", "Switch", "HandsfreeL Mux"}, | 1422 | {"HandsfreeL", "Switch", "HandsfreeL Mux"}, |
1363 | {"HandsfreeL PGA", NULL, "HandsfreeL Switch"}, | 1423 | {"HandsfreeL PGA", NULL, "HandsfreeL"}, |
1364 | /* HandsfreeR */ | 1424 | /* HandsfreeR */ |
1365 | {"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"}, | 1425 | {"HandsfreeR Mux", "Voice", "Analog Voice Playback Mixer"}, |
1366 | {"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"}, | 1426 | {"HandsfreeR Mux", "AudioR1", "Analog R1 Playback Mixer"}, |
1367 | {"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"}, | 1427 | {"HandsfreeR Mux", "AudioR2", "Analog R2 Playback Mixer"}, |
1368 | {"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"}, | 1428 | {"HandsfreeR Mux", "AudioL2", "Analog L2 Playback Mixer"}, |
1369 | {"HandsfreeR Switch", "Switch", "HandsfreeR Mux"}, | 1429 | {"HandsfreeR", "Switch", "HandsfreeR Mux"}, |
1370 | {"HandsfreeR PGA", NULL, "HandsfreeR Switch"}, | 1430 | {"HandsfreeR PGA", NULL, "HandsfreeR"}, |
1371 | /* Vibra */ | 1431 | /* Vibra */ |
1372 | {"Vibra Mux", "AudioL1", "DAC Left1"}, | 1432 | {"Vibra Mux", "AudioL1", "DAC Left1"}, |
1373 | {"Vibra Mux", "AudioR1", "DAC Right1"}, | 1433 | {"Vibra Mux", "AudioR1", "DAC Right1"}, |
@@ -1377,29 +1437,29 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1377 | /* outputs */ | 1437 | /* outputs */ |
1378 | {"OUTL", NULL, "Analog L2 Playback Mixer"}, | 1438 | {"OUTL", NULL, "Analog L2 Playback Mixer"}, |
1379 | {"OUTR", NULL, "Analog R2 Playback Mixer"}, | 1439 | {"OUTR", NULL, "Analog R2 Playback Mixer"}, |
1380 | {"EARPIECE", NULL, "Earpiece Mixer"}, | 1440 | {"EARPIECE", NULL, "Earpiece PGA"}, |
1381 | {"PREDRIVEL", NULL, "PredriveL Mixer"}, | 1441 | {"PREDRIVEL", NULL, "PredriveL PGA"}, |
1382 | {"PREDRIVER", NULL, "PredriveR Mixer"}, | 1442 | {"PREDRIVER", NULL, "PredriveR PGA"}, |
1383 | {"HSOL", NULL, "HeadsetL PGA"}, | 1443 | {"HSOL", NULL, "HeadsetL PGA"}, |
1384 | {"HSOR", NULL, "HeadsetR PGA"}, | 1444 | {"HSOR", NULL, "HeadsetR PGA"}, |
1385 | {"CARKITL", NULL, "CarkitL Mixer"}, | 1445 | {"CARKITL", NULL, "CarkitL PGA"}, |
1386 | {"CARKITR", NULL, "CarkitR Mixer"}, | 1446 | {"CARKITR", NULL, "CarkitR PGA"}, |
1387 | {"HFL", NULL, "HandsfreeL PGA"}, | 1447 | {"HFL", NULL, "HandsfreeL PGA"}, |
1388 | {"HFR", NULL, "HandsfreeR PGA"}, | 1448 | {"HFR", NULL, "HandsfreeR PGA"}, |
1389 | {"Vibra Route", "Audio", "Vibra Mux"}, | 1449 | {"Vibra Route", "Audio", "Vibra Mux"}, |
1390 | {"VIBRA", NULL, "Vibra Route"}, | 1450 | {"VIBRA", NULL, "Vibra Route"}, |
1391 | 1451 | ||
1392 | /* Capture path */ | 1452 | /* Capture path */ |
1393 | {"Analog Left Capture Route", "Main mic", "MAINMIC"}, | 1453 | {"Analog Left", "Main Mic Capture Switch", "MAINMIC"}, |
1394 | {"Analog Left Capture Route", "Headset mic", "HSMIC"}, | 1454 | {"Analog Left", "Headset Mic Capture Switch", "HSMIC"}, |
1395 | {"Analog Left Capture Route", "AUXL", "AUXL"}, | 1455 | {"Analog Left", "AUXL Capture Switch", "AUXL"}, |
1396 | {"Analog Left Capture Route", "Carkit mic", "CARKITMIC"}, | 1456 | {"Analog Left", "Carkit Mic Capture Switch", "CARKITMIC"}, |
1397 | 1457 | ||
1398 | {"Analog Right Capture Route", "Sub mic", "SUBMIC"}, | 1458 | {"Analog Right", "Sub Mic Capture Switch", "SUBMIC"}, |
1399 | {"Analog Right Capture Route", "AUXR", "AUXR"}, | 1459 | {"Analog Right", "AUXR Capture Switch", "AUXR"}, |
1400 | 1460 | ||
1401 | {"ADC Physical Left", NULL, "Analog Left Capture Route"}, | 1461 | {"ADC Physical Left", NULL, "Analog Left"}, |
1402 | {"ADC Physical Right", NULL, "Analog Right Capture Route"}, | 1462 | {"ADC Physical Right", NULL, "Analog Right"}, |
1403 | 1463 | ||
1404 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, | 1464 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, |
1405 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, | 1465 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, |
@@ -1423,11 +1483,11 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1423 | {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, | 1483 | {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, |
1424 | 1484 | ||
1425 | /* Analog bypass routes */ | 1485 | /* Analog bypass routes */ |
1426 | {"Right1 Analog Loopback", "Switch", "Analog Right Capture Route"}, | 1486 | {"Right1 Analog Loopback", "Switch", "Analog Right"}, |
1427 | {"Left1 Analog Loopback", "Switch", "Analog Left Capture Route"}, | 1487 | {"Left1 Analog Loopback", "Switch", "Analog Left"}, |
1428 | {"Right2 Analog Loopback", "Switch", "Analog Right Capture Route"}, | 1488 | {"Right2 Analog Loopback", "Switch", "Analog Right"}, |
1429 | {"Left2 Analog Loopback", "Switch", "Analog Left Capture Route"}, | 1489 | {"Left2 Analog Loopback", "Switch", "Analog Left"}, |
1430 | {"Voice Analog Loopback", "Switch", "Analog Left Capture Route"}, | 1490 | {"Voice Analog Loopback", "Switch", "Analog Left"}, |
1431 | 1491 | ||
1432 | {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, | 1492 | {"Analog R1 Playback Mixer", NULL, "Right1 Analog Loopback"}, |
1433 | {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, | 1493 | {"Analog L1 Playback Mixer", NULL, "Left1 Analog Loopback"}, |
@@ -1609,8 +1669,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1609 | 1669 | ||
1610 | /* If the substream has 4 channel, do the necessary setup */ | 1670 | /* If the substream has 4 channel, do the necessary setup */ |
1611 | if (params_channels(params) == 4) { | 1671 | if (params_channels(params) == 4) { |
1612 | u8 format, mode; | ||
1613 | |||
1614 | format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); | 1672 | format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); |
1615 | mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); | 1673 | mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); |
1616 | 1674 | ||
@@ -1806,6 +1864,19 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1806 | return 0; | 1864 | return 0; |
1807 | } | 1865 | } |
1808 | 1866 | ||
1867 | static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
1868 | { | ||
1869 | struct snd_soc_codec *codec = dai->codec; | ||
1870 | u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); | ||
1871 | |||
1872 | if (tristate) | ||
1873 | reg |= TWL4030_AIF_TRI_EN; | ||
1874 | else | ||
1875 | reg &= ~TWL4030_AIF_TRI_EN; | ||
1876 | |||
1877 | return twl4030_write(codec, TWL4030_REG_AUDIO_IF, reg); | ||
1878 | } | ||
1879 | |||
1809 | /* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R | 1880 | /* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R |
1810 | * (VTXL, VTXR) for uplink has to be enabled/disabled. */ | 1881 | * (VTXL, VTXR) for uplink has to be enabled/disabled. */ |
1811 | static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, | 1882 | static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, |
@@ -1948,7 +2019,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1948 | 2019 | ||
1949 | /* set master/slave audio interface */ | 2020 | /* set master/slave audio interface */ |
1950 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 2021 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
1951 | case SND_SOC_DAIFMT_CBS_CFM: | 2022 | case SND_SOC_DAIFMT_CBM_CFM: |
1952 | format &= ~(TWL4030_VIF_SLAVE_EN); | 2023 | format &= ~(TWL4030_VIF_SLAVE_EN); |
1953 | break; | 2024 | break; |
1954 | case SND_SOC_DAIFMT_CBS_CFS: | 2025 | case SND_SOC_DAIFMT_CBS_CFS: |
@@ -1980,6 +2051,19 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1980 | return 0; | 2051 | return 0; |
1981 | } | 2052 | } |
1982 | 2053 | ||
2054 | static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
2055 | { | ||
2056 | struct snd_soc_codec *codec = dai->codec; | ||
2057 | u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); | ||
2058 | |||
2059 | if (tristate) | ||
2060 | reg |= TWL4030_VIF_TRI_EN; | ||
2061 | else | ||
2062 | reg &= ~TWL4030_VIF_TRI_EN; | ||
2063 | |||
2064 | return twl4030_write(codec, TWL4030_REG_VOICE_IF, reg); | ||
2065 | } | ||
2066 | |||
1983 | #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) | 2067 | #define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000) |
1984 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) | 2068 | #define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE) |
1985 | 2069 | ||
@@ -1989,6 +2073,7 @@ static struct snd_soc_dai_ops twl4030_dai_ops = { | |||
1989 | .hw_params = twl4030_hw_params, | 2073 | .hw_params = twl4030_hw_params, |
1990 | .set_sysclk = twl4030_set_dai_sysclk, | 2074 | .set_sysclk = twl4030_set_dai_sysclk, |
1991 | .set_fmt = twl4030_set_dai_fmt, | 2075 | .set_fmt = twl4030_set_dai_fmt, |
2076 | .set_tristate = twl4030_set_tristate, | ||
1992 | }; | 2077 | }; |
1993 | 2078 | ||
1994 | static struct snd_soc_dai_ops twl4030_dai_voice_ops = { | 2079 | static struct snd_soc_dai_ops twl4030_dai_voice_ops = { |
@@ -1997,6 +2082,7 @@ static struct snd_soc_dai_ops twl4030_dai_voice_ops = { | |||
1997 | .hw_params = twl4030_voice_hw_params, | 2082 | .hw_params = twl4030_voice_hw_params, |
1998 | .set_sysclk = twl4030_voice_set_dai_sysclk, | 2083 | .set_sysclk = twl4030_voice_set_dai_sysclk, |
1999 | .set_fmt = twl4030_voice_set_dai_fmt, | 2084 | .set_fmt = twl4030_voice_set_dai_fmt, |
2085 | .set_tristate = twl4030_voice_set_tristate, | ||
2000 | }; | 2086 | }; |
2001 | 2087 | ||
2002 | struct snd_soc_dai twl4030_dai[] = { | 2088 | struct snd_soc_dai twl4030_dai[] = { |