aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/twl4030.c72
1 files changed, 56 insertions, 16 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 6f5d4af20052..bf59b8a4d1d7 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -135,9 +135,11 @@ struct twl4030_priv {
135 135
136 unsigned int sysclk; 136 unsigned int sysclk;
137 137
138 /* Headset output state handling */ 138 /* Output (with associated amp) states */
139 unsigned int hsl_enabled; 139 u8 hsl_enabled, hsr_enabled;
140 unsigned int hsr_enabled; 140 u8 earpiece_enabled;
141 u8 predrivel_enabled, predriver_enabled;
142 u8 carkitl_enabled, carkitr_enabled;
141}; 143};
142 144
143/* 145/*
@@ -173,12 +175,47 @@ static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
173static int twl4030_write(struct snd_soc_codec *codec, 175static int twl4030_write(struct snd_soc_codec *codec,
174 unsigned int reg, unsigned int value) 176 unsigned int reg, unsigned int value)
175{ 177{
178 struct twl4030_priv *twl4030 = codec->private_data;
179 int write_to_reg = 0;
180
176 twl4030_write_reg_cache(codec, reg, value); 181 twl4030_write_reg_cache(codec, reg, value);
177 if (likely(reg < TWL4030_REG_SW_SHADOW)) 182 if (likely(reg < TWL4030_REG_SW_SHADOW)) {
178 return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, 183 /* Decide if the given register can be written */
179 reg); 184 switch (reg) {
180 else 185 case TWL4030_REG_EAR_CTL:
181 return 0; 186 if (twl4030->earpiece_enabled)
187 write_to_reg = 1;
188 break;
189 case TWL4030_REG_PREDL_CTL:
190 if (twl4030->predrivel_enabled)
191 write_to_reg = 1;
192 break;
193 case TWL4030_REG_PREDR_CTL:
194 if (twl4030->predriver_enabled)
195 write_to_reg = 1;
196 break;
197 case TWL4030_REG_PRECKL_CTL:
198 if (twl4030->carkitl_enabled)
199 write_to_reg = 1;
200 break;
201 case TWL4030_REG_PRECKR_CTL:
202 if (twl4030->carkitr_enabled)
203 write_to_reg = 1;
204 break;
205 case TWL4030_REG_HS_GAIN_SET:
206 if (twl4030->hsl_enabled || twl4030->hsr_enabled)
207 write_to_reg = 1;
208 break;
209 default:
210 /* All other register can be written */
211 write_to_reg = 1;
212 break;
213 }
214 if (write_to_reg)
215 return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
216 value, reg);
217 }
218 return 0;
182} 219}
183 220
184static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) 221static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
@@ -525,26 +562,26 @@ static int micpath_event(struct snd_soc_dapm_widget *w,
525 * Output PGA builder: 562 * Output PGA builder:
526 * Handle the muting and unmuting of the given output (turning off the 563 * Handle the muting and unmuting of the given output (turning off the
527 * amplifier associated with the output pin) 564 * amplifier associated with the output pin)
528 * On mute bypass the reg_cache and mute the volume 565 * On mute bypass the reg_cache and write 0 to the register
529 * On unmute: restore the register content 566 * On unmute: restore the register content from the reg_cache
530 * Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R 567 * Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R
531 */ 568 */
532#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \ 569#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \
533static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ 570static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
534 struct snd_kcontrol *kcontrol, int event) \ 571 struct snd_kcontrol *kcontrol, int event) \
535{ \ 572{ \
536 u8 reg_val; \ 573 struct twl4030_priv *twl4030 = w->codec->private_data; \
537 \ 574 \
538 switch (event) { \ 575 switch (event) { \
539 case SND_SOC_DAPM_POST_PMU: \ 576 case SND_SOC_DAPM_POST_PMU: \
577 twl4030->pin_name##_enabled = 1; \
540 twl4030_write(w->codec, reg, \ 578 twl4030_write(w->codec, reg, \
541 twl4030_read_reg_cache(w->codec, reg)); \ 579 twl4030_read_reg_cache(w->codec, reg)); \
542 break; \ 580 break; \
543 case SND_SOC_DAPM_POST_PMD: \ 581 case SND_SOC_DAPM_POST_PMD: \
544 reg_val = twl4030_read_reg_cache(w->codec, reg); \ 582 twl4030->pin_name##_enabled = 0; \
545 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \ 583 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \
546 reg_val & (~mask), \ 584 0, reg); \
547 reg); \
548 break; \ 585 break; \
549 } \ 586 } \
550 return 0; \ 587 return 0; \
@@ -664,7 +701,10 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
664 /* Headset ramp-up according to the TRM */ 701 /* Headset ramp-up according to the TRM */
665 hs_pop |= TWL4030_VMID_EN; 702 hs_pop |= TWL4030_VMID_EN;
666 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); 703 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
667 twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain); 704 /* Actually write to the register */
705 twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
706 hs_gain,
707 TWL4030_REG_HS_GAIN_SET);
668 hs_pop |= TWL4030_RAMP_EN; 708 hs_pop |= TWL4030_RAMP_EN;
669 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); 709 twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
670 /* Wait ramp delay time + 1, so the VMID can settle */ 710 /* Wait ramp delay time + 1, so the VMID can settle */