aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2009-08-13 08:59:34 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-08-13 09:56:13 -0400
commit9008adf9a9c3a43ef237f6cd416857569beb0029 (patch)
treeccc443a537a4b82a8dbebfb65e31d744a6b4c49b /sound
parentc4ff357ada4fc7a73d899a496b636c698519b958 (diff)
ASoC: TWL4030: Introduce PGAs for outputs
Dynamically control and control only the needed output amplifier muting/un-muting. The original code was muting and un-muting the following output amplifiers: Earpiece PreDrivL/R, CarkitL/R at the same time regardless which pin is actually in use at the given moment. Move these as separate PGA so only the needed amplifier will be touched. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/twl4030.c109
1 files changed, 60 insertions, 49 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 818fb37bd7f7..1a65004fa376 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;
@@ -560,6 +516,41 @@ static int micpath_event(struct snd_soc_dapm_widget *w,
560 return 0; 516 return 0;
561} 517}
562 518
519/*
520 * Output PGA builder:
521 * Handle the muting and unmuting of the given output (turning off the
522 * amplifier associated with the output pin)
523 * On mute bypass the reg_cache and mute the volume
524 * On unmute: restore the register content
525 * Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R
526 */
527#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \
528static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
529 struct snd_kcontrol *kcontrol, int event) \
530{ \
531 u8 reg_val; \
532 \
533 switch (event) { \
534 case SND_SOC_DAPM_POST_PMU: \
535 twl4030_write(w->codec, reg, \
536 twl4030_read_reg_cache(w->codec, reg)); \
537 break; \
538 case SND_SOC_DAPM_POST_PMD: \
539 reg_val = twl4030_read_reg_cache(w->codec, reg); \
540 twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \
541 reg_val & (~mask), \
542 reg); \
543 break; \
544 } \
545 return 0; \
546}
547
548TWL4030_OUTPUT_PGA(earpiece, TWL4030_REG_EAR_CTL, TWL4030_EAR_GAIN);
549TWL4030_OUTPUT_PGA(predrivel, TWL4030_REG_PREDL_CTL, TWL4030_PREDL_GAIN);
550TWL4030_OUTPUT_PGA(predriver, TWL4030_REG_PREDR_CTL, TWL4030_PREDR_GAIN);
551TWL4030_OUTPUT_PGA(carkitl, TWL4030_REG_PRECKL_CTL, TWL4030_PRECKL_GAIN);
552TWL4030_OUTPUT_PGA(carkitr, TWL4030_REG_PRECKR_CTL, TWL4030_PRECKR_GAIN);
553
563static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) 554static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
564{ 555{
565 unsigned char hs_ctl; 556 unsigned char hs_ctl;
@@ -1253,13 +1244,22 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1253 SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0, 1244 SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
1254 &twl4030_dapm_earpiece_controls[0], 1245 &twl4030_dapm_earpiece_controls[0],
1255 ARRAY_SIZE(twl4030_dapm_earpiece_controls)), 1246 ARRAY_SIZE(twl4030_dapm_earpiece_controls)),
1247 SND_SOC_DAPM_PGA_E("Earpiece PGA", SND_SOC_NOPM,
1248 0, 0, NULL, 0, earpiecepga_event,
1249 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
1256 /* PreDrivL/R */ 1250 /* PreDrivL/R */
1257 SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0, 1251 SND_SOC_DAPM_MIXER("PredriveL Mixer", SND_SOC_NOPM, 0, 0,
1258 &twl4030_dapm_predrivel_controls[0], 1252 &twl4030_dapm_predrivel_controls[0],
1259 ARRAY_SIZE(twl4030_dapm_predrivel_controls)), 1253 ARRAY_SIZE(twl4030_dapm_predrivel_controls)),
1254 SND_SOC_DAPM_PGA_E("PredriveL PGA", SND_SOC_NOPM,
1255 0, 0, NULL, 0, predrivelpga_event,
1256 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
1260 SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0, 1257 SND_SOC_DAPM_MIXER("PredriveR Mixer", SND_SOC_NOPM, 0, 0,
1261 &twl4030_dapm_predriver_controls[0], 1258 &twl4030_dapm_predriver_controls[0],
1262 ARRAY_SIZE(twl4030_dapm_predriver_controls)), 1259 ARRAY_SIZE(twl4030_dapm_predriver_controls)),
1260 SND_SOC_DAPM_PGA_E("PredriveR PGA", SND_SOC_NOPM,
1261 0, 0, NULL, 0, predriverpga_event,
1262 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
1263 /* HeadsetL/R */ 1263 /* HeadsetL/R */
1264 SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0, 1264 SND_SOC_DAPM_MIXER("HeadsetL Mixer", SND_SOC_NOPM, 0, 0,
1265 &twl4030_dapm_hsol_controls[0], 1265 &twl4030_dapm_hsol_controls[0],
@@ -1277,9 +1277,15 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1277 SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0, 1277 SND_SOC_DAPM_MIXER("CarkitL Mixer", SND_SOC_NOPM, 0, 0,
1278 &twl4030_dapm_carkitl_controls[0], 1278 &twl4030_dapm_carkitl_controls[0],
1279 ARRAY_SIZE(twl4030_dapm_carkitl_controls)), 1279 ARRAY_SIZE(twl4030_dapm_carkitl_controls)),
1280 SND_SOC_DAPM_PGA_E("CarkitL PGA", SND_SOC_NOPM,
1281 0, 0, NULL, 0, carkitlpga_event,
1282 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
1280 SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0, 1283 SND_SOC_DAPM_MIXER("CarkitR Mixer", SND_SOC_NOPM, 0, 0,
1281 &twl4030_dapm_carkitr_controls[0], 1284 &twl4030_dapm_carkitr_controls[0],
1282 ARRAY_SIZE(twl4030_dapm_carkitr_controls)), 1285 ARRAY_SIZE(twl4030_dapm_carkitr_controls)),
1286 SND_SOC_DAPM_PGA_E("CarkitR PGA", SND_SOC_NOPM,
1287 0, 0, NULL, 0, carkitrpga_event,
1288 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
1283 1289
1284 /* Output MUX controls */ 1290 /* Output MUX controls */
1285 /* HandsfreeL/R */ 1291 /* HandsfreeL/R */
@@ -1371,16 +1377,19 @@ static const struct snd_soc_dapm_route intercon[] = {
1371 {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"}, 1377 {"Earpiece Mixer", "AudioL1", "Analog L1 Playback Mixer"},
1372 {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"}, 1378 {"Earpiece Mixer", "AudioL2", "Analog L2 Playback Mixer"},
1373 {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"}, 1379 {"Earpiece Mixer", "AudioR1", "Analog R1 Playback Mixer"},
1380 {"Earpiece PGA", NULL, "Earpiece Mixer"},
1374 /* PreDrivL */ 1381 /* PreDrivL */
1375 {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"}, 1382 {"PredriveL Mixer", "Voice", "Analog Voice Playback Mixer"},
1376 {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, 1383 {"PredriveL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
1377 {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, 1384 {"PredriveL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
1378 {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"}, 1385 {"PredriveL Mixer", "AudioR2", "Analog R2 Playback Mixer"},
1386 {"PredriveL PGA", NULL, "PredriveL Mixer"},
1379 /* PreDrivR */ 1387 /* PreDrivR */
1380 {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"}, 1388 {"PredriveR Mixer", "Voice", "Analog Voice Playback Mixer"},
1381 {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, 1389 {"PredriveR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
1382 {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, 1390 {"PredriveR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
1383 {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"}, 1391 {"PredriveR Mixer", "AudioL2", "Analog L2 Playback Mixer"},
1392 {"PredriveR PGA", NULL, "PredriveR Mixer"},
1384 /* HeadsetL */ 1393 /* HeadsetL */
1385 {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"}, 1394 {"HeadsetL Mixer", "Voice", "Analog Voice Playback Mixer"},
1386 {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, 1395 {"HeadsetL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
@@ -1395,10 +1404,12 @@ static const struct snd_soc_dapm_route intercon[] = {
1395 {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"}, 1404 {"CarkitL Mixer", "Voice", "Analog Voice Playback Mixer"},
1396 {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"}, 1405 {"CarkitL Mixer", "AudioL1", "Analog L1 Playback Mixer"},
1397 {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"}, 1406 {"CarkitL Mixer", "AudioL2", "Analog L2 Playback Mixer"},
1407 {"CarkitL PGA", NULL, "CarkitL Mixer"},
1398 /* CarkitR */ 1408 /* CarkitR */
1399 {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"}, 1409 {"CarkitR Mixer", "Voice", "Analog Voice Playback Mixer"},
1400 {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"}, 1410 {"CarkitR Mixer", "AudioR1", "Analog R1 Playback Mixer"},
1401 {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"}, 1411 {"CarkitR Mixer", "AudioR2", "Analog R2 Playback Mixer"},
1412 {"CarkitR PGA", NULL, "CarkitR Mixer"},
1402 /* HandsfreeL */ 1413 /* HandsfreeL */
1403 {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"}, 1414 {"HandsfreeL Mux", "Voice", "Analog Voice Playback Mixer"},
1404 {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"}, 1415 {"HandsfreeL Mux", "AudioL1", "Analog L1 Playback Mixer"},
@@ -1422,13 +1433,13 @@ static const struct snd_soc_dapm_route intercon[] = {
1422 /* outputs */ 1433 /* outputs */
1423 {"OUTL", NULL, "Analog L2 Playback Mixer"}, 1434 {"OUTL", NULL, "Analog L2 Playback Mixer"},
1424 {"OUTR", NULL, "Analog R2 Playback Mixer"}, 1435 {"OUTR", NULL, "Analog R2 Playback Mixer"},
1425 {"EARPIECE", NULL, "Earpiece Mixer"}, 1436 {"EARPIECE", NULL, "Earpiece PGA"},
1426 {"PREDRIVEL", NULL, "PredriveL Mixer"}, 1437 {"PREDRIVEL", NULL, "PredriveL PGA"},
1427 {"PREDRIVER", NULL, "PredriveR Mixer"}, 1438 {"PREDRIVER", NULL, "PredriveR PGA"},
1428 {"HSOL", NULL, "HeadsetL PGA"}, 1439 {"HSOL", NULL, "HeadsetL PGA"},
1429 {"HSOR", NULL, "HeadsetR PGA"}, 1440 {"HSOR", NULL, "HeadsetR PGA"},
1430 {"CARKITL", NULL, "CarkitL Mixer"}, 1441 {"CARKITL", NULL, "CarkitL PGA"},
1431 {"CARKITR", NULL, "CarkitR Mixer"}, 1442 {"CARKITR", NULL, "CarkitR PGA"},
1432 {"HFL", NULL, "HandsfreeL PGA"}, 1443 {"HFL", NULL, "HandsfreeL PGA"},
1433 {"HFR", NULL, "HandsfreeR PGA"}, 1444 {"HFR", NULL, "HandsfreeR PGA"},
1434 {"Vibra Route", "Audio", "Vibra Mux"}, 1445 {"Vibra Route", "Audio", "Vibra Mux"},