aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2010-04-29 03:58:08 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-05-03 07:47:29 -0400
commit7b4c734eead5ef0b1c95ec336ddd28e58e648676 (patch)
tree61f824f0cf0ee5f3f850cac8252b89a646fdb7de /sound
parentcf134d5bfb19cdee922b95738ce3cfe86c0e8f7a (diff)
ASoC: TWL4030: AIF/APLL fix in DAPM domain
This patch orders the APLL and AIF power sequence in case of HiFi (audio in TWL4030 terms) playback/capture. We also need to make sure that the AIF is running during playback/capture, when there is no valid DAPM route available. For this purpose I introduce these virtual widgets: /* To have complete playback route all the time */ DAPM_OUTPUT("Virtual HiFi OUT") /* Will keep AIF/APLL enabled */ /* To have complete capture route all the time */ DAPM_INPUT("Virtual HiFi IN") /* Will keep AIF/APLL enabled */ /* To have complete playback route for the voice module */ DAPM_OUTPUT("Virtual Voice OUT") /* Will keep APLL enabled */ The DAPM_SUPPLY widgets for APLL and AIF are placed in a way, that during any audio activity the needed configuration of AIF and APLL will be enabled (playback, capture, analog loopback, digital loopback, and voice activity). The apll reference counting code has been lifted, and modified from Liam Girdwood's earlier patch. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound')
-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"},