|
@@ -47,6 +47,15 @@
|
|
|
|
|
|
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
|
|
|
|
|
|
+static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
|
|
|
+ struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
|
|
|
+ const char *control,
|
|
|
+ int (*connected)(struct snd_soc_dapm_widget *source,
|
|
|
+ struct snd_soc_dapm_widget *sink));
|
|
|
+static struct snd_soc_dapm_widget *
|
|
|
+snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
|
|
|
+ const struct snd_soc_dapm_widget *widget);
|
|
|
+
|
|
|
/* dapm power sequences - make this per codec in the future */
|
|
|
static int dapm_up_seq[] = {
|
|
|
[snd_soc_dapm_pre] = 0,
|
|
@@ -73,16 +82,18 @@ static int dapm_up_seq[] = {
|
|
|
[snd_soc_dapm_hp] = 10,
|
|
|
[snd_soc_dapm_spk] = 10,
|
|
|
[snd_soc_dapm_line] = 10,
|
|
|
- [snd_soc_dapm_post] = 11,
|
|
|
+ [snd_soc_dapm_kcontrol] = 11,
|
|
|
+ [snd_soc_dapm_post] = 12,
|
|
|
};
|
|
|
|
|
|
static int dapm_down_seq[] = {
|
|
|
[snd_soc_dapm_pre] = 0,
|
|
|
- [snd_soc_dapm_adc] = 1,
|
|
|
- [snd_soc_dapm_hp] = 2,
|
|
|
- [snd_soc_dapm_spk] = 2,
|
|
|
- [snd_soc_dapm_line] = 2,
|
|
|
- [snd_soc_dapm_out_drv] = 2,
|
|
|
+ [snd_soc_dapm_kcontrol] = 1,
|
|
|
+ [snd_soc_dapm_adc] = 2,
|
|
|
+ [snd_soc_dapm_hp] = 3,
|
|
|
+ [snd_soc_dapm_spk] = 3,
|
|
|
+ [snd_soc_dapm_line] = 3,
|
|
|
+ [snd_soc_dapm_out_drv] = 3,
|
|
|
[snd_soc_dapm_pga] = 4,
|
|
|
[snd_soc_dapm_switch] = 5,
|
|
|
[snd_soc_dapm_mixer_named_ctl] = 5,
|
|
@@ -174,6 +185,176 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
|
|
|
return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
|
|
|
}
|
|
|
|
|
|
+struct dapm_kcontrol_data {
|
|
|
+ unsigned int value;
|
|
|
+ struct snd_soc_dapm_widget *widget;
|
|
|
+ struct list_head paths;
|
|
|
+ struct snd_soc_dapm_widget_list *wlist;
|
|
|
+};
|
|
|
+
|
|
|
+static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
|
|
|
+ struct snd_kcontrol *kcontrol)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data;
|
|
|
+ struct soc_mixer_control *mc;
|
|
|
+
|
|
|
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
|
|
|
+ if (!data) {
|
|
|
+ dev_err(widget->dapm->dev,
|
|
|
+ "ASoC: can't allocate kcontrol data for %s\n",
|
|
|
+ widget->name);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&data->paths);
|
|
|
+
|
|
|
+ switch (widget->id) {
|
|
|
+ case snd_soc_dapm_switch:
|
|
|
+ case snd_soc_dapm_mixer:
|
|
|
+ case snd_soc_dapm_mixer_named_ctl:
|
|
|
+ mc = (struct soc_mixer_control *)kcontrol->private_value;
|
|
|
+
|
|
|
+ if (mc->autodisable) {
|
|
|
+ struct snd_soc_dapm_widget template;
|
|
|
+
|
|
|
+ memset(&template, 0, sizeof(template));
|
|
|
+ template.reg = mc->reg;
|
|
|
+ template.mask = (1 << fls(mc->max)) - 1;
|
|
|
+ template.shift = mc->shift;
|
|
|
+ if (mc->invert)
|
|
|
+ template.off_val = mc->max;
|
|
|
+ else
|
|
|
+ template.off_val = 0;
|
|
|
+ template.on_val = template.off_val;
|
|
|
+ template.id = snd_soc_dapm_kcontrol;
|
|
|
+ template.name = kcontrol->id.name;
|
|
|
+
|
|
|
+ data->widget = snd_soc_dapm_new_control(widget->dapm,
|
|
|
+ &template);
|
|
|
+ if (!data->widget) {
|
|
|
+ kfree(data);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ kcontrol->private_data = data;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
|
|
|
+ kfree(data->widget);
|
|
|
+ kfree(data->wlist);
|
|
|
+ kfree(data);
|
|
|
+}
|
|
|
+
|
|
|
+static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
|
|
|
+ const struct snd_kcontrol *kcontrol)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
|
|
|
+
|
|
|
+ return data->wlist;
|
|
|
+}
|
|
|
+
|
|
|
+static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_soc_dapm_widget *widget)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
|
|
|
+ struct snd_soc_dapm_widget_list *new_wlist;
|
|
|
+ unsigned int n;
|
|
|
+
|
|
|
+ if (data->wlist)
|
|
|
+ n = data->wlist->num_widgets + 1;
|
|
|
+ else
|
|
|
+ n = 1;
|
|
|
+
|
|
|
+ new_wlist = krealloc(data->wlist,
|
|
|
+ sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
|
|
|
+ if (!new_wlist)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ new_wlist->widgets[n - 1] = widget;
|
|
|
+ new_wlist->num_widgets = n;
|
|
|
+
|
|
|
+ data->wlist = new_wlist;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
|
|
|
+ struct snd_soc_dapm_path *path)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
|
|
|
+
|
|
|
+ list_add_tail(&path->list_kcontrol, &data->paths);
|
|
|
+
|
|
|
+ if (data->widget) {
|
|
|
+ snd_soc_dapm_add_path(data->widget->dapm, data->widget,
|
|
|
+ path->source, NULL, NULL);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
|
|
|
+
|
|
|
+ if (!data->widget)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ return data->widget->power;
|
|
|
+}
|
|
|
+
|
|
|
+static struct list_head *dapm_kcontrol_get_path_list(
|
|
|
+ const struct snd_kcontrol *kcontrol)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
|
|
|
+
|
|
|
+ return &data->paths;
|
|
|
+}
|
|
|
+
|
|
|
+#define dapm_kcontrol_for_each_path(path, kcontrol) \
|
|
|
+ list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
|
|
|
+ list_kcontrol)
|
|
|
+
|
|
|
+static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
|
|
|
+
|
|
|
+ return data->value;
|
|
|
+}
|
|
|
+
|
|
|
+static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
|
|
|
+ unsigned int value)
|
|
|
+{
|
|
|
+ struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
|
|
|
+
|
|
|
+ if (data->value == value)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (data->widget)
|
|
|
+ data->widget->on_val = value;
|
|
|
+
|
|
|
+ data->value = value;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
|
|
|
+ * @kcontrol: The kcontrol
|
|
|
+ */
|
|
|
+struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol)
|
|
|
+{
|
|
|
+ return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
|
|
|
+
|
|
|
static void dapm_reset(struct snd_soc_card *card)
|
|
|
{
|
|
|
struct snd_soc_dapm_widget *w;
|
|
@@ -181,6 +362,7 @@ static void dapm_reset(struct snd_soc_card *card)
|
|
|
memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
|
|
|
|
|
|
list_for_each_entry(w, &card->widgets, list) {
|
|
|
+ w->new_power = w->power;
|
|
|
w->power_checked = false;
|
|
|
w->inputs = -1;
|
|
|
w->outputs = -1;
|
|
@@ -398,6 +580,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
|
|
|
case snd_soc_dapm_spk:
|
|
|
case snd_soc_dapm_line:
|
|
|
case snd_soc_dapm_dai_link:
|
|
|
+ case snd_soc_dapm_kcontrol:
|
|
|
p->connect = 1;
|
|
|
break;
|
|
|
/* does affect routing - dynamically connected */
|
|
@@ -477,17 +660,12 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
|
|
|
-{
|
|
|
- kfree(kctl->private_data);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Determine if a kcontrol is shared. If it is, look it up. If it isn't,
|
|
|
* create it. Either way, add the widget into the control's widget list
|
|
|
*/
|
|
|
static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
|
|
|
- int kci, struct snd_soc_dapm_path *path)
|
|
|
+ int kci)
|
|
|
{
|
|
|
struct snd_soc_dapm_context *dapm = w->dapm;
|
|
|
struct snd_card *card = dapm->card->snd_card;
|
|
@@ -495,9 +673,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
|
|
|
size_t prefix_len;
|
|
|
int shared;
|
|
|
struct snd_kcontrol *kcontrol;
|
|
|
- struct snd_soc_dapm_widget_list *wlist;
|
|
|
- int wlistentries;
|
|
|
- size_t wlistsize;
|
|
|
bool wname_in_long_name, kcname_in_long_name;
|
|
|
char *long_name;
|
|
|
const char *name;
|
|
@@ -516,25 +691,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
|
|
|
shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
|
|
|
&kcontrol);
|
|
|
|
|
|
- if (kcontrol) {
|
|
|
- wlist = kcontrol->private_data;
|
|
|
- wlistentries = wlist->num_widgets + 1;
|
|
|
- } else {
|
|
|
- wlist = NULL;
|
|
|
- wlistentries = 1;
|
|
|
- }
|
|
|
-
|
|
|
- wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
|
|
|
- wlistentries * sizeof(struct snd_soc_dapm_widget *);
|
|
|
- wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
|
|
|
- if (wlist == NULL) {
|
|
|
- dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
|
|
|
- w->name);
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
- wlist->num_widgets = wlistentries;
|
|
|
- wlist->widgets[wlistentries - 1] = w;
|
|
|
-
|
|
|
if (!kcontrol) {
|
|
|
if (shared) {
|
|
|
wname_in_long_name = false;
|
|
@@ -557,7 +713,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
|
|
|
kcname_in_long_name = false;
|
|
|
break;
|
|
|
default:
|
|
|
- kfree(wlist);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
}
|
|
@@ -572,10 +727,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
|
|
|
long_name = kasprintf(GFP_KERNEL, "%s %s",
|
|
|
w->name + prefix_len,
|
|
|
w->kcontrol_news[kci].name);
|
|
|
- if (long_name == NULL) {
|
|
|
- kfree(wlist);
|
|
|
+ if (long_name == NULL)
|
|
|
return -ENOMEM;
|
|
|
- }
|
|
|
|
|
|
name = long_name;
|
|
|
} else if (wname_in_long_name) {
|
|
@@ -586,23 +739,33 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
|
|
|
name = w->kcontrol_news[kci].name;
|
|
|
}
|
|
|
|
|
|
- kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
|
|
|
+ kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
|
|
|
prefix);
|
|
|
- kcontrol->private_free = dapm_kcontrol_free;
|
|
|
kfree(long_name);
|
|
|
+ if (!kcontrol)
|
|
|
+ return -ENOMEM;
|
|
|
+ kcontrol->private_free = dapm_kcontrol_free;
|
|
|
+
|
|
|
+ ret = dapm_kcontrol_data_alloc(w, kcontrol);
|
|
|
+ if (ret) {
|
|
|
+ snd_ctl_free_one(kcontrol);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
ret = snd_ctl_add(card, kcontrol);
|
|
|
if (ret < 0) {
|
|
|
dev_err(dapm->dev,
|
|
|
"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
|
|
|
w->name, name, ret);
|
|
|
- kfree(wlist);
|
|
|
return ret;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- kcontrol->private_data = wlist;
|
|
|
+ ret = dapm_kcontrol_add_widget(kcontrol, w);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
w->kcontrols[kci] = kcontrol;
|
|
|
- path->kcontrol = kcontrol;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -622,13 +785,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
|
|
|
continue;
|
|
|
|
|
|
if (w->kcontrols[i]) {
|
|
|
- path->kcontrol = w->kcontrols[i];
|
|
|
+ dapm_kcontrol_add_path(w->kcontrols[i], path);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
|
|
|
+ ret = dapm_create_or_share_mixmux_kcontrol(w, i);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
+
|
|
|
+ dapm_kcontrol_add_path(w->kcontrols[i], path);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -654,15 +819,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
|
|
|
- list_sink);
|
|
|
-
|
|
|
- ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
|
|
|
+ ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
list_for_each_entry(path, &w->sources, list_sink)
|
|
|
- path->kcontrol = w->kcontrols[0];
|
|
|
+ dapm_kcontrol_add_path(w->kcontrols[0], path);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -783,6 +945,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
|
|
|
case snd_soc_dapm_supply:
|
|
|
case snd_soc_dapm_regulator_supply:
|
|
|
case snd_soc_dapm_clock_supply:
|
|
|
+ case snd_soc_dapm_kcontrol:
|
|
|
return 0;
|
|
|
default:
|
|
|
break;
|
|
@@ -878,6 +1041,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
|
|
|
case snd_soc_dapm_supply:
|
|
|
case snd_soc_dapm_regulator_supply:
|
|
|
case snd_soc_dapm_clock_supply:
|
|
|
+ case snd_soc_dapm_kcontrol:
|
|
|
return 0;
|
|
|
default:
|
|
|
break;
|
|
@@ -1032,7 +1196,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
|
|
|
int ret;
|
|
|
|
|
|
if (SND_SOC_DAPM_EVENT_ON(event)) {
|
|
|
- if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
|
|
|
+ if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
|
|
|
ret = regulator_allow_bypass(w->regulator, false);
|
|
|
if (ret != 0)
|
|
|
dev_warn(w->dapm->dev,
|
|
@@ -1042,7 +1206,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
|
|
|
|
|
|
return regulator_enable(w->regulator);
|
|
|
} else {
|
|
|
- if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
|
|
|
+ if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
|
|
|
ret = regulator_allow_bypass(w->regulator, true);
|
|
|
if (ret != 0)
|
|
|
dev_warn(w->dapm->dev,
|
|
@@ -1214,10 +1378,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
|
|
|
list_add_tail(&new_widget->power_list, list);
|
|
|
}
|
|
|
|
|
|
-static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
|
|
|
+static void dapm_seq_check_event(struct snd_soc_card *card,
|
|
|
struct snd_soc_dapm_widget *w, int event)
|
|
|
{
|
|
|
- struct snd_soc_card *card = dapm->card;
|
|
|
const char *ev_name;
|
|
|
int power, ret;
|
|
|
|
|
@@ -1251,55 +1414,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if (w->power != power)
|
|
|
+ if (w->new_power != power)
|
|
|
return;
|
|
|
|
|
|
if (w->event && (w->event_flags & event)) {
|
|
|
- pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
|
|
|
+ pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
|
|
|
w->name, ev_name);
|
|
|
trace_snd_soc_dapm_widget_event_start(w, event);
|
|
|
ret = w->event(w, NULL, event);
|
|
|
trace_snd_soc_dapm_widget_event_done(w, event);
|
|
|
if (ret < 0)
|
|
|
- dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n",
|
|
|
+ dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
|
|
|
ev_name, w->name, ret);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Apply the coalesced changes from a DAPM sequence */
|
|
|
-static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
|
|
|
+static void dapm_seq_run_coalesced(struct snd_soc_card *card,
|
|
|
struct list_head *pending)
|
|
|
{
|
|
|
- struct snd_soc_card *card = dapm->card;
|
|
|
struct snd_soc_dapm_widget *w;
|
|
|
- int reg, power;
|
|
|
+ int reg;
|
|
|
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;
|
|
|
|
|
|
list_for_each_entry(w, pending, power_list) {
|
|
|
- cur_mask = 1 << w->shift;
|
|
|
BUG_ON(reg != w->reg);
|
|
|
+ w->power = w->new_power;
|
|
|
|
|
|
- if (w->invert)
|
|
|
- power = !w->power;
|
|
|
+ mask |= w->mask << w->shift;
|
|
|
+ if (w->power)
|
|
|
+ value |= w->on_val << w->shift;
|
|
|
else
|
|
|
- power = w->power;
|
|
|
-
|
|
|
- mask |= cur_mask;
|
|
|
- if (power)
|
|
|
- value |= cur_mask;
|
|
|
+ value |= w->off_val << w->shift;
|
|
|
|
|
|
- pop_dbg(dapm->dev, card->pop_time,
|
|
|
+ pop_dbg(w->dapm->dev, card->pop_time,
|
|
|
"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
|
|
|
w->name, reg, value, mask);
|
|
|
|
|
|
/* Check for events */
|
|
|
- dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
|
|
|
- dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
|
|
|
+ dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
|
|
|
+ dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
|
|
|
}
|
|
|
|
|
|
if (reg >= 0) {
|
|
@@ -1309,7 +1467,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
|
|
|
w = list_first_entry(pending, struct snd_soc_dapm_widget,
|
|
|
power_list);
|
|
|
|
|
|
- pop_dbg(dapm->dev, card->pop_time,
|
|
|
+ pop_dbg(w->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);
|
|
@@ -1317,8 +1475,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
|
|
|
}
|
|
|
|
|
|
list_for_each_entry(w, pending, power_list) {
|
|
|
- dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
|
|
|
- dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
|
|
|
+ dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
|
|
|
+ dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1330,8 +1488,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
|
|
|
* Currently anything that requires more than a single write is not
|
|
|
* handled.
|
|
|
*/
|
|
|
-static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
|
|
|
- struct list_head *list, int event, bool power_up)
|
|
|
+static void dapm_seq_run(struct snd_soc_card *card,
|
|
|
+ struct list_head *list, int event, bool power_up)
|
|
|
{
|
|
|
struct snd_soc_dapm_widget *w, *n;
|
|
|
LIST_HEAD(pending);
|
|
@@ -1354,7 +1512,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
|
|
|
if (sort[w->id] != cur_sort || w->reg != cur_reg ||
|
|
|
w->dapm != cur_dapm || w->subseq != cur_subseq) {
|
|
|
if (!list_empty(&pending))
|
|
|
- dapm_seq_run_coalesced(cur_dapm, &pending);
|
|
|
+ dapm_seq_run_coalesced(card, &pending);
|
|
|
|
|
|
if (cur_dapm && cur_dapm->seq_notifier) {
|
|
|
for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
|
|
@@ -1414,7 +1572,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
|
|
|
}
|
|
|
|
|
|
if (!list_empty(&pending))
|
|
|
- dapm_seq_run_coalesced(cur_dapm, &pending);
|
|
|
+ dapm_seq_run_coalesced(card, &pending);
|
|
|
|
|
|
if (cur_dapm && cur_dapm->seq_notifier) {
|
|
|
for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
|
|
@@ -1424,37 +1582,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
|
|
|
+static void dapm_widget_update(struct snd_soc_card *card)
|
|
|
{
|
|
|
- struct snd_soc_dapm_update *update = dapm->update;
|
|
|
- struct snd_soc_dapm_widget *w;
|
|
|
+ struct snd_soc_dapm_update *update = card->update;
|
|
|
+ struct snd_soc_dapm_widget_list *wlist;
|
|
|
+ struct snd_soc_dapm_widget *w = NULL;
|
|
|
+ unsigned int wi;
|
|
|
int ret;
|
|
|
|
|
|
- if (!update)
|
|
|
+ if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
|
|
|
return;
|
|
|
|
|
|
- w = update->widget;
|
|
|
+ wlist = dapm_kcontrol_get_wlist(update->kcontrol);
|
|
|
|
|
|
- if (w->event &&
|
|
|
- (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
|
|
|
- ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
|
|
|
- if (ret != 0)
|
|
|
- dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
|
|
|
- w->name, ret);
|
|
|
+ for (wi = 0; wi < wlist->num_widgets; wi++) {
|
|
|
+ w = wlist->widgets[wi];
|
|
|
+
|
|
|
+ if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
|
|
|
+ ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
|
|
|
+ if (ret != 0)
|
|
|
+ dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
|
|
|
+ w->name, ret);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ if (!w)
|
|
|
+ return;
|
|
|
+
|
|
|
ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
|
|
|
update->val);
|
|
|
if (ret < 0)
|
|
|
- dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n",
|
|
|
+ dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
|
|
|
w->name, ret);
|
|
|
|
|
|
- if (w->event &&
|
|
|
- (w->event_flags & SND_SOC_DAPM_POST_REG)) {
|
|
|
- ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
|
|
|
- if (ret != 0)
|
|
|
- dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
|
|
|
- w->name, ret);
|
|
|
+ for (wi = 0; wi < wlist->num_widgets; wi++) {
|
|
|
+ w = wlist->widgets[wi];
|
|
|
+
|
|
|
+ if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
|
|
|
+ ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
|
|
|
+ if (ret != 0)
|
|
|
+ dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
|
|
|
+ w->name, ret);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1566,6 +1735,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
|
|
|
case snd_soc_dapm_supply:
|
|
|
case snd_soc_dapm_regulator_supply:
|
|
|
case snd_soc_dapm_clock_supply:
|
|
|
+ case snd_soc_dapm_kcontrol:
|
|
|
/* Supplies can't affect their outputs, only their inputs */
|
|
|
break;
|
|
|
default:
|
|
@@ -1582,8 +1752,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
|
|
|
dapm_seq_insert(w, up_list, true);
|
|
|
else
|
|
|
dapm_seq_insert(w, down_list, false);
|
|
|
-
|
|
|
- w->power = power;
|
|
|
}
|
|
|
|
|
|
static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
|
|
@@ -1617,9 +1785,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
|
|
|
* o Input pin to Output pin (bypass, sidetone)
|
|
|
* o DAC to ADC (loopback).
|
|
|
*/
|
|
|
-static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
|
|
|
+static int dapm_power_widgets(struct snd_soc_card *card, int event)
|
|
|
{
|
|
|
- struct snd_soc_card *card = dapm->card;
|
|
|
struct snd_soc_dapm_widget *w;
|
|
|
struct snd_soc_dapm_context *d;
|
|
|
LIST_HEAD(up_list);
|
|
@@ -1659,7 +1826,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (w->power) {
|
|
|
+ if (w->new_power) {
|
|
|
d = w->dapm;
|
|
|
|
|
|
/* Supplies and micbiases only bring the
|
|
@@ -1701,29 +1868,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
|
|
|
trace_snd_soc_dapm_walk_done(card);
|
|
|
|
|
|
/* Run all the bias changes in parallel */
|
|
|
- list_for_each_entry(d, &dapm->card->dapm_list, list)
|
|
|
+ list_for_each_entry(d, &card->dapm_list, list)
|
|
|
async_schedule_domain(dapm_pre_sequence_async, d,
|
|
|
&async_domain);
|
|
|
async_synchronize_full_domain(&async_domain);
|
|
|
|
|
|
list_for_each_entry(w, &down_list, power_list) {
|
|
|
- dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
|
|
|
+ dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
|
|
|
}
|
|
|
|
|
|
list_for_each_entry(w, &up_list, power_list) {
|
|
|
- dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
|
|
|
+ dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
|
|
|
}
|
|
|
|
|
|
/* Power down widgets first; try to avoid amplifying pops. */
|
|
|
- dapm_seq_run(dapm, &down_list, event, false);
|
|
|
+ dapm_seq_run(card, &down_list, event, false);
|
|
|
|
|
|
- dapm_widget_update(dapm);
|
|
|
+ dapm_widget_update(card);
|
|
|
|
|
|
/* Now power up. */
|
|
|
- dapm_seq_run(dapm, &up_list, event, true);
|
|
|
+ dapm_seq_run(card, &up_list, event, true);
|
|
|
|
|
|
/* Run all the bias changes in parallel */
|
|
|
- list_for_each_entry(d, &dapm->card->dapm_list, list)
|
|
|
+ list_for_each_entry(d, &card->dapm_list, list)
|
|
|
async_schedule_domain(dapm_post_sequence_async, d,
|
|
|
&async_domain);
|
|
|
async_synchronize_full_domain(&async_domain);
|
|
@@ -1734,7 +1901,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
|
|
|
d->stream_event(d, event);
|
|
|
}
|
|
|
|
|
|
- pop_dbg(dapm->dev, card->pop_time,
|
|
|
+ pop_dbg(card->dev, card->pop_time,
|
|
|
"DAPM sequencing finished, waiting %dms\n", card->pop_time);
|
|
|
pop_wait(card->pop_time);
|
|
|
|
|
@@ -1769,8 +1936,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
|
|
|
|
|
|
if (w->reg >= 0)
|
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret,
|
|
|
- " - R%d(0x%x) bit %d",
|
|
|
- w->reg, w->reg, w->shift);
|
|
|
+ " - R%d(0x%x) mask 0x%x",
|
|
|
+ w->reg, w->reg, w->mask << w->shift);
|
|
|
|
|
|
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
|
|
|
|
|
@@ -1907,22 +2074,14 @@ 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 soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
|
|
|
+static int soc_dapm_mux_update_power(struct snd_soc_card *card,
|
|
|
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
|
|
|
{
|
|
|
struct snd_soc_dapm_path *path;
|
|
|
int found = 0;
|
|
|
|
|
|
- if (widget->id != snd_soc_dapm_mux &&
|
|
|
- widget->id != snd_soc_dapm_virt_mux &&
|
|
|
- widget->id != snd_soc_dapm_value_mux)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
/* find dapm widget path assoc with kcontrol */
|
|
|
- list_for_each_entry(path, &widget->dapm->card->paths, list) {
|
|
|
- if (path->kcontrol != kcontrol)
|
|
|
- continue;
|
|
|
-
|
|
|
+ dapm_kcontrol_for_each_path(path, kcontrol) {
|
|
|
if (!path->name || !e->texts[mux])
|
|
|
continue;
|
|
|
|
|
@@ -1937,73 +2096,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
|
|
|
"mux disconnection");
|
|
|
path->connect = 0; /* old connection must be powered down */
|
|
|
}
|
|
|
+ dapm_mark_dirty(path->sink, "mux change");
|
|
|
}
|
|
|
|
|
|
- if (found) {
|
|
|
- dapm_mark_dirty(widget, "mux change");
|
|
|
- dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
|
|
|
- }
|
|
|
+ if (found)
|
|
|
+ dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
|
|
|
|
|
|
return found;
|
|
|
}
|
|
|
|
|
|
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
|
|
|
- struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
|
|
|
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
|
|
|
+ struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
|
|
|
+ struct snd_soc_dapm_update *update)
|
|
|
{
|
|
|
- struct snd_soc_card *card = widget->dapm->card;
|
|
|
+ struct snd_soc_card *card = dapm->card;
|
|
|
int ret;
|
|
|
|
|
|
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
- ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
|
|
|
+ card->update = update;
|
|
|
+ ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
|
|
|
+ card->update = NULL;
|
|
|
mutex_unlock(&card->dapm_mutex);
|
|
|
if (ret > 0)
|
|
|
- soc_dpcm_runtime_update(widget);
|
|
|
+ soc_dpcm_runtime_update(card);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
|
|
|
|
|
|
/* test and update the power status of a mixer or switch widget */
|
|
|
-static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
|
|
|
+static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
|
|
|
struct snd_kcontrol *kcontrol, int connect)
|
|
|
{
|
|
|
struct snd_soc_dapm_path *path;
|
|
|
int found = 0;
|
|
|
|
|
|
- if (widget->id != snd_soc_dapm_mixer &&
|
|
|
- widget->id != snd_soc_dapm_mixer_named_ctl &&
|
|
|
- widget->id != snd_soc_dapm_switch)
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
/* find dapm widget path assoc with kcontrol */
|
|
|
- list_for_each_entry(path, &widget->dapm->card->paths, list) {
|
|
|
- if (path->kcontrol != kcontrol)
|
|
|
- continue;
|
|
|
-
|
|
|
- /* found, now check type */
|
|
|
+ dapm_kcontrol_for_each_path(path, kcontrol) {
|
|
|
found = 1;
|
|
|
path->connect = connect;
|
|
|
dapm_mark_dirty(path->source, "mixer connection");
|
|
|
+ dapm_mark_dirty(path->sink, "mixer update");
|
|
|
}
|
|
|
|
|
|
- if (found) {
|
|
|
- dapm_mark_dirty(widget, "mixer update");
|
|
|
- dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
|
|
|
- }
|
|
|
+ if (found)
|
|
|
+ dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
|
|
|
|
|
|
return found;
|
|
|
}
|
|
|
|
|
|
-int snd_soc_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_context *dapm,
|
|
|
+ struct snd_kcontrol *kcontrol, int connect,
|
|
|
+ struct snd_soc_dapm_update *update)
|
|
|
{
|
|
|
- struct snd_soc_card *card = widget->dapm->card;
|
|
|
+ struct snd_soc_card *card = dapm->card;
|
|
|
int ret;
|
|
|
|
|
|
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
- ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
|
|
|
+ card->update = update;
|
|
|
+ ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
|
|
|
+ card->update = NULL;
|
|
|
mutex_unlock(&card->dapm_mutex);
|
|
|
if (ret > 0)
|
|
|
- soc_dpcm_runtime_update(widget);
|
|
|
+ soc_dpcm_runtime_update(card);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
|
|
@@ -2082,6 +2236,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path)
|
|
|
{
|
|
|
list_del(&path->list_sink);
|
|
|
list_del(&path->list_source);
|
|
|
+ list_del(&path->list_kcontrol);
|
|
|
list_del(&path->list);
|
|
|
kfree(path);
|
|
|
}
|
|
@@ -2176,70 +2331,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
|
|
|
return 0;
|
|
|
|
|
|
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
- ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
|
|
|
+ ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
|
|
|
mutex_unlock(&dapm->card->dapm_mutex);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
|
|
|
|
|
|
-static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
|
|
|
- const struct snd_soc_dapm_route *route)
|
|
|
+static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
|
|
|
+ struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
|
|
|
+ const char *control,
|
|
|
+ int (*connected)(struct snd_soc_dapm_widget *source,
|
|
|
+ struct snd_soc_dapm_widget *sink))
|
|
|
{
|
|
|
struct snd_soc_dapm_path *path;
|
|
|
- struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
|
|
|
- struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
|
|
|
- const char *sink;
|
|
|
- const char *control = route->control;
|
|
|
- const char *source;
|
|
|
- char prefixed_sink[80];
|
|
|
- char prefixed_source[80];
|
|
|
- int ret = 0;
|
|
|
-
|
|
|
- if (dapm->codec && dapm->codec->name_prefix) {
|
|
|
- snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
|
|
|
- dapm->codec->name_prefix, route->sink);
|
|
|
- sink = prefixed_sink;
|
|
|
- snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
|
|
|
- dapm->codec->name_prefix, route->source);
|
|
|
- source = prefixed_source;
|
|
|
- } else {
|
|
|
- sink = route->sink;
|
|
|
- source = route->source;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * find src and dest widgets over all widgets but favor a widget from
|
|
|
- * current DAPM context
|
|
|
- */
|
|
|
- list_for_each_entry(w, &dapm->card->widgets, list) {
|
|
|
- if (!wsink && !(strcmp(w->name, sink))) {
|
|
|
- wtsink = w;
|
|
|
- if (w->dapm == dapm)
|
|
|
- wsink = w;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (!wsource && !(strcmp(w->name, source))) {
|
|
|
- wtsource = w;
|
|
|
- if (w->dapm == dapm)
|
|
|
- wsource = w;
|
|
|
- }
|
|
|
- }
|
|
|
- /* use widget from another DAPM context if not found from this */
|
|
|
- if (!wsink)
|
|
|
- wsink = wtsink;
|
|
|
- if (!wsource)
|
|
|
- wsource = wtsource;
|
|
|
-
|
|
|
- if (wsource == NULL) {
|
|
|
- dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
|
|
|
- route->source);
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
- if (wsink == NULL) {
|
|
|
- dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
|
|
|
- route->sink);
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
+ int ret;
|
|
|
|
|
|
path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
|
|
|
if (!path)
|
|
@@ -2247,8 +2352,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
|
|
|
|
|
|
path->source = wsource;
|
|
|
path->sink = wsink;
|
|
|
- path->connected = route->connected;
|
|
|
+ path->connected = connected;
|
|
|
INIT_LIST_HEAD(&path->list);
|
|
|
+ INIT_LIST_HEAD(&path->list_kcontrol);
|
|
|
INIT_LIST_HEAD(&path->list_source);
|
|
|
INIT_LIST_HEAD(&path->list_sink);
|
|
|
|
|
@@ -2268,6 +2374,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
|
|
|
wsource->ext = 1;
|
|
|
}
|
|
|
|
|
|
+ dapm_mark_dirty(wsource, "Route added");
|
|
|
+ dapm_mark_dirty(wsink, "Route added");
|
|
|
+
|
|
|
/* connect static paths */
|
|
|
if (control == NULL) {
|
|
|
list_add(&path->list, &dapm->card->paths);
|
|
@@ -2298,6 +2407,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
|
|
|
case snd_soc_dapm_dai_in:
|
|
|
case snd_soc_dapm_dai_out:
|
|
|
case snd_soc_dapm_dai_link:
|
|
|
+ case snd_soc_dapm_kcontrol:
|
|
|
list_add(&path->list, &dapm->card->paths);
|
|
|
list_add(&path->list_sink, &wsink->sources);
|
|
|
list_add(&path->list_source, &wsource->sinks);
|
|
@@ -2329,15 +2439,78 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- dapm_mark_dirty(wsource, "Route added");
|
|
|
- dapm_mark_dirty(wsink, "Route added");
|
|
|
-
|
|
|
return 0;
|
|
|
+err:
|
|
|
+ kfree(path);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
|
|
|
+ const struct snd_soc_dapm_route *route)
|
|
|
+{
|
|
|
+ struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
|
|
|
+ struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
|
|
|
+ const char *sink;
|
|
|
+ const char *source;
|
|
|
+ char prefixed_sink[80];
|
|
|
+ char prefixed_source[80];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (dapm->codec && dapm->codec->name_prefix) {
|
|
|
+ snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
|
|
|
+ dapm->codec->name_prefix, route->sink);
|
|
|
+ sink = prefixed_sink;
|
|
|
+ snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
|
|
|
+ dapm->codec->name_prefix, route->source);
|
|
|
+ source = prefixed_source;
|
|
|
+ } else {
|
|
|
+ sink = route->sink;
|
|
|
+ source = route->source;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * find src and dest widgets over all widgets but favor a widget from
|
|
|
+ * current DAPM context
|
|
|
+ */
|
|
|
+ list_for_each_entry(w, &dapm->card->widgets, list) {
|
|
|
+ if (!wsink && !(strcmp(w->name, sink))) {
|
|
|
+ wtsink = w;
|
|
|
+ if (w->dapm == dapm)
|
|
|
+ wsink = w;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!wsource && !(strcmp(w->name, source))) {
|
|
|
+ wtsource = w;
|
|
|
+ if (w->dapm == dapm)
|
|
|
+ wsource = w;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* use widget from another DAPM context if not found from this */
|
|
|
+ if (!wsink)
|
|
|
+ wsink = wtsink;
|
|
|
+ if (!wsource)
|
|
|
+ wsource = wtsource;
|
|
|
|
|
|
+ if (wsource == NULL) {
|
|
|
+ dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
|
|
|
+ route->source);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+ if (wsink == NULL) {
|
|
|
+ dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
|
|
|
+ route->sink);
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
|
|
|
+ route->connected);
|
|
|
+ if (ret)
|
|
|
+ goto err;
|
|
|
+
|
|
|
+ return 0;
|
|
|
err:
|
|
|
dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
|
|
|
- source, control, sink);
|
|
|
- kfree(path);
|
|
|
+ source, route->control, sink);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -2541,12 +2714,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
|
|
|
*/
|
|
|
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
|
|
|
{
|
|
|
+ struct snd_soc_card *card = dapm->card;
|
|
|
struct snd_soc_dapm_widget *w;
|
|
|
unsigned int val;
|
|
|
|
|
|
- mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
|
|
|
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
|
|
|
|
|
|
- list_for_each_entry(w, &dapm->card->widgets, list)
|
|
|
+ list_for_each_entry(w, &card->widgets, list)
|
|
|
{
|
|
|
if (w->new)
|
|
|
continue;
|
|
@@ -2556,7 +2730,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
|
|
|
sizeof(struct snd_kcontrol *),
|
|
|
GFP_KERNEL);
|
|
|
if (!w->kcontrols) {
|
|
|
- mutex_unlock(&dapm->card->dapm_mutex);
|
|
|
+ mutex_unlock(&card->dapm_mutex);
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
}
|
|
@@ -2582,12 +2756,9 @@ 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 = soc_widget_read(w, w->reg);
|
|
|
- val &= 1 << w->shift;
|
|
|
- if (w->invert)
|
|
|
- val = !val;
|
|
|
-
|
|
|
- if (val)
|
|
|
+ val = soc_widget_read(w, w->reg) >> w->shift;
|
|
|
+ val &= w->mask;
|
|
|
+ if (val == w->on_val)
|
|
|
w->power = 1;
|
|
|
}
|
|
|
|
|
@@ -2597,8 +2768,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
|
|
|
dapm_debugfs_add_widget(w);
|
|
|
}
|
|
|
|
|
|
- dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
|
|
|
- mutex_unlock(&dapm->card->dapm_mutex);
|
|
|
+ dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
|
|
|
+ mutex_unlock(&card->dapm_mutex);
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
|
|
@@ -2615,8 +2786,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
|
|
|
int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
|
|
+ struct snd_soc_card *card = codec->card;
|
|
|
struct soc_mixer_control *mc =
|
|
|
(struct soc_mixer_control *)kcontrol->private_value;
|
|
|
unsigned int reg = mc->reg;
|
|
@@ -2624,17 +2795,24 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
|
|
|
int max = mc->max;
|
|
|
unsigned int mask = (1 << fls(max)) - 1;
|
|
|
unsigned int invert = mc->invert;
|
|
|
+ unsigned int val;
|
|
|
|
|
|
if (snd_soc_volsw_is_stereo(mc))
|
|
|
- dev_warn(widget->dapm->dev,
|
|
|
+ dev_warn(codec->dapm.dev,
|
|
|
"ASoC: Control '%s' is stereo, which is not supported\n",
|
|
|
kcontrol->id.name);
|
|
|
|
|
|
- ucontrol->value.integer.value[0] =
|
|
|
- (snd_soc_read(widget->codec, reg) >> shift) & mask;
|
|
|
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
+ if (dapm_kcontrol_is_powered(kcontrol))
|
|
|
+ val = (snd_soc_read(codec, reg) >> shift) & mask;
|
|
|
+ else
|
|
|
+ val = dapm_kcontrol_get_value(kcontrol);
|
|
|
+ mutex_unlock(&card->dapm_mutex);
|
|
|
+
|
|
|
if (invert)
|
|
|
- ucontrol->value.integer.value[0] =
|
|
|
- max - ucontrol->value.integer.value[0];
|
|
|
+ ucontrol->value.integer.value[0] = max - val;
|
|
|
+ else
|
|
|
+ ucontrol->value.integer.value[0] = val;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -2652,9 +2830,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
|
|
|
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
- struct snd_soc_codec *codec = widget->codec;
|
|
|
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
|
|
struct snd_soc_card *card = codec->card;
|
|
|
struct soc_mixer_control *mc =
|
|
|
(struct soc_mixer_control *)kcontrol->private_value;
|
|
@@ -2666,10 +2842,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
|
|
|
unsigned int val;
|
|
|
int connect, change;
|
|
|
struct snd_soc_dapm_update update;
|
|
|
- int wi;
|
|
|
|
|
|
if (snd_soc_volsw_is_stereo(mc))
|
|
|
- dev_warn(widget->dapm->dev,
|
|
|
+ dev_warn(codec->dapm.dev,
|
|
|
"ASoC: Control '%s' is stereo, which is not supported\n",
|
|
|
kcontrol->id.name);
|
|
|
|
|
@@ -2678,29 +2853,26 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
|
|
|
|
|
|
if (invert)
|
|
|
val = max - val;
|
|
|
- mask = mask << shift;
|
|
|
- val = val << shift;
|
|
|
|
|
|
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
|
|
|
- change = snd_soc_test_bits(widget->codec, reg, mask, val);
|
|
|
- if (change) {
|
|
|
- for (wi = 0; wi < wlist->num_widgets; wi++) {
|
|
|
- widget = wlist->widgets[wi];
|
|
|
+ dapm_kcontrol_set_value(kcontrol, val);
|
|
|
|
|
|
- widget->value = val;
|
|
|
+ mask = mask << shift;
|
|
|
+ val = val << shift;
|
|
|
|
|
|
- update.kcontrol = kcontrol;
|
|
|
- update.widget = widget;
|
|
|
- update.reg = reg;
|
|
|
- update.mask = mask;
|
|
|
- update.val = val;
|
|
|
- widget->dapm->update = &update;
|
|
|
+ change = snd_soc_test_bits(codec, reg, mask, val);
|
|
|
+ if (change) {
|
|
|
+ update.kcontrol = kcontrol;
|
|
|
+ update.reg = reg;
|
|
|
+ update.mask = mask;
|
|
|
+ update.val = val;
|
|
|
|
|
|
- soc_dapm_mixer_update_power(widget, kcontrol, connect);
|
|
|
+ card->update = &update;
|
|
|
|
|
|
- widget->dapm->update = NULL;
|
|
|
- }
|
|
|
+ soc_dapm_mixer_update_power(card, kcontrol, connect);
|
|
|
+
|
|
|
+ card->update = NULL;
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&card->dapm_mutex);
|
|
@@ -2720,12 +2892,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
|
|
|
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
|
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
|
|
unsigned int val;
|
|
|
|
|
|
- val = snd_soc_read(widget->codec, e->reg);
|
|
|
+ val = snd_soc_read(codec, e->reg);
|
|
|
ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
|
|
|
if (e->shift_l != e->shift_r)
|
|
|
ucontrol->value.enumerated.item[1] =
|
|
@@ -2747,15 +2918,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
|
|
|
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
- struct snd_soc_codec *codec = widget->codec;
|
|
|
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
|
|
struct snd_soc_card *card = codec->card;
|
|
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
|
|
unsigned int val, mux, change;
|
|
|
unsigned int mask;
|
|
|
struct snd_soc_dapm_update update;
|
|
|
- int wi;
|
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] > e->max - 1)
|
|
|
return -EINVAL;
|
|
@@ -2771,24 +2939,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
|
|
|
|
|
|
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
|
|
|
- change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
|
|
|
+ change = snd_soc_test_bits(codec, e->reg, mask, val);
|
|
|
if (change) {
|
|
|
- for (wi = 0; wi < wlist->num_widgets; wi++) {
|
|
|
- widget = wlist->widgets[wi];
|
|
|
-
|
|
|
- widget->value = val;
|
|
|
+ update.kcontrol = kcontrol;
|
|
|
+ update.reg = e->reg;
|
|
|
+ update.mask = mask;
|
|
|
+ update.val = val;
|
|
|
+ card->update = &update;
|
|
|
|
|
|
- update.kcontrol = kcontrol;
|
|
|
- update.widget = widget;
|
|
|
- update.reg = e->reg;
|
|
|
- update.mask = mask;
|
|
|
- update.val = val;
|
|
|
- widget->dapm->update = &update;
|
|
|
+ soc_dapm_mux_update_power(card, kcontrol, mux, e);
|
|
|
|
|
|
- soc_dapm_mux_update_power(widget, kcontrol, mux, e);
|
|
|
-
|
|
|
- widget->dapm->update = NULL;
|
|
|
- }
|
|
|
+ card->update = NULL;
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&card->dapm_mutex);
|
|
@@ -2806,11 +2967,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
|
|
|
int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
-
|
|
|
- ucontrol->value.enumerated.item[0] = widget->value;
|
|
|
-
|
|
|
+ ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol);
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
|
|
@@ -2825,30 +2982,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
|
|
|
int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
- struct snd_soc_codec *codec = widget->codec;
|
|
|
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
|
|
struct snd_soc_card *card = codec->card;
|
|
|
+ unsigned int value;
|
|
|
struct soc_enum *e =
|
|
|
(struct soc_enum *)kcontrol->private_value;
|
|
|
int change;
|
|
|
- int wi;
|
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] >= e->max)
|
|
|
return -EINVAL;
|
|
|
|
|
|
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
|
|
|
- change = widget->value != ucontrol->value.enumerated.item[0];
|
|
|
- if (change) {
|
|
|
- for (wi = 0; wi < wlist->num_widgets; wi++) {
|
|
|
- widget = wlist->widgets[wi];
|
|
|
-
|
|
|
- widget->value = ucontrol->value.enumerated.item[0];
|
|
|
-
|
|
|
- soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
|
|
|
- }
|
|
|
- }
|
|
|
+ value = ucontrol->value.enumerated.item[0];
|
|
|
+ change = dapm_kcontrol_set_value(kcontrol, value);
|
|
|
+ if (change)
|
|
|
+ soc_dapm_mux_update_power(card, kcontrol, value, e);
|
|
|
|
|
|
mutex_unlock(&card->dapm_mutex);
|
|
|
return change;
|
|
@@ -2871,12 +3020,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
|
|
|
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
|
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
|
|
unsigned int reg_val, val, mux;
|
|
|
|
|
|
- reg_val = snd_soc_read(widget->codec, e->reg);
|
|
|
+ reg_val = snd_soc_read(codec, e->reg);
|
|
|
val = (reg_val >> e->shift_l) & e->mask;
|
|
|
for (mux = 0; mux < e->max; mux++) {
|
|
|
if (val == e->values[mux])
|
|
@@ -2912,15 +3060,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
|
|
|
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
|
|
struct snd_ctl_elem_value *ucontrol)
|
|
|
{
|
|
|
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
|
|
|
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
|
|
|
- struct snd_soc_codec *codec = widget->codec;
|
|
|
+ struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
|
|
|
struct snd_soc_card *card = codec->card;
|
|
|
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
|
|
unsigned int val, mux, change;
|
|
|
unsigned int mask;
|
|
|
struct snd_soc_dapm_update update;
|
|
|
- int wi;
|
|
|
|
|
|
if (ucontrol->value.enumerated.item[0] > e->max - 1)
|
|
|
return -EINVAL;
|
|
@@ -2936,24 +3081,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
|
|
|
|
|
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
|
|
|
|
|
|
- change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
|
|
|
+ change = snd_soc_test_bits(codec, e->reg, mask, val);
|
|
|
if (change) {
|
|
|
- for (wi = 0; wi < wlist->num_widgets; wi++) {
|
|
|
- widget = wlist->widgets[wi];
|
|
|
-
|
|
|
- widget->value = val;
|
|
|
+ update.kcontrol = kcontrol;
|
|
|
+ update.reg = e->reg;
|
|
|
+ update.mask = mask;
|
|
|
+ update.val = val;
|
|
|
+ card->update = &update;
|
|
|
|
|
|
- update.kcontrol = kcontrol;
|
|
|
- update.widget = widget;
|
|
|
- update.reg = e->reg;
|
|
|
- update.mask = mask;
|
|
|
- update.val = val;
|
|
|
- widget->dapm->update = &update;
|
|
|
+ soc_dapm_mux_update_power(card, kcontrol, mux, e);
|
|
|
|
|
|
- soc_dapm_mux_update_power(widget, kcontrol, mux, e);
|
|
|
-
|
|
|
- widget->dapm->update = NULL;
|
|
|
- }
|
|
|
+ card->update = NULL;
|
|
|
}
|
|
|
|
|
|
mutex_unlock(&card->dapm_mutex);
|
|
@@ -3050,7 +3188,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
- if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
|
|
|
+ if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
|
|
|
ret = regulator_allow_bypass(w->regulator, true);
|
|
|
if (ret != 0)
|
|
|
dev_warn(w->dapm->dev,
|
|
@@ -3097,16 +3235,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
|
|
|
case snd_soc_dapm_value_mux:
|
|
|
w->power_check = dapm_generic_check_power;
|
|
|
break;
|
|
|
- case snd_soc_dapm_adc:
|
|
|
- case snd_soc_dapm_aif_out:
|
|
|
case snd_soc_dapm_dai_out:
|
|
|
w->power_check = dapm_adc_check_power;
|
|
|
break;
|
|
|
- case snd_soc_dapm_dac:
|
|
|
- case snd_soc_dapm_aif_in:
|
|
|
case snd_soc_dapm_dai_in:
|
|
|
w->power_check = dapm_dac_check_power;
|
|
|
break;
|
|
|
+ case snd_soc_dapm_adc:
|
|
|
+ case snd_soc_dapm_aif_out:
|
|
|
+ case snd_soc_dapm_dac:
|
|
|
+ case snd_soc_dapm_aif_in:
|
|
|
case snd_soc_dapm_pga:
|
|
|
case snd_soc_dapm_out_drv:
|
|
|
case snd_soc_dapm_input:
|
|
@@ -3122,6 +3260,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
|
|
|
case snd_soc_dapm_supply:
|
|
|
case snd_soc_dapm_regulator_supply:
|
|
|
case snd_soc_dapm_clock_supply:
|
|
|
+ case snd_soc_dapm_kcontrol:
|
|
|
w->power_check = dapm_supply_check_power;
|
|
|
break;
|
|
|
default:
|
|
@@ -3386,9 +3525,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
|
|
|
{
|
|
|
struct snd_soc_dapm_widget *dai_w, *w;
|
|
|
struct snd_soc_dai *dai;
|
|
|
- struct snd_soc_dapm_route r;
|
|
|
-
|
|
|
- memset(&r, 0, sizeof(r));
|
|
|
|
|
|
/* For each DAI widget... */
|
|
|
list_for_each_entry(dai_w, &card->widgets, list) {
|
|
@@ -3415,29 +3551,27 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (!w->sname)
|
|
|
+ if (!w->sname || !strstr(w->sname, dai_w->name))
|
|
|
continue;
|
|
|
|
|
|
if (dai->driver->playback.stream_name &&
|
|
|
strstr(w->sname,
|
|
|
dai->driver->playback.stream_name)) {
|
|
|
- r.source = dai->playback_widget->name;
|
|
|
- r.sink = w->name;
|
|
|
dev_dbg(dai->dev, "%s -> %s\n",
|
|
|
- r.source, r.sink);
|
|
|
+ dai->playback_widget->name, w->name);
|
|
|
|
|
|
- snd_soc_dapm_add_route(w->dapm, &r);
|
|
|
+ snd_soc_dapm_add_path(w->dapm,
|
|
|
+ dai->playback_widget, w, NULL, NULL);
|
|
|
}
|
|
|
|
|
|
if (dai->driver->capture.stream_name &&
|
|
|
strstr(w->sname,
|
|
|
dai->driver->capture.stream_name)) {
|
|
|
- r.source = w->name;
|
|
|
- r.sink = dai->capture_widget->name;
|
|
|
dev_dbg(dai->dev, "%s -> %s\n",
|
|
|
- r.source, r.sink);
|
|
|
+ w->name, dai->capture_widget->name);
|
|
|
|
|
|
- snd_soc_dapm_add_route(w->dapm, &r);
|
|
|
+ snd_soc_dapm_add_path(w->dapm, w,
|
|
|
+ dai->capture_widget, NULL, NULL);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -3499,7 +3633,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- dapm_power_widgets(&rtd->card->dapm, event);
|
|
|
+ dapm_power_widgets(rtd->card, event);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -3768,7 +3902,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
|
|
|
if (dapm->bias_level == SND_SOC_BIAS_ON)
|
|
|
snd_soc_dapm_set_bias_level(dapm,
|
|
|
SND_SOC_BIAS_PREPARE);
|
|
|
- dapm_seq_run(dapm, &down_list, 0, false);
|
|
|
+ dapm_seq_run(card, &down_list, 0, false);
|
|
|
if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
|
|
|
snd_soc_dapm_set_bias_level(dapm,
|
|
|
SND_SOC_BIAS_STANDBY);
|