aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-09-11 05:05:18 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-09-14 05:59:36 -0400
commitc83495af6395446b81da54b17a479557ad0b2fc8 (patch)
tree5c297c65478e1e8113cc05e1b19b8fbcbe60ff60 /sound
parentda07ecd93b196819dcec488b7ebec69a71f3819e (diff)
ASoC: Disable WM8996 CPVDD supply when not in use
The WM8996 only requires CPVDD when the charge pump is active so control it separately to the other supplies, only enabling it when the charge pump is active. This will result in a small power saving on systems which are able to provide independent software control of the supply. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@ti.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm8996.c38
1 files changed, 30 insertions, 8 deletions
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index e386d25aba82..9d0ab87bad96 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -41,12 +41,11 @@
41#define HPOUT2L 4 41#define HPOUT2L 4
42#define HPOUT2R 8 42#define HPOUT2R 8
43 43
44#define WM8996_NUM_SUPPLIES 4 44#define WM8996_NUM_SUPPLIES 3
45static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = { 45static const char *wm8996_supply_names[WM8996_NUM_SUPPLIES] = {
46 "DBVDD", 46 "DBVDD",
47 "AVDD1", 47 "AVDD1",
48 "AVDD2", 48 "AVDD2",
49 "CPVDD",
50}; 49};
51 50
52struct wm8996_priv { 51struct wm8996_priv {
@@ -71,6 +70,7 @@ struct wm8996_priv {
71 70
72 struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES]; 71 struct regulator_bulk_data supplies[WM8996_NUM_SUPPLIES];
73 struct notifier_block disable_nb[WM8996_NUM_SUPPLIES]; 72 struct notifier_block disable_nb[WM8996_NUM_SUPPLIES];
73 struct regulator *cpvdd;
74 74
75 struct wm8996_pdata pdata; 75 struct wm8996_pdata pdata;
76 76
@@ -112,7 +112,6 @@ static int wm8996_regulator_event_##n(struct notifier_block *nb, \
112WM8996_REGULATOR_EVENT(0) 112WM8996_REGULATOR_EVENT(0)
113WM8996_REGULATOR_EVENT(1) 113WM8996_REGULATOR_EVENT(1)
114WM8996_REGULATOR_EVENT(2) 114WM8996_REGULATOR_EVENT(2)
115WM8996_REGULATOR_EVENT(3)
116 115
117static const u16 wm8996_reg[WM8996_MAX_REGISTER] = { 116static const u16 wm8996_reg[WM8996_MAX_REGISTER] = {
118 [WM8996_SOFTWARE_RESET] = 0x8996, 117 [WM8996_SOFTWARE_RESET] = 0x8996,
@@ -670,16 +669,29 @@ SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8996_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
670static int cp_event(struct snd_soc_dapm_widget *w, 669static int cp_event(struct snd_soc_dapm_widget *w,
671 struct snd_kcontrol *kcontrol, int event) 670 struct snd_kcontrol *kcontrol, int event)
672{ 671{
672 struct snd_soc_codec *codec = w->codec;
673 struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
674 int ret = 0;
675
673 switch (event) { 676 switch (event) {
677 case SND_SOC_DAPM_PRE_PMU:
678 ret = regulator_enable(wm8996->cpvdd);
679 if (ret != 0)
680 dev_err(codec->dev, "Failed to enable CPVDD: %d\n",
681 ret);
682 break;
674 case SND_SOC_DAPM_POST_PMU: 683 case SND_SOC_DAPM_POST_PMU:
675 msleep(5); 684 msleep(5);
676 break; 685 break;
686 case SND_SOC_DAPM_POST_PMD:
687 regulator_disable_deferred(wm8996->cpvdd, 20);
688 break;
677 default: 689 default:
678 BUG(); 690 BUG();
679 return -EINVAL; 691 ret = -EINVAL;
680 } 692 }
681 693
682 return 0; 694 return ret;
683} 695}
684 696
685static int rmv_short_event(struct snd_soc_dapm_widget *w, 697static int rmv_short_event(struct snd_soc_dapm_widget *w,
@@ -988,7 +1000,8 @@ SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8996_AIF_CLOCKING_1, 0, 0, NULL, 0),
988SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0), 1000SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8996_CLOCKING_1, 1, 0, NULL, 0),
989SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0), 1001SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8996_CLOCKING_1, 2, 0, NULL, 0),
990SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event, 1002SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8996_CHARGE_PUMP_1, 15, 0, cp_event,
991 SND_SOC_DAPM_POST_PMU), 1003 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
1004 SND_SOC_DAPM_POST_PMD),
992 1005
993SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0), 1006SND_SOC_DAPM_SUPPLY("LDO2", WM8996_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
994SND_SOC_DAPM_SUPPLY("MICB1 Audio", WM8996_MICBIAS_1, 4, 1, NULL, 0), 1007SND_SOC_DAPM_SUPPLY("MICB1 Audio", WM8996_MICBIAS_1, 4, 1, NULL, 0),
@@ -2573,7 +2586,13 @@ static int wm8996_probe(struct snd_soc_codec *codec)
2573 wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0; 2586 wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0;
2574 wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1; 2587 wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1;
2575 wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2; 2588 wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2;
2576 wm8996->disable_nb[3].notifier_call = wm8996_regulator_event_3; 2589
2590 wm8996->cpvdd = regulator_get(&i2c->dev, "CPVDD");
2591 if (IS_ERR(wm8996->cpvdd)) {
2592 ret = PTR_ERR(wm8996->cpvdd);
2593 dev_err(&i2c->dev, "Failed to get CPVDD: %d\n", ret);
2594 goto err_get;
2595 }
2577 2596
2578 /* This should really be moved into the regulator core */ 2597 /* This should really be moved into the regulator core */
2579 for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) { 2598 for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) {
@@ -2590,7 +2609,7 @@ static int wm8996_probe(struct snd_soc_codec *codec)
2590 wm8996->supplies); 2609 wm8996->supplies);
2591 if (ret != 0) { 2610 if (ret != 0) {
2592 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 2611 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
2593 goto err_get; 2612 goto err_cpvdd;
2594 } 2613 }
2595 2614
2596 if (wm8996->pdata.ldo_ena >= 0) { 2615 if (wm8996->pdata.ldo_ena >= 0) {
@@ -2833,6 +2852,8 @@ err_enable:
2833 gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); 2852 gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0);
2834 2853
2835 regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); 2854 regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
2855err_cpvdd:
2856 regulator_put(wm8996->cpvdd);
2836err_get: 2857err_get:
2837 regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); 2858 regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
2838err: 2859err:
@@ -2856,6 +2877,7 @@ static int wm8996_remove(struct snd_soc_codec *codec)
2856 for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) 2877 for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++)
2857 regulator_unregister_notifier(wm8996->supplies[i].consumer, 2878 regulator_unregister_notifier(wm8996->supplies[i].consumer,
2858 &wm8996->disable_nb[i]); 2879 &wm8996->disable_nb[i]);
2880 regulator_put(wm8996->cpvdd);
2859 regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); 2881 regulator_bulk_free(ARRAY_SIZE(wm8996->supplies), wm8996->supplies);
2860 2882
2861 return 0; 2883 return 0;