aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c604
1 files changed, 550 insertions, 54 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 0c9dee2..042d4ae 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -48,6 +48,10 @@
#include <trace/events/asoc.h>
+#define PATH_MAX_HOPS 16
+
+int soc_dsp_runtime_update(struct snd_soc_dapm_widget *);
+
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 0,
@@ -126,6 +130,390 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
}
+static inline struct snd_card *dapm_get_card(struct snd_soc_dapm_context *dapm)
+{
+ if (dapm->codec)
+ return dapm->codec->card->snd_card;
+ else if (dapm->platform)
+ return dapm->platform->card->snd_card;
+ else
+ BUG();
+}
+
+static inline struct snd_soc_card *dapm_get_soc_card(
+ struct snd_soc_dapm_context *dapm)
+{
+ if (dapm->codec)
+ return dapm->codec->card;
+ else if (dapm->platform)
+ return dapm->platform->card;
+ else
+ BUG();
+}
+
+static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
+{
+ if (w->codec)
+ return snd_soc_read(w->codec, reg);
+ else if (w->platform)
+ return snd_soc_platform_read(w->platform, reg);
+ return 0;
+}
+
+static int soc_widget_write(struct snd_soc_dapm_widget *w,int reg, int val)
+{
+ if (w->codec)
+ return snd_soc_write(w->codec, reg, val);
+ else if (w->platform)
+ return snd_soc_platform_write(w->platform, reg, val);
+ return 0;
+}
+
+int soc_widget_update_bits(struct snd_soc_dapm_widget *w, unsigned short reg,
+ unsigned int mask, unsigned int value)
+{
+ int change;
+ unsigned int old, new;
+
+ old = soc_widget_read(w, reg);
+ new = (old & ~mask) | value;
+ change = old != new;
+ if (change)
+ soc_widget_write(w, reg, new);
+
+ return change;
+}
+
+int soc_widget_test_bits(struct snd_soc_dapm_widget *w, unsigned short reg,
+ unsigned int mask, unsigned int value)
+{
+ int change;
+ unsigned int old, new;
+
+ old = soc_widget_read(w, reg);
+ new = (old & ~mask) | value;
+ change = old != new;
+
+ return change;
+}
+
+/* reset 'walked' bit for each dapm path */
+static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
+{
+ struct snd_soc_dapm_path *p;
+
+ list_for_each_entry(p, &dapm->card->paths, list)
+ p->walked = 0;
+}
+
+static void dapm_clear_paths(struct snd_soc_dapm_context *dapm)
+{
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dapm_widget *w;
+ struct list_head *l;
+
+ list_for_each(l, &dapm->card->paths) {
+ p = list_entry(l, struct snd_soc_dapm_path, list);
+ p->length = 0;
+ }
+ list_for_each(l, &dapm->card->widgets) {
+ w = list_entry(l, struct snd_soc_dapm_widget, list);
+ w->hops = 0;
+ }
+ dapm_clear_walk(dapm);
+}
+
+static int dapm_add_unique_widget(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget_list **list, struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_widget_list *wlist;
+ int wlistsize, wlistentries, i;
+
+ /* is the list empty ? */
+ if (*list == NULL) {
+
+ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+ sizeof(struct snd_soc_dapm_widget *);
+ *list = kzalloc(wlistsize, GFP_KERNEL);
+ if (*list == NULL) {
+ dev_err(dapm->dev, "can't allocate widget list for %s\n", w->name);
+ return -ENOMEM;
+ }
+ } else {
+
+ wlist = *list;
+ /* is this widget already in the list */
+ for (i = 0; i < wlist->num_widgets; i++) {
+ if (wlist->widgets[i] == w)
+ return 0;
+ }
+
+ wlistentries = wlist->num_widgets + 1;
+ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+ wlistentries * sizeof(struct snd_soc_dapm_widget *);
+ *list = krealloc(wlist, wlistsize, GFP_KERNEL);
+ if (*list == NULL) {
+ dev_err(dapm->dev, "can't allocate widget list for %s\n", w->name);
+ return -ENOMEM;
+ }
+ }
+ wlist = *list;
+
+ /* insert the widget */
+ dev_dbg(dapm->dev, "added %s in widget list pos %d\n",
+ w->name, wlist->num_widgets);
+ wlist->widgets[wlist->num_widgets] = w;
+ wlist->num_widgets++;
+ return 1;
+}
+
+static int is_output_widget_ep(struct snd_soc_dapm_widget *widget)
+{
+ switch (widget->id) {
+ case snd_soc_dapm_adc:
+ case snd_soc_dapm_aif_out:
+ return 1;
+ case snd_soc_dapm_output:
+ if (widget->connected && !widget->ext)
+ return 1;
+ else
+ return 0;
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_line:
+ return !list_empty(&widget->sources);
+ default:
+ return 0;
+ }
+}
+
+static int is_input_widget_ep(struct snd_soc_dapm_widget *widget)
+{
+ switch (widget->id) {
+ case snd_soc_dapm_dac:
+ case snd_soc_dapm_aif_in:
+ return 1;
+ case snd_soc_dapm_input:
+ if (widget->connected && !widget->ext)
+ return 1;
+ else
+ return 0;
+ case snd_soc_dapm_mic:
+ return !list_empty(&widget->sources);
+ default:
+ return 0;
+ }
+}
+
+/*
+ * find all the paths between source and sink
+ */
+static int dapm_find_playback_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list, int hops)
+{
+ struct list_head *lp;
+ struct snd_soc_dapm_path *path;
+ int dist = 0;
+
+ if (hops > PATH_MAX_HOPS)
+ return 0;
+
+ if (is_output_widget_ep(root) && hops != 1) {
+ dev_dbg(dapm->dev," ! %d: valid playback route found\n", hops);
+ dapm->num_valid_paths++;
+ return 1;
+ }
+
+ if (root->hops && root->hops <= hops)
+ return 0;
+ root->hops = hops;
+
+ /* check all the output paths on this source widget by walking
+ * from source to sink */
+ list_for_each(lp, &root->sinks) {
+ path = list_entry(lp, struct snd_soc_dapm_path, list_source);
+
+ dev_dbg(dapm->dev," %c %d: %s -> %s -> %s\n",
+ path->connect ? '*' : ' ', hops,
+ root->name, path->name, path->sink->name);
+
+ /* been here before ? */
+ if (path->length && path->length <= hops)
+ continue;
+
+ /* check down the next path if connected */
+ if (path->sink && path->connect &&
+ dapm_find_playback_paths(dapm, path->sink, list, hops + 1)) {
+ path->length = hops;
+
+ /* add widget to list */
+ dapm_add_unique_widget(dapm, list, path->sink);
+
+ if (!dist || dist > path->length)
+ dist = path->length;
+ }
+ }
+
+ return dist;
+}
+
+static int dapm_find_capture_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list, int hops)
+{
+ struct list_head *lp;
+ struct snd_soc_dapm_path *path;
+ int dist = 0;
+
+ if (hops > PATH_MAX_HOPS)
+ return 0;
+
+ if (is_input_widget_ep(root) && hops != 1) {
+ dev_dbg(dapm->dev," ! %d: valid capture route found\n", hops);
+ dapm->num_valid_paths++;
+ return 1;
+ }
+
+ if (root->hops && root->hops <= hops)
+ return 0;
+ root->hops = hops;
+
+ /* check all the output paths on this source widget by walking from
+ * sink to source */
+ list_for_each(lp, &root->sources) {
+ path = list_entry(lp, struct snd_soc_dapm_path, list_sink);
+
+ dev_dbg(dapm->dev," %c %d: %s <- %s <- %s\n",
+ path->connect ? '*' : ' ', hops,
+ root->name, path->name, path->source->name);
+
+ /* been here before ? */
+ if (path->length && path->length <= hops)
+ continue;
+
+ /* check down the next path if connected */
+ if (path->source && path->connect &&
+ dapm_find_capture_paths(dapm, path->source, list, hops + 1)) {
+ path->length = hops;
+
+ /* add widget to list */
+ dapm_add_unique_widget(dapm, list, path->source);
+
+ if (!dist || dist > path->length)
+ dist = path->length;
+ }
+ }
+
+ return dist;
+}
+
+/*
+ * traverse the tree from sink to source via the shortest path
+ */
+static int dapm_get_playback_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list)
+{
+ dev_dbg(dapm->dev, "Playback: checking paths from %s\n",root->name);
+ dapm_find_playback_paths(dapm, root, list, 1);
+ return dapm->num_valid_paths;
+}
+
+static int dapm_get_capture_paths(struct snd_soc_dapm_context *dapm,
+ struct snd_soc_dapm_widget *root,
+ struct snd_soc_dapm_widget_list **list)
+{
+ dev_dbg(dapm->dev, "Capture: checking paths to %s\n", root->name);
+ dapm_find_capture_paths(dapm, root, list, 1);
+ return dapm->num_valid_paths;
+}
+
+/**
+ * snd_soc_dapm_get_connected_widgets_type - query audio path and it's widgets.
+ * @dapm: the dapm context.
+ * @stream_name: stream name.
+ * @list: list of active widgets for this stream.
+ * @stream: stream direction.
+ * @type: Initial widget type.
+ *
+ * Queries DAPM graph as to whether an valid audio stream path exists for
+ * the DAPM stream and initial widget type specified. This takes into account
+ * current mixer and mux kcontrol settings. Creates list of valid widgets.
+ *
+ * Returns the number of valid paths or negative error.
+ */
+int snd_soc_dapm_get_connected_widgets_type(struct snd_soc_dapm_context *dapm,
+ const char *stream_name, struct snd_soc_dapm_widget_list **list,
+ int stream, enum snd_soc_dapm_type type)
+{
+ struct snd_soc_dapm_widget *w;
+ int paths;
+
+ /* get stream root widget AIF, DAC or ADC from stream string and direction */
+ list_for_each_entry(w, &dapm->card->widgets, list) {
+
+ if (!w->sname)
+ continue;
+
+ if (w->id != type)
+ continue;
+
+ if (strstr(w->sname, stream_name))
+ goto found;
+ }
+ dev_err(dapm->dev, "root widget not found\n");
+ return 0;
+
+found:
+ dapm->num_valid_paths = 0;
+ *list = NULL;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ paths = dapm_get_playback_paths(dapm, w, list);
+ else
+ paths = dapm_get_capture_paths(dapm, w, list);
+
+ dapm_clear_paths(dapm);
+ return paths;
+}
+/**
+ * snd_soc_dapm_get_connected_widgets_name - query audio path and it's widgets.
+ * @dapm: the dapm context.
+ * @name: initial widget name.
+ * @list: list of active widgets for this stream.
+ * @stream: stream direction.
+ *
+ * Queries DAPM graph as to whether an valid audio stream path exists for
+ * the initial widget specified by name. This takes into account
+ * current mixer and mux kcontrol settings. Creates list of valid widgets.
+ *
+ * Returns the number of valid paths or negative error.
+ */
+int snd_soc_dapm_get_connected_widgets_name(struct snd_soc_dapm_context *dapm,
+ const char *name, struct snd_soc_dapm_widget_list **list, int stream)
+{
+ struct snd_soc_dapm_widget *w;
+ int paths;
+
+ /* get stream root widget AIF, DAC or ADC from stream string and direction */
+ list_for_each_entry(w, &dapm->card->widgets, list) {
+
+ if (strstr(w->name, name))
+ goto found;
+ }
+ dev_err(dapm->dev, "root widget %s not found\n", name);
+ return 0;
+
+found:
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ paths = dapm_get_playback_paths(dapm, w, list);
+ else
+ paths = dapm_get_capture_paths(dapm, w, list);
+
+ dapm_clear_paths(dapm);
+ return paths;
+}
+
/**
* snd_soc_dapm_set_bias_level - set the bias level for the system
* @dapm: DAPM context
@@ -196,7 +584,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
- val = snd_soc_read(w->codec, reg);
+ val = soc_widget_read(w, reg);
val = (val >> shift) & mask;
if ((invert && !val) || (!invert && val))
@@ -212,12 +600,12 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
- val = snd_soc_read(w->codec, e->reg);
+ val = soc_widget_read(w, e->reg);
item = (val >> e->shift_l) & (bitmask - 1);
p->connect = 0;
for (i = 0; i < e->max; i++) {
- if (!(strcmp(p->name, e->texts[i])) && item == i)
+ if (!(strcmp(p->name, snd_soc_get_enum_text(e, i))) && item == i)
p->connect = 1;
}
}
@@ -233,7 +621,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
* that the default mux choice (the first) will be
* correctly powered up during initialization.
*/
- if (!strcmp(p->name, e->texts[0]))
+ if (!strcmp(p->name, snd_soc_get_enum_text(e, 0)))
p->connect = 1;
}
break;
@@ -242,7 +630,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
w->kcontrol_news[i].private_value;
int val, item;
- val = snd_soc_read(w->codec, e->reg);
+ val = soc_widget_read(w, e->reg);
val = (val >> e->shift_l) & e->mask;
for (item = 0; item < e->max; item++) {
if (val == e->values[item])
@@ -251,7 +639,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
p->connect = 0;
for (i = 0; i < e->max; i++) {
- if (!(strcmp(p->name, e->texts[i])) && item == i)
+ if (!(strcmp(p->name, snd_soc_get_enum_text(e, i))) && item == i)
p->connect = 1;
}
}
@@ -292,11 +680,11 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
int i;
for (i = 0; i < e->max; i++) {
- if (!(strcmp(control_name, e->texts[i]))) {
+ if (!(strcmp(control_name, snd_soc_get_enum_text(e, i)))) {
list_add(&path->list, &dapm->card->paths);
list_add(&path->list_sink, &dest->sources);
list_add(&path->list_source, &src->sinks);
- path->name = (char*)e->texts[i];
+ path->name = (char*)snd_soc_get_enum_text(e, i);
dapm_set_path_status(dest, path, 0);
return 0;
}
@@ -494,7 +882,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
wlist->widgets[wlistentries - 1] = w;
if (!kcontrol) {
- if (dapm->codec)
+ if (dapm->codec && dapm->codec->name_prefix)
prefix = dapm->codec->name_prefix;
else
prefix = NULL;
@@ -516,7 +904,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
* cut the prefix off the front of the widget name.
*/
kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
- name + prefix_len, prefix);
+ name, prefix);
ret = snd_ctl_add(card, kcontrol);
if (ret < 0) {
dev_err(dapm->dev,
@@ -546,15 +934,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
return 0;
}
-/* reset 'walked' bit for each dapm path */
-static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
-{
- struct snd_soc_dapm_path *p;
-
- list_for_each_entry(p, &dapm->card->paths, list)
- p->walked = 0;
-}
-
/* We implement power down on suspend by checking the power state of
* the ALSA card - when we are suspending the ALSA state for the card
* is set to D3.
@@ -683,7 +1062,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
else
val = w->off_val;
- snd_soc_update_bits(w->codec, -(w->reg + 1),
+ soc_widget_update_bits(w, -(w->reg + 1),
w->mask << w->shift, val << w->shift);
return 0;
@@ -855,14 +1234,15 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
struct list_head *pending)
{
struct snd_soc_card *card = dapm->card;
- struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_widget *w, *_w;
int reg, power;
unsigned int value = 0;
unsigned int mask = 0;
unsigned int cur_mask;
- reg = list_first_entry(pending, struct snd_soc_dapm_widget,
- power_list)->reg;
+ _w = list_first_entry(pending, struct snd_soc_dapm_widget,
+ power_list);
+ reg = _w->reg;
list_for_each_entry(w, pending, power_list) {
cur_mask = 1 << w->shift;
@@ -887,11 +1267,17 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
}
if (reg >= 0) {
+ /* Any widget will do, they should all be updating the
+ * same register.
+ */
+ w = list_first_entry(pending, struct snd_soc_dapm_widget,
+ power_list);
+
pop_dbg(dapm->dev, card->pop_time,
"pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, card->pop_time);
pop_wait(card->pop_time);
- snd_soc_update_bits(dapm->codec, reg, mask, value);
+ soc_widget_update_bits(_w, reg, mask, value);
}
list_for_each_entry(w, pending, power_list) {
@@ -1114,12 +1500,14 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
trace_snd_soc_dapm_start(card);
list_for_each_entry(d, &card->dapm_list, list)
- if (d->n_widgets || d->codec == NULL)
+ if (d->n_widgets || d->codec == NULL ||
+ strstr(d->codec->name, "null-codec"))
d->dev_power = 0;
/* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down.
*/
+ mutex_lock(&card->power_mutex);
list_for_each_entry(w, &card->widgets, list) {
switch (w->id) {
case snd_soc_dapm_pre:
@@ -1165,7 +1553,11 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
dapm->dev_power = 1;
break;
case SND_SOC_DAPM_STREAM_STOP:
- dapm->dev_power = !!dapm->codec->active;
+#warning need re-work
+ if (dapm->codec)
+ dapm->dev_power = !!dapm->codec->active;
+ else
+ dapm->dev_power = 0;
break;
case SND_SOC_DAPM_STREAM_SUSPEND:
dapm->dev_power = 0;
@@ -1221,6 +1613,8 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
trace_snd_soc_dapm_done(card);
+ mutex_unlock(&card->power_mutex);
+
return 0;
}
@@ -1399,7 +1793,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
#endif
/* test and update the power status of a mux widget */
-static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int change,
int mux, struct soc_enum *e)
{
@@ -1416,29 +1810,33 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
/* find dapm widget path assoc with kcontrol */
list_for_each_entry(path, &widget->dapm->card->paths, list) {
+
if (path->kcontrol != kcontrol)
continue;
- if (!path->name || !e->texts[mux])
+ if (!path->name || !snd_soc_get_enum_text(e, mux))
continue;
found = 1;
/* we now need to match the string in the enum to the path */
- if (!(strcmp(path->name, e->texts[mux])))
+ if (!(strcmp(path->name, snd_soc_get_enum_text(e, mux))))
path->connect = 1; /* new connection */
else
path->connect = 0; /* old connection must be powered down */
}
- if (found)
+ if (found) {
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
+ soc_dsp_runtime_update(widget);
+ }
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */
-static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
- struct snd_kcontrol *kcontrol, int connect)
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int connect)
{
struct snd_soc_dapm_path *path;
int found = 0;
@@ -1459,26 +1857,25 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
break;
}
- if (found)
+ if (found) {
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
+ soc_dsp_runtime_update(widget);
+ }
return 0;
}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
/* show dapm widget status in sys fs */
-static ssize_t dapm_widget_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t widget_show(struct snd_soc_dapm_context *dapm,
+ const char *name, char *buf, ssize_t count)
{
- struct snd_soc_pcm_runtime *rtd =
- container_of(dev, struct snd_soc_pcm_runtime, dev);
- struct snd_soc_codec *codec =rtd->codec;
struct snd_soc_dapm_widget *w;
- int count = 0;
char *state = "not set";
- list_for_each_entry(w, &codec->card->widgets, list) {
- if (w->dapm != &codec->dapm)
- continue;
+ count += sprintf(buf + count, "\n%s\n", name);
+
+ list_for_each_entry(w, &dapm->card->widgets, list) {
/* only display widgets that burnm power */
switch (w->id) {
@@ -1503,7 +1900,7 @@ static ssize_t dapm_widget_show(struct device *dev,
}
}
- switch (codec->dapm.bias_level) {
+ switch (dapm->bias_level) {
case SND_SOC_BIAS_ON:
state = "On";
break;
@@ -1522,6 +1919,21 @@ static ssize_t dapm_widget_show(struct device *dev,
return count;
}
+/* show dapm widget status in sys fs */
+static ssize_t dapm_widget_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct snd_soc_pcm_runtime *rtd =
+ container_of(dev, struct snd_soc_pcm_runtime, dev);
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_platform *platform = rtd->platform;
+ ssize_t count = 0;
+
+ count += widget_show(&codec->dapm, codec->name, buf, count);
+ count += widget_show(&platform->dapm, platform->name, buf, count);
+ return count;
+}
+
static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
int snd_soc_dapm_sys_add(struct device *dev)
@@ -1867,7 +2279,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
/* Read the initial power state from the device */
if (w->reg >= 0) {
- val = snd_soc_read(w->codec, w->reg);
+ val = soc_widget_read(w, w->reg);
val &= 1 << w->shift;
if (w->invert)
val = !val;
@@ -1886,6 +2298,24 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
+const char *snd_soc_dapm_get_aif(struct snd_soc_dapm_context *dapm,
+ const char *stream_name, enum snd_soc_dapm_type type)
+{
+ struct snd_soc_dapm_widget *w;
+
+ list_for_each_entry(w, &dapm->card->widgets, list) {
+
+ if (!w->sname)
+ continue;
+
+ if (w->id == type && strstr(w->sname, stream_name))
+ return w->name;
+
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_aif);
+
/**
* snd_soc_dapm_get_volsw - dapm mixer get callback
* @kcontrol: mixer control
@@ -1983,7 +2413,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- dapm_mixer_update_power(widget, kcontrol, connect);
+ snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
widget->dapm->update = NULL;
}
@@ -2074,7 +2504,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
}
@@ -2135,8 +2565,8 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
widget->value = ucontrol->value.enumerated.item[0];
- dapm_mux_update_power(widget, kcontrol, change,
- widget->value, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, change,
+ widget->value, e);
}
}
@@ -2239,7 +2669,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- dapm_mux_update_power(widget, kcontrol, change, mux, e);
+ snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e);
widget->dapm->update = NULL;
}
@@ -2355,6 +2785,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
dapm->n_widgets++;
w->dapm = dapm;
w->codec = dapm->codec;
+ w->platform = dapm->platform;
INIT_LIST_HEAD(&w->sources);
INIT_LIST_HEAD(&w->sinks);
INIT_LIST_HEAD(&w->list);
@@ -2401,6 +2832,9 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
{
struct snd_soc_dapm_widget *w;
+ if (!dapm)
+ return;
+
list_for_each_entry(w, &dapm->card->widgets, list)
{
if (!w->sname || w->dapm != dapm)
@@ -2425,8 +2859,41 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
}
dapm_power_widgets(dapm, event);
+ /* do we need to notify any clients that DAPM stream is complete */
+ if (dapm->stream_event)
+ dapm->stream_event(dapm);
+}
+
+static void soc_dapm_platform_stream_event(struct snd_soc_platform *platform,
+ const char *stream, int event)
+{
+ soc_dapm_stream_event(&platform->dapm, stream, event);
}
+static void soc_dapm_codec_stream_event(struct snd_soc_codec *codec,
+ const char *stream, int event)
+{
+ soc_dapm_stream_event(&codec->dapm, stream, event);
+}
+
+void snd_soc_dapm_platform_stream_event(struct snd_soc_platform *platform,
+ const char *stream, int event)
+{
+ mutex_lock(&platform->card->dapm_mutex);
+ soc_dapm_platform_stream_event(platform, stream, event);
+ mutex_unlock(&platform->card->dapm_mutex);
+}
+EXPORT_SYMBOL(snd_soc_dapm_platform_stream_event);
+
+void snd_soc_dapm_codec_stream_event(struct snd_soc_codec *codec,
+ const char *stream, int event)
+{
+ mutex_lock(&codec->card->dapm_mutex);
+ soc_dapm_codec_stream_event(codec, stream, event);
+ mutex_unlock(&codec->card->dapm_mutex);
+}
+EXPORT_SYMBOL(snd_soc_dapm_codec_stream_event);
+
/**
* snd_soc_dapm_stream_event - send a stream event to the dapm core
* @rtd: PCM runtime data
@@ -2441,14 +2908,16 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
const char *stream, int event)
{
- struct snd_soc_codec *codec = rtd->codec;
-
if (stream == NULL)
return 0;
- mutex_lock(&codec->mutex);
- soc_dapm_stream_event(&codec->dapm, stream, event);
- mutex_unlock(&codec->mutex);
+ mutex_lock(&rtd->card->dapm_mutex);
+
+ soc_dapm_platform_stream_event(rtd->platform, stream, event);
+ soc_dapm_codec_stream_event(rtd->codec, stream, event);
+ soc_dapm_stream_event(&rtd->card->dapm, stream, event);
+
+ mutex_unlock(&rtd->card->dapm_mutex);
return 0;
}
@@ -2556,6 +3025,27 @@ int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
/**
+ * snd_soc_dapm_get_pin_power - get audio pin power state
+ * @dapm: DAPM context
+ * @pin: audio signal pin endpoint (or start point)
+ *
+ * Get audio pin power state - powered or not-powered.
+ *
+ * Returns 1 if powered, otherwise 0.
+ */
+int snd_soc_dapm_get_pin_power(struct snd_soc_dapm_context *dapm,
+ const char *pin)
+{
+ struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
+
+ if (w)
+ return w->power;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_power);
+
+/**
* snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
* @dapm: DAPM context
* @pin: audio signal pin endpoint (or start point)
@@ -2633,6 +3123,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
void snd_soc_dapm_shutdown(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
+ struct snd_soc_platform *platform;
list_for_each_entry(codec, &card->codec_dev_list, card_list) {
soc_dapm_shutdown_codec(&codec->dapm);
@@ -2640,6 +3131,11 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card)
snd_soc_dapm_set_bias_level(&codec->dapm,
SND_SOC_BIAS_OFF);
}
+
+ list_for_each_entry(platform, &card->platform_dev_list, card_list) {
+ soc_dapm_shutdown_codec(&platform->dapm);
+ snd_soc_dapm_set_bias_level(&platform->dapm, SND_SOC_BIAS_OFF);
+ }
}
/* Module information */