aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-04-22 13:24:55 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-04-22 14:10:13 -0400
commit246d0a17f5e09af0794960164269fc8988a8811c (patch)
tree3c10da44183691038959ba0b53d5598ac1aaabc4
parent1b4246a1fc487370665bf6c55aac8eae379642c0 (diff)
ASoC: Add power supply widget to DAPM
Many modern CODECs have shared resources on chip which must be enabled for portions of the chip to work but which can be disabled at other times in order to achieve power savings. Examples of such resources include power supplies and some internal clocks. Since these widgets are dependencies for the audio path but do not carry audio signals they require slightly different handling to most widgets - they do not contribute to the audio path and so should not be counted as either inputs or outputs during path walks. Cases where one supply provides a supply for another will require additional work. There is also room for more optimisation of the graph walking to avoid repeated checks for the same thing. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--Documentation/sound/alsa/soc/dapm.txt1
-rw-r--r--include/sound/soc-dapm.h7
-rw-r--r--sound/soc/soc-dapm.c44
3 files changed, 46 insertions, 6 deletions
diff --git a/Documentation/sound/alsa/soc/dapm.txt b/Documentation/sound/alsa/soc/dapm.txt
index 9e6763264a2e..9ac842be9b4f 100644
--- a/Documentation/sound/alsa/soc/dapm.txt
+++ b/Documentation/sound/alsa/soc/dapm.txt
@@ -62,6 +62,7 @@ Audio DAPM widgets fall into a number of types:-
62 o Mic - Mic (and optional Jack) 62 o Mic - Mic (and optional Jack)
63 o Line - Line Input/Output (and optional Jack) 63 o Line - Line Input/Output (and optional Jack)
64 o Speaker - Speaker 64 o Speaker - Speaker
65 o Supply - Power or clock supply widget used by other widgets.
65 o Pre - Special PRE widget (exec before all others) 66 o Pre - Special PRE widget (exec before all others)
66 o Post - Special POST widget (exec after all others) 67 o Post - Special POST widget (exec after all others)
67 68
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 839a97b63269..533f9f256496 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -154,12 +154,16 @@
154 .shift = wshift, .invert = winvert, \ 154 .shift = wshift, .invert = winvert, \
155 .event = wevent, .event_flags = wflags} 155 .event = wevent, .event_flags = wflags}
156 156
157/* generic register modifier widget */ 157/* generic widgets */
158#define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \ 158#define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
159{ .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \ 159{ .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
160 .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \ 160 .reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
161 .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ 161 .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
162 .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} 162 .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
163#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
164{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \
165 .shift = wshift, .invert = winvert, .event = wevent, \
166 .event_flags = wflags}
163 167
164/* dapm kcontrol types */ 168/* dapm kcontrol types */
165#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \ 169#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
@@ -308,6 +312,7 @@ enum snd_soc_dapm_type {
308 snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */ 312 snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
309 snd_soc_dapm_pre, /* machine specific pre widget - exec first */ 313 snd_soc_dapm_pre, /* machine specific pre widget - exec first */
310 snd_soc_dapm_post, /* machine specific post widget - exec last */ 314 snd_soc_dapm_post, /* machine specific post widget - exec last */
315 snd_soc_dapm_supply, /* power/clock supply */
311}; 316};
312 317
313/* 318/*
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d3d17354e76c..7847f80e96d1 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -52,17 +52,19 @@
52 52
53/* dapm power sequences - make this per codec in the future */ 53/* dapm power sequences - make this per codec in the future */
54static int dapm_up_seq[] = { 54static int dapm_up_seq[] = {
55 snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, 55 snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias,
56 snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, 56 snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
57 snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga, 57 snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl,
58 snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post 58 snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
59 snd_soc_dapm_post
59}; 60};
60 61
61static int dapm_down_seq[] = { 62static int dapm_down_seq[] = {
62 snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, 63 snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
63 snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer, 64 snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
64 snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias, 65 snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
65 snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post 66 snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply,
67 snd_soc_dapm_post
66}; 68};
67 69
68static int dapm_status = 1; 70static int dapm_status = 1;
@@ -165,6 +167,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
165 case snd_soc_dapm_dac: 167 case snd_soc_dapm_dac:
166 case snd_soc_dapm_micbias: 168 case snd_soc_dapm_micbias:
167 case snd_soc_dapm_vmid: 169 case snd_soc_dapm_vmid:
170 case snd_soc_dapm_supply:
168 p->connect = 1; 171 p->connect = 1;
169 break; 172 break;
170 /* does effect routing - dynamically connected */ 173 /* does effect routing - dynamically connected */
@@ -435,6 +438,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
435 struct snd_soc_dapm_path *path; 438 struct snd_soc_dapm_path *path;
436 int con = 0; 439 int con = 0;
437 440
441 if (widget->id == snd_soc_dapm_supply)
442 return 0;
443
438 if (widget->id == snd_soc_dapm_adc && widget->active) 444 if (widget->id == snd_soc_dapm_adc && widget->active)
439 return 1; 445 return 1;
440 446
@@ -471,6 +477,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
471 struct snd_soc_dapm_path *path; 477 struct snd_soc_dapm_path *path;
472 int con = 0; 478 int con = 0;
473 479
480 if (widget->id == snd_soc_dapm_supply)
481 return 0;
482
474 /* active stream ? */ 483 /* active stream ? */
475 if (widget->id == snd_soc_dapm_dac && widget->active) 484 if (widget->id == snd_soc_dapm_dac && widget->active)
476 return 1; 485 return 1;
@@ -622,6 +631,26 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
622 } 631 }
623} 632}
624 633
634/* Check to see if a power supply is needed */
635static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
636{
637 struct snd_soc_dapm_path *path;
638 int power = 0;
639
640 /* Check if one of our outputs is connected */
641 list_for_each_entry(path, &w->sinks, list_source) {
642 if (path->sink && path->sink->power_check &&
643 path->sink->power_check(path->sink)) {
644 power = 1;
645 break;
646 }
647 }
648
649 dapm_clear_walk(w->codec);
650
651 return power;
652}
653
625/* 654/*
626 * Scan a single DAPM widget for a complete audio path and update the 655 * Scan a single DAPM widget for a complete audio path and update the
627 * power status appropriately. 656 * power status appropriately.
@@ -752,6 +781,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
752 case snd_soc_dapm_pga: 781 case snd_soc_dapm_pga:
753 case snd_soc_dapm_mixer: 782 case snd_soc_dapm_mixer:
754 case snd_soc_dapm_mixer_named_ctl: 783 case snd_soc_dapm_mixer_named_ctl:
784 case snd_soc_dapm_supply:
755 if (w->name) { 785 if (w->name) {
756 in = is_connected_input_ep(w); 786 in = is_connected_input_ep(w);
757 dapm_clear_walk(w->codec); 787 dapm_clear_walk(w->codec);
@@ -880,6 +910,7 @@ static ssize_t dapm_widget_show(struct device *dev,
880 case snd_soc_dapm_pga: 910 case snd_soc_dapm_pga:
881 case snd_soc_dapm_mixer: 911 case snd_soc_dapm_mixer:
882 case snd_soc_dapm_mixer_named_ctl: 912 case snd_soc_dapm_mixer_named_ctl:
913 case snd_soc_dapm_supply:
883 if (w->name) 914 if (w->name)
884 count += sprintf(buf + count, "%s: %s\n", 915 count += sprintf(buf + count, "%s: %s\n",
885 w->name, w->power ? "On":"Off"); 916 w->name, w->power ? "On":"Off");
@@ -1044,6 +1075,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
1044 case snd_soc_dapm_vmid: 1075 case snd_soc_dapm_vmid:
1045 case snd_soc_dapm_pre: 1076 case snd_soc_dapm_pre:
1046 case snd_soc_dapm_post: 1077 case snd_soc_dapm_post:
1078 case snd_soc_dapm_supply:
1047 list_add(&path->list, &codec->dapm_paths); 1079 list_add(&path->list, &codec->dapm_paths);
1048 list_add(&path->list_sink, &wsink->sources); 1080 list_add(&path->list_sink, &wsink->sources);
1049 list_add(&path->list_source, &wsource->sinks); 1081 list_add(&path->list_source, &wsource->sinks);
@@ -1164,6 +1196,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
1164 case snd_soc_dapm_line: 1196 case snd_soc_dapm_line:
1165 w->power_check = dapm_generic_check_power; 1197 w->power_check = dapm_generic_check_power;
1166 break; 1198 break;
1199 case snd_soc_dapm_supply:
1200 w->power_check = dapm_supply_check_power;
1167 case snd_soc_dapm_vmid: 1201 case snd_soc_dapm_vmid:
1168 case snd_soc_dapm_pre: 1202 case snd_soc_dapm_pre:
1169 case snd_soc_dapm_post: 1203 case snd_soc_dapm_post: