aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/twl4030.c82
1 files changed, 60 insertions, 22 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 2e025a3a2618..12931f6d445b 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -123,6 +123,8 @@ struct twl4030_priv {
123 struct snd_soc_codec codec; 123 struct snd_soc_codec codec;
124 124
125 unsigned int codec_powered; 125 unsigned int codec_powered;
126
127 /* reference counts of AIF/APLL users */
126 unsigned int apll_enabled; 128 unsigned int apll_enabled;
127 129
128 struct snd_pcm_substream *master_substream; 130 struct snd_pcm_substream *master_substream;
@@ -259,22 +261,22 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
259static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) 261static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
260{ 262{
261 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 263 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
262 int status; 264 int status = -1;
263
264 if (enable == twl4030->apll_enabled)
265 return;
266 265
267 if (enable) 266 if (enable) {
268 /* Enable PLL */ 267 twl4030->apll_enabled++;
269 status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL); 268 if (twl4030->apll_enabled == 1)
270 else 269 status = twl4030_codec_enable_resource(
271 /* Disable PLL */ 270 TWL4030_CODEC_RES_APLL);
272 status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL); 271 } else {
272 twl4030->apll_enabled--;
273 if (!twl4030->apll_enabled)
274 status = twl4030_codec_disable_resource(
275 TWL4030_CODEC_RES_APLL);
276 }
273 277
274 if (status >= 0) 278 if (status >= 0)
275 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); 279 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
276
277 twl4030->apll_enabled = enable;
278} 280}
279 281
280static void twl4030_power_up(struct snd_soc_codec *codec) 282static void twl4030_power_up(struct snd_soc_codec *codec)
@@ -672,6 +674,31 @@ static int apll_event(struct snd_soc_dapm_widget *w,
672 return 0; 674 return 0;
673} 675}
674 676
677static int aif_event(struct snd_soc_dapm_widget *w,
678 struct snd_kcontrol *kcontrol, int event)
679{
680 u8 audio_if;
681
682 audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF);
683 switch (event) {
684 case SND_SOC_DAPM_PRE_PMU:
685 /* Enable AIF */
686 /* enable the PLL before we use it to clock the DAI */
687 twl4030_apll_enable(w->codec, 1);
688
689 twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
690 audio_if | TWL4030_AIF_EN);
691 break;
692 case SND_SOC_DAPM_POST_PMD:
693 /* disable the DAI before we stop it's source PLL */
694 twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
695 audio_if & ~TWL4030_AIF_EN);
696 twl4030_apll_enable(w->codec, 0);
697 break;
698 }
699 return 0;
700}
701
675static void headset_ramp(struct snd_soc_codec *codec, int ramp) 702static void headset_ramp(struct snd_soc_codec *codec, int ramp)
676{ 703{
677 struct snd_soc_device *socdev = codec->socdev; 704 struct snd_soc_device *socdev = codec->socdev;
@@ -1180,6 +1207,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1180 SND_SOC_DAPM_OUTPUT("HFR"), 1207 SND_SOC_DAPM_OUTPUT("HFR"),
1181 SND_SOC_DAPM_OUTPUT("VIBRA"), 1208 SND_SOC_DAPM_OUTPUT("VIBRA"),
1182 1209
1210 /* AIF and APLL clocks for running DAIs (including loopback) */
1211 SND_SOC_DAPM_OUTPUT("Virtual HiFi OUT"),
1212 SND_SOC_DAPM_INPUT("Virtual HiFi IN"),
1213 SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"),
1214
1183 /* DACs */ 1215 /* DACs */
1184 SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback", 1216 SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback",
1185 SND_SOC_NOPM, 0, 0), 1217 SND_SOC_NOPM, 0, 0),
@@ -1243,7 +1275,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1243 SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event, 1275 SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
1244 SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), 1276 SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
1245 1277
1246 SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0), 1278 SND_SOC_DAPM_SUPPLY("AIF Enable", SND_SOC_NOPM, 0, 0, aif_event,
1279 SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
1247 1280
1248 /* Output MIXER controls */ 1281 /* Output MIXER controls */
1249 /* Earpiece */ 1282 /* Earpiece */
@@ -1373,10 +1406,6 @@ static const struct snd_soc_dapm_route intercon[] = {
1373 {"Digital Voice Playback Mixer", NULL, "DAC Voice"}, 1406 {"Digital Voice Playback Mixer", NULL, "DAC Voice"},
1374 1407
1375 /* Supply for the digital part (APLL) */ 1408 /* Supply for the digital part (APLL) */
1376 {"Digital R1 Playback Mixer", NULL, "APLL Enable"},
1377 {"Digital L1 Playback Mixer", NULL, "APLL Enable"},
1378 {"Digital R2 Playback Mixer", NULL, "APLL Enable"},
1379 {"Digital L2 Playback Mixer", NULL, "APLL Enable"},
1380 {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, 1409 {"Digital Voice Playback Mixer", NULL, "APLL Enable"},
1381 1410
1382 {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, 1411 {"Digital R1 Playback Mixer", NULL, "AIF Enable"},
@@ -1450,6 +1479,14 @@ static const struct snd_soc_dapm_route intercon[] = {
1450 {"Vibra Mux", "AudioR2", "DAC Right2"}, 1479 {"Vibra Mux", "AudioR2", "DAC Right2"},
1451 1480
1452 /* outputs */ 1481 /* outputs */
1482 /* Must be always connected (for AIF and APLL) */
1483 {"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"},
1484 {"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"},
1485 {"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"},
1486 {"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"},
1487 /* Must be always connected (for APLL) */
1488 {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"},
1489 /* Physical outputs */
1453 {"OUTL", NULL, "Analog L2 Playback Mixer"}, 1490 {"OUTL", NULL, "Analog L2 Playback Mixer"},
1454 {"OUTR", NULL, "Analog R2 Playback Mixer"}, 1491 {"OUTR", NULL, "Analog R2 Playback Mixer"},
1455 {"EARPIECE", NULL, "Earpiece PGA"}, 1492 {"EARPIECE", NULL, "Earpiece PGA"},
@@ -1465,6 +1502,12 @@ static const struct snd_soc_dapm_route intercon[] = {
1465 {"VIBRA", NULL, "Vibra Route"}, 1502 {"VIBRA", NULL, "Vibra Route"},
1466 1503
1467 /* Capture path */ 1504 /* Capture path */
1505 /* Must be always connected (for AIF and APLL) */
1506 {"ADC Virtual Left1", NULL, "Virtual HiFi IN"},
1507 {"ADC Virtual Right1", NULL, "Virtual HiFi IN"},
1508 {"ADC Virtual Left2", NULL, "Virtual HiFi IN"},
1509 {"ADC Virtual Right2", NULL, "Virtual HiFi IN"},
1510 /* Physical inputs */
1468 {"Analog Left", "Main Mic Capture Switch", "MAINMIC"}, 1511 {"Analog Left", "Main Mic Capture Switch", "MAINMIC"},
1469 {"Analog Left", "Headset Mic Capture Switch", "HSMIC"}, 1512 {"Analog Left", "Headset Mic Capture Switch", "HSMIC"},
1470 {"Analog Left", "AUXL Capture Switch", "AUXL"}, 1513 {"Analog Left", "AUXL Capture Switch", "AUXL"},
@@ -1497,11 +1540,6 @@ static const struct snd_soc_dapm_route intercon[] = {
1497 {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, 1540 {"ADC Virtual Left2", NULL, "TX2 Capture Route"},
1498 {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, 1541 {"ADC Virtual Right2", NULL, "TX2 Capture Route"},
1499 1542
1500 {"ADC Virtual Left1", NULL, "APLL Enable"},
1501 {"ADC Virtual Right1", NULL, "APLL Enable"},
1502 {"ADC Virtual Left2", NULL, "APLL Enable"},
1503 {"ADC Virtual Right2", NULL, "APLL Enable"},
1504
1505 {"ADC Virtual Left1", NULL, "AIF Enable"}, 1543 {"ADC Virtual Left1", NULL, "AIF Enable"},
1506 {"ADC Virtual Right1", NULL, "AIF Enable"}, 1544 {"ADC Virtual Right1", NULL, "AIF Enable"},
1507 {"ADC Virtual Left2", NULL, "AIF Enable"}, 1545 {"ADC Virtual Left2", NULL, "AIF Enable"},