Skip to content

Commit

Permalink
ASoC: Add power supply widget to DAPM
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
broonie committed Apr 22, 2009
1 parent 1b4246a commit 246d0a1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
1 change: 1 addition & 0 deletions Documentation/sound/alsa/soc/dapm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Audio DAPM widgets fall into a number of types:-
o Mic - Mic (and optional Jack)
o Line - Line Input/Output (and optional Jack)
o Speaker - Speaker
o Supply - Power or clock supply widget used by other widgets.
o Pre - Special PRE widget (exec before all others)
o Post - Special POST widget (exec after all others)

Expand Down
7 changes: 6 additions & 1 deletion include/sound/soc-dapm.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,16 @@
.shift = wshift, .invert = winvert, \
.event = wevent, .event_flags = wflags}

/* generic register modifier widget */
/* generic widgets */
#define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
{ .id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
.reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \
.shift = wshift, .invert = winvert, .event = wevent, \
.event_flags = wflags}

/* dapm kcontrol types */
#define SOC_DAPM_SINGLE(xname, reg, shift, max, invert) \
Expand Down Expand Up @@ -308,6 +312,7 @@ enum snd_soc_dapm_type {
snd_soc_dapm_vmid, /* codec bias/vmid - to minimise pops */
snd_soc_dapm_pre, /* machine specific pre widget - exec first */
snd_soc_dapm_post, /* machine specific post widget - exec last */
snd_soc_dapm_supply, /* power/clock supply */
};

/*
Expand Down
44 changes: 39 additions & 5 deletions sound/soc/soc-dapm.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,19 @@

/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac,
snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_pga,
snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias,
snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl,
snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
snd_soc_dapm_post
};

static int dapm_down_seq[] = {
snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_post
snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply,
snd_soc_dapm_post
};

static int dapm_status = 1;
Expand Down Expand Up @@ -165,6 +167,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_dac:
case snd_soc_dapm_micbias:
case snd_soc_dapm_vmid:
case snd_soc_dapm_supply:
p->connect = 1;
break;
/* does effect routing - dynamically connected */
Expand Down Expand Up @@ -435,6 +438,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
struct snd_soc_dapm_path *path;
int con = 0;

if (widget->id == snd_soc_dapm_supply)
return 0;

if (widget->id == snd_soc_dapm_adc && widget->active)
return 1;

Expand Down Expand Up @@ -471,6 +477,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
struct snd_soc_dapm_path *path;
int con = 0;

if (widget->id == snd_soc_dapm_supply)
return 0;

/* active stream ? */
if (widget->id == snd_soc_dapm_dac && widget->active)
return 1;
Expand Down Expand Up @@ -622,6 +631,26 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
}
}

/* Check to see if a power supply is needed */
static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
{
struct snd_soc_dapm_path *path;
int power = 0;

/* Check if one of our outputs is connected */
list_for_each_entry(path, &w->sinks, list_source) {
if (path->sink && path->sink->power_check &&
path->sink->power_check(path->sink)) {
power = 1;
break;
}
}

dapm_clear_walk(w->codec);

return power;
}

/*
* Scan a single DAPM widget for a complete audio path and update the
* power status appropriately.
Expand Down Expand Up @@ -752,6 +781,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
case snd_soc_dapm_pga:
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
case snd_soc_dapm_supply:
if (w->name) {
in = is_connected_input_ep(w);
dapm_clear_walk(w->codec);
Expand Down Expand Up @@ -880,6 +910,7 @@ static ssize_t dapm_widget_show(struct device *dev,
case snd_soc_dapm_pga:
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
case snd_soc_dapm_supply:
if (w->name)
count += sprintf(buf + count, "%s: %s\n",
w->name, w->power ? "On":"Off");
Expand Down Expand Up @@ -1044,6 +1075,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
case snd_soc_dapm_vmid:
case snd_soc_dapm_pre:
case snd_soc_dapm_post:
case snd_soc_dapm_supply:
list_add(&path->list, &codec->dapm_paths);
list_add(&path->list_sink, &wsink->sources);
list_add(&path->list_source, &wsource->sinks);
Expand Down Expand Up @@ -1164,6 +1196,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
case snd_soc_dapm_line:
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_supply:
w->power_check = dapm_supply_check_power;
case snd_soc_dapm_vmid:
case snd_soc_dapm_pre:
case snd_soc_dapm_post:
Expand Down

0 comments on commit 246d0a1

Please sign in to comment.