aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl4030.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r--sound/soc/codecs/twl4030.c86
1 files changed, 60 insertions, 26 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 2e025a3a2618..b717a03dfacf 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;
@@ -1167,8 +1194,6 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1167 SND_SOC_DAPM_INPUT("DIGIMIC1"), 1194 SND_SOC_DAPM_INPUT("DIGIMIC1"),
1168 1195
1169 /* Outputs */ 1196 /* Outputs */
1170 SND_SOC_DAPM_OUTPUT("OUTL"),
1171 SND_SOC_DAPM_OUTPUT("OUTR"),
1172 SND_SOC_DAPM_OUTPUT("EARPIECE"), 1197 SND_SOC_DAPM_OUTPUT("EARPIECE"),
1173 SND_SOC_DAPM_OUTPUT("PREDRIVEL"), 1198 SND_SOC_DAPM_OUTPUT("PREDRIVEL"),
1174 SND_SOC_DAPM_OUTPUT("PREDRIVER"), 1199 SND_SOC_DAPM_OUTPUT("PREDRIVER"),
@@ -1180,6 +1205,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1180 SND_SOC_DAPM_OUTPUT("HFR"), 1205 SND_SOC_DAPM_OUTPUT("HFR"),
1181 SND_SOC_DAPM_OUTPUT("VIBRA"), 1206 SND_SOC_DAPM_OUTPUT("VIBRA"),
1182 1207
1208 /* AIF and APLL clocks for running DAIs (including loopback) */
1209 SND_SOC_DAPM_OUTPUT("Virtual HiFi OUT"),
1210 SND_SOC_DAPM_INPUT("Virtual HiFi IN"),
1211 SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"),
1212
1183 /* DACs */ 1213 /* DACs */
1184 SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback", 1214 SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback",
1185 SND_SOC_NOPM, 0, 0), 1215 SND_SOC_NOPM, 0, 0),
@@ -1243,7 +1273,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, 1273 SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
1244 SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD), 1274 SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
1245 1275
1246 SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0), 1276 SND_SOC_DAPM_SUPPLY("AIF Enable", SND_SOC_NOPM, 0, 0, aif_event,
1277 SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
1247 1278
1248 /* Output MIXER controls */ 1279 /* Output MIXER controls */
1249 /* Earpiece */ 1280 /* Earpiece */
@@ -1373,10 +1404,6 @@ static const struct snd_soc_dapm_route intercon[] = {
1373 {"Digital Voice Playback Mixer", NULL, "DAC Voice"}, 1404 {"Digital Voice Playback Mixer", NULL, "DAC Voice"},
1374 1405
1375 /* Supply for the digital part (APLL) */ 1406 /* 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"}, 1407 {"Digital Voice Playback Mixer", NULL, "APLL Enable"},
1381 1408
1382 {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, 1409 {"Digital R1 Playback Mixer", NULL, "AIF Enable"},
@@ -1450,8 +1477,14 @@ static const struct snd_soc_dapm_route intercon[] = {
1450 {"Vibra Mux", "AudioR2", "DAC Right2"}, 1477 {"Vibra Mux", "AudioR2", "DAC Right2"},
1451 1478
1452 /* outputs */ 1479 /* outputs */
1453 {"OUTL", NULL, "Analog L2 Playback Mixer"}, 1480 /* Must be always connected (for AIF and APLL) */
1454 {"OUTR", NULL, "Analog R2 Playback Mixer"}, 1481 {"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"},
1482 {"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"},
1483 {"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"},
1484 {"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"},
1485 /* Must be always connected (for APLL) */
1486 {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"},
1487 /* Physical outputs */
1455 {"EARPIECE", NULL, "Earpiece PGA"}, 1488 {"EARPIECE", NULL, "Earpiece PGA"},
1456 {"PREDRIVEL", NULL, "PredriveL PGA"}, 1489 {"PREDRIVEL", NULL, "PredriveL PGA"},
1457 {"PREDRIVER", NULL, "PredriveR PGA"}, 1490 {"PREDRIVER", NULL, "PredriveR PGA"},
@@ -1465,6 +1498,12 @@ static const struct snd_soc_dapm_route intercon[] = {
1465 {"VIBRA", NULL, "Vibra Route"}, 1498 {"VIBRA", NULL, "Vibra Route"},
1466 1499
1467 /* Capture path */ 1500 /* Capture path */
1501 /* Must be always connected (for AIF and APLL) */
1502 {"ADC Virtual Left1", NULL, "Virtual HiFi IN"},
1503 {"ADC Virtual Right1", NULL, "Virtual HiFi IN"},
1504 {"ADC Virtual Left2", NULL, "Virtual HiFi IN"},
1505 {"ADC Virtual Right2", NULL, "Virtual HiFi IN"},
1506 /* Physical inputs */
1468 {"Analog Left", "Main Mic Capture Switch", "MAINMIC"}, 1507 {"Analog Left", "Main Mic Capture Switch", "MAINMIC"},
1469 {"Analog Left", "Headset Mic Capture Switch", "HSMIC"}, 1508 {"Analog Left", "Headset Mic Capture Switch", "HSMIC"},
1470 {"Analog Left", "AUXL Capture Switch", "AUXL"}, 1509 {"Analog Left", "AUXL Capture Switch", "AUXL"},
@@ -1497,11 +1536,6 @@ static const struct snd_soc_dapm_route intercon[] = {
1497 {"ADC Virtual Left2", NULL, "TX2 Capture Route"}, 1536 {"ADC Virtual Left2", NULL, "TX2 Capture Route"},
1498 {"ADC Virtual Right2", NULL, "TX2 Capture Route"}, 1537 {"ADC Virtual Right2", NULL, "TX2 Capture Route"},
1499 1538
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"}, 1539 {"ADC Virtual Left1", NULL, "AIF Enable"},
1506 {"ADC Virtual Right1", NULL, "AIF Enable"}, 1540 {"ADC Virtual Right1", NULL, "AIF Enable"},
1507 {"ADC Virtual Left2", NULL, "AIF Enable"}, 1541 {"ADC Virtual Left2", NULL, "AIF Enable"},