diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 816 |
1 files changed, 460 insertions, 356 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b94190820e8c..d84bd0f167b6 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -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,36 +185,176 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); } -/* get snd_card from DAPM context */ -static inline struct snd_card *dapm_get_snd_card( - struct snd_soc_dapm_context *dapm) +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) { - if (dapm->codec) - return dapm->codec->card->snd_card; - else if (dapm->platform) - return dapm->platform->card->snd_card; - else - BUG(); + struct dapm_kcontrol_data *data; + struct soc_mixer_control *mc; - /* unreachable */ - return NULL; + 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; } -/* get soc_card from DAPM context */ -static inline struct snd_soc_card *dapm_get_soc_card( - struct snd_soc_dapm_context *dapm) +static void dapm_kcontrol_free(struct snd_kcontrol *kctl) { - if (dapm->codec) - return dapm->codec->card; - else if (dapm->platform) - return dapm->platform->card; + 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 - BUG(); + n = 1; - /* unreachable */ - return NULL; + 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; @@ -211,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; @@ -428,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 */ @@ -507,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; @@ -525,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; @@ -546,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; @@ -587,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; } } @@ -602,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) { @@ -616,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; } @@ -652,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); } } @@ -679,19 +814,17 @@ 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); - if (!path) { + if (list_empty(&w->sources)) { dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name); return -EINVAL; } - 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; } @@ -812,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; @@ -907,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; @@ -1061,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, @@ -1071,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, @@ -1243,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; @@ -1280,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) { @@ -1338,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); @@ -1346,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); } } @@ -1359,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); @@ -1383,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++) @@ -1443,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++) @@ -1453,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); + } } } @@ -1595,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: @@ -1611,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, @@ -1646,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); @@ -1688,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 @@ -1730,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); @@ -1763,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); @@ -1798,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"); @@ -1936,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; @@ -1966,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); @@ -2111,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); } @@ -2205,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) @@ -2276,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); @@ -2327,6 +2404,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); @@ -2362,11 +2440,77 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, 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; } @@ -2570,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; @@ -2585,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; } } @@ -2611,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; } @@ -2626,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); @@ -2644,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; @@ -2653,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; } @@ -2681,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; @@ -2695,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); @@ -2707,33 +2853,30 @@ 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); - return 0; + return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); @@ -2749,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] = @@ -2776,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; @@ -2800,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.widget = widget; - update.reg = e->reg; - update.mask = mask; - update.val = val; - widget->dapm->update = &update; + update.kcontrol = kcontrol; + update.reg = e->reg; + update.mask = mask; + update.val = val; + card->update = &update; - soc_dapm_mux_update_power(widget, kcontrol, mux, e); + soc_dapm_mux_update_power(card, kcontrol, mux, e); - widget->dapm->update = NULL; - } + card->update = NULL; } mutex_unlock(&card->dapm_mutex); @@ -2835,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); @@ -2854,34 +2982,25 @@ 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 ret = 0; - 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 ret; + return change; } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); @@ -2901,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]) @@ -2942,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; @@ -2966,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); @@ -3080,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, @@ -3127,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: @@ -3152,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: @@ -3416,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) { @@ -3445,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); } } } @@ -3529,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); } /** @@ -3798,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); |