diff options
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 86 |
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) | |||
259 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) | 261 | static 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 | ||
280 | static void twl4030_power_up(struct snd_soc_codec *codec) | 282 | static 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 | ||
677 | static 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 | |||
675 | static void headset_ramp(struct snd_soc_codec *codec, int ramp) | 702 | static 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"}, |