diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-09-21 12:59:02 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-09-22 12:24:32 -0400 |
commit | 7aefb086c15fc44066e705e479d012d46476d8c5 (patch) | |
tree | e6a262fbf261a5a49f0b960bf984a188390cc774 /sound/soc/codecs/wm5100.c | |
parent | ab6cf13943303f865320407b17b0f86095d23ce3 (diff) |
ASoC: Dynamically manage DBVDD2 and DBVDD3 on WM5100
Allow the DBVDD2 and DBVDD3 rails to be powered down when idle, helping
fully power down connected devices when idle.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm5100.c')
-rw-r--r-- | sound/soc/codecs/wm5100.c | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 576081a2de10..443d76d3d182 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
@@ -54,6 +54,8 @@ struct wm5100_priv { | |||
54 | 54 | ||
55 | struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES]; | 55 | struct regulator_bulk_data core_supplies[WM5100_NUM_CORE_SUPPLIES]; |
56 | struct regulator *cpvdd; | 56 | struct regulator *cpvdd; |
57 | struct regulator *dbvdd2; | ||
58 | struct regulator *dbvdd3; | ||
57 | 59 | ||
58 | int rev; | 60 | int rev; |
59 | 61 | ||
@@ -803,6 +805,52 @@ static int wm5100_cp_ev(struct snd_soc_dapm_widget *w, | |||
803 | } | 805 | } |
804 | } | 806 | } |
805 | 807 | ||
808 | static int wm5100_dbvdd_ev(struct snd_soc_dapm_widget *w, | ||
809 | struct snd_kcontrol *kcontrol, | ||
810 | int event) | ||
811 | { | ||
812 | struct snd_soc_codec *codec = w->codec; | ||
813 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); | ||
814 | struct regulator *regulator; | ||
815 | int ret; | ||
816 | |||
817 | switch (w->shift) { | ||
818 | case 2: | ||
819 | regulator = wm5100->dbvdd2; | ||
820 | break; | ||
821 | case 3: | ||
822 | regulator = wm5100->dbvdd3; | ||
823 | break; | ||
824 | default: | ||
825 | BUG(); | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | switch (event) { | ||
830 | case SND_SOC_DAPM_PRE_PMU: | ||
831 | ret = regulator_enable(regulator); | ||
832 | if (ret != 0) { | ||
833 | dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n", | ||
834 | w->shift, ret); | ||
835 | return ret; | ||
836 | } | ||
837 | return ret; | ||
838 | |||
839 | case SND_SOC_DAPM_POST_PMD: | ||
840 | ret = regulator_disable(regulator); | ||
841 | if (ret != 0) { | ||
842 | dev_err(codec->dev, "Failed to enable DBVDD%d: %d\n", | ||
843 | w->shift, ret); | ||
844 | return ret; | ||
845 | } | ||
846 | return ret; | ||
847 | |||
848 | default: | ||
849 | BUG(); | ||
850 | return 0; | ||
851 | } | ||
852 | } | ||
853 | |||
806 | static void wm5100_log_status3(struct snd_soc_codec *codec, int val) | 854 | static void wm5100_log_status3(struct snd_soc_codec *codec, int val) |
807 | { | 855 | { |
808 | if (val & WM5100_SPK_SHUTDOWN_WARN_EINT) | 856 | if (val & WM5100_SPK_SHUTDOWN_WARN_EINT) |
@@ -880,6 +928,10 @@ SND_SOC_DAPM_SUPPLY("CP2", WM5100_MIC_CHARGE_PUMP_1, WM5100_CP2_ENA_SHIFT, 0, | |||
880 | SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1, | 928 | SND_SOC_DAPM_SUPPLY("CP2 Active", WM5100_MIC_CHARGE_PUMP_1, |
881 | WM5100_CP2_BYPASS_SHIFT, 1, wm5100_cp_ev, | 929 | WM5100_CP2_BYPASS_SHIFT, 1, wm5100_cp_ev, |
882 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | 930 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
931 | SND_SOC_DAPM_SUPPLY("DBVDD2", SND_SOC_NOPM, 2, 0, wm5100_dbvdd_ev, | ||
932 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
933 | SND_SOC_DAPM_SUPPLY("DBVDD3", SND_SOC_NOPM, 3, 0, wm5100_dbvdd_ev, | ||
934 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
883 | 935 | ||
884 | SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT, | 936 | SND_SOC_DAPM_SUPPLY("MICBIAS1", WM5100_MIC_BIAS_CTRL_1, WM5100_MICB1_ENA_SHIFT, |
885 | 0, NULL, 0), | 937 | 0, NULL, 0), |
@@ -1122,10 +1174,14 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { | |||
1122 | { "AIF1RX8", NULL, "SYSCLK" }, | 1174 | { "AIF1RX8", NULL, "SYSCLK" }, |
1123 | 1175 | ||
1124 | { "AIF2RX1", NULL, "SYSCLK" }, | 1176 | { "AIF2RX1", NULL, "SYSCLK" }, |
1177 | { "AIF2RX1", NULL, "DBVDD2" }, | ||
1125 | { "AIF2RX2", NULL, "SYSCLK" }, | 1178 | { "AIF2RX2", NULL, "SYSCLK" }, |
1179 | { "AIF2RX2", NULL, "DBVDD2" }, | ||
1126 | 1180 | ||
1127 | { "AIF3RX1", NULL, "SYSCLK" }, | 1181 | { "AIF3RX1", NULL, "SYSCLK" }, |
1182 | { "AIF3RX1", NULL, "DBVDD3" }, | ||
1128 | { "AIF3RX2", NULL, "SYSCLK" }, | 1183 | { "AIF3RX2", NULL, "SYSCLK" }, |
1184 | { "AIF3RX2", NULL, "DBVDD3" }, | ||
1129 | 1185 | ||
1130 | { "AIF1TX1", NULL, "SYSCLK" }, | 1186 | { "AIF1TX1", NULL, "SYSCLK" }, |
1131 | { "AIF1TX2", NULL, "SYSCLK" }, | 1187 | { "AIF1TX2", NULL, "SYSCLK" }, |
@@ -1137,10 +1193,14 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { | |||
1137 | { "AIF1TX8", NULL, "SYSCLK" }, | 1193 | { "AIF1TX8", NULL, "SYSCLK" }, |
1138 | 1194 | ||
1139 | { "AIF2TX1", NULL, "SYSCLK" }, | 1195 | { "AIF2TX1", NULL, "SYSCLK" }, |
1196 | { "AIF2TX1", NULL, "DBVDD2" }, | ||
1140 | { "AIF2TX2", NULL, "SYSCLK" }, | 1197 | { "AIF2TX2", NULL, "SYSCLK" }, |
1198 | { "AIF2TX2", NULL, "DBVDD2" }, | ||
1141 | 1199 | ||
1142 | { "AIF3TX1", NULL, "SYSCLK" }, | 1200 | { "AIF3TX1", NULL, "SYSCLK" }, |
1201 | { "AIF3TX1", NULL, "DBVDD3" }, | ||
1143 | { "AIF3TX2", NULL, "SYSCLK" }, | 1202 | { "AIF3TX2", NULL, "SYSCLK" }, |
1203 | { "AIF3TX2", NULL, "DBVDD3" }, | ||
1144 | 1204 | ||
1145 | { "MICBIAS1", NULL, "CP2" }, | 1205 | { "MICBIAS1", NULL, "CP2" }, |
1146 | { "MICBIAS2", NULL, "CP2" }, | 1206 | { "MICBIAS2", NULL, "CP2" }, |
@@ -2250,12 +2310,26 @@ static int wm5100_probe(struct snd_soc_codec *codec) | |||
2250 | goto err_core; | 2310 | goto err_core; |
2251 | } | 2311 | } |
2252 | 2312 | ||
2313 | wm5100->dbvdd2 = regulator_get(&i2c->dev, "DBVDD2"); | ||
2314 | if (IS_ERR(wm5100->dbvdd2)) { | ||
2315 | ret = PTR_ERR(wm5100->dbvdd2); | ||
2316 | dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret); | ||
2317 | goto err_cpvdd; | ||
2318 | } | ||
2319 | |||
2320 | wm5100->dbvdd3 = regulator_get(&i2c->dev, "DBVDD3"); | ||
2321 | if (IS_ERR(wm5100->dbvdd3)) { | ||
2322 | ret = PTR_ERR(wm5100->dbvdd3); | ||
2323 | dev_err(&i2c->dev, "Failed to get DBVDD2: %d\n", ret); | ||
2324 | goto err_dbvdd2; | ||
2325 | } | ||
2326 | |||
2253 | ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies), | 2327 | ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies), |
2254 | wm5100->core_supplies); | 2328 | wm5100->core_supplies); |
2255 | if (ret != 0) { | 2329 | if (ret != 0) { |
2256 | dev_err(codec->dev, "Failed to enable core supplies: %d\n", | 2330 | dev_err(codec->dev, "Failed to enable core supplies: %d\n", |
2257 | ret); | 2331 | ret); |
2258 | goto err_cpvdd; | 2332 | goto err_dbvdd3; |
2259 | } | 2333 | } |
2260 | 2334 | ||
2261 | if (wm5100->pdata.ldo_ena) { | 2335 | if (wm5100->pdata.ldo_ena) { |
@@ -2432,6 +2506,10 @@ err_ldo: | |||
2432 | err_enable: | 2506 | err_enable: |
2433 | regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), | 2507 | regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies), |
2434 | wm5100->core_supplies); | 2508 | wm5100->core_supplies); |
2509 | err_dbvdd3: | ||
2510 | regulator_put(wm5100->dbvdd3); | ||
2511 | err_dbvdd2: | ||
2512 | regulator_put(wm5100->dbvdd2); | ||
2435 | err_cpvdd: | 2513 | err_cpvdd: |
2436 | regulator_put(wm5100->cpvdd); | 2514 | regulator_put(wm5100->cpvdd); |
2437 | err_core: | 2515 | err_core: |
@@ -2458,6 +2536,8 @@ static int wm5100_remove(struct snd_soc_codec *codec) | |||
2458 | gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); | 2536 | gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0); |
2459 | gpio_free(wm5100->pdata.ldo_ena); | 2537 | gpio_free(wm5100->pdata.ldo_ena); |
2460 | } | 2538 | } |
2539 | regulator_put(wm5100->dbvdd3); | ||
2540 | regulator_put(wm5100->dbvdd2); | ||
2461 | regulator_put(wm5100->cpvdd); | 2541 | regulator_put(wm5100->cpvdd); |
2462 | regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies), | 2542 | regulator_bulk_free(ARRAY_SIZE(wm5100->core_supplies), |
2463 | wm5100->core_supplies); | 2543 | wm5100->core_supplies); |