blob: beb48b60814287dd3a0f543ad75c62b45154b66e [file] [log] [blame]
Richard Purdie2b97eab2006-10-06 18:32:18 +02001/*
2 * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
3 *
4 * Copyright 2005 Wolfson Microelectronics PLC.
Liam Girdwoodd3311242008-10-12 13:17:36 +01005 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
Richard Purdie2b97eab2006-10-06 18:32:18 +02006 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
Richard Purdie2b97eab2006-10-06 18:32:18 +020012 * Features:
13 * o Changes power status of internal codec blocks depending on the
14 * dynamic configuration of codec internal audio paths and active
Mark Brown74b8f952009-06-06 11:26:15 +010015 * DACs/ADCs.
Richard Purdie2b97eab2006-10-06 18:32:18 +020016 * o Platform power domain - can support external components i.e. amps and
Liam Girdwood612a3fe2012-02-06 16:05:29 +000017 * mic/headphone insertion events.
Richard Purdie2b97eab2006-10-06 18:32:18 +020018 * o Automatic Mic Bias support
19 * o Jack insertion power event initiation - e.g. hp insertion will enable
20 * sinks, dacs, etc
Liam Girdwood612a3fe2012-02-06 16:05:29 +000021 * o Delayed power down of audio subsystem to reduce pops between a quick
Richard Purdie2b97eab2006-10-06 18:32:18 +020022 * device reopen.
23 *
Richard Purdie2b97eab2006-10-06 18:32:18 +020024 */
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/init.h>
Mark Brown9d0624a2011-02-18 11:49:43 -080029#include <linux/async.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020030#include <linux/delay.h>
31#include <linux/pm.h>
32#include <linux/bitops.h>
33#include <linux/platform_device.h>
34#include <linux/jiffies.h>
Takashi Iwai20496ff2009-08-24 09:40:34 +020035#include <linux/debugfs.h>
Mark Brownf1aac482011-12-05 15:17:06 +000036#include <linux/pm_runtime.h>
Mark Brown62ea8742012-01-21 21:14:48 +000037#include <linux/regulator/consumer.h>
Ola Liljad7e7eb92012-05-24 15:26:25 +020038#include <linux/clk.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090039#include <linux/slab.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020040#include <sound/core.h>
41#include <sound/pcm.h>
42#include <sound/pcm_params.h>
Liam Girdwoodce6120c2010-11-05 15:53:46 +020043#include <sound/soc.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020044#include <sound/initval.h>
45
Mark Brown84e90932010-11-04 00:07:02 -040046#include <trace/events/asoc.h>
47
Mark Brownde02d072011-09-20 21:43:24 +010048#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
49
Lars-Peter Clausen57295072013-08-05 11:27:31 +020050static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
51 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
52 const char *control,
53 int (*connected)(struct snd_soc_dapm_widget *source,
54 struct snd_soc_dapm_widget *sink));
55static struct snd_soc_dapm_widget *
56snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
57 const struct snd_soc_dapm_widget *widget);
58
Richard Purdie2b97eab2006-10-06 18:32:18 +020059/* dapm power sequences - make this per codec in the future */
60static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010061 [snd_soc_dapm_pre] = 0,
Mark Brown62ea8742012-01-21 21:14:48 +000062 [snd_soc_dapm_regulator_supply] = 1,
Ola Liljad7e7eb92012-05-24 15:26:25 +020063 [snd_soc_dapm_clock_supply] = 1,
Mark Brown1dd275b2013-10-09 13:56:37 +010064 [snd_soc_dapm_supply] = 2,
65 [snd_soc_dapm_micbias] = 3,
Mark Brownc74184e2012-04-04 22:12:09 +010066 [snd_soc_dapm_dai_link] = 2,
Mark Brown1dd275b2013-10-09 13:56:37 +010067 [snd_soc_dapm_dai_in] = 4,
68 [snd_soc_dapm_dai_out] = 4,
69 [snd_soc_dapm_aif_in] = 4,
70 [snd_soc_dapm_aif_out] = 4,
71 [snd_soc_dapm_mic] = 5,
72 [snd_soc_dapm_mux] = 6,
Mark Brown1dd275b2013-10-09 13:56:37 +010073 [snd_soc_dapm_dac] = 7,
74 [snd_soc_dapm_switch] = 8,
75 [snd_soc_dapm_mixer] = 8,
76 [snd_soc_dapm_mixer_named_ctl] = 8,
77 [snd_soc_dapm_pga] = 9,
78 [snd_soc_dapm_adc] = 10,
79 [snd_soc_dapm_out_drv] = 11,
80 [snd_soc_dapm_hp] = 11,
81 [snd_soc_dapm_spk] = 11,
82 [snd_soc_dapm_line] = 11,
83 [snd_soc_dapm_kcontrol] = 12,
84 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020085};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000086
Richard Purdie2b97eab2006-10-06 18:32:18 +020087static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010088 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +020089 [snd_soc_dapm_kcontrol] = 1,
90 [snd_soc_dapm_adc] = 2,
91 [snd_soc_dapm_hp] = 3,
92 [snd_soc_dapm_spk] = 3,
93 [snd_soc_dapm_line] = 3,
94 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +010095 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +020096 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +010097 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +010098 [snd_soc_dapm_mixer] = 5,
99 [snd_soc_dapm_dac] = 6,
100 [snd_soc_dapm_mic] = 7,
101 [snd_soc_dapm_micbias] = 8,
102 [snd_soc_dapm_mux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100103 [snd_soc_dapm_aif_in] = 10,
104 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100105 [snd_soc_dapm_dai_in] = 10,
106 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100107 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100108 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100109 [snd_soc_dapm_clock_supply] = 13,
110 [snd_soc_dapm_regulator_supply] = 13,
111 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200112};
113
Mark Brownf9fa2b12014-03-06 16:49:11 +0800114static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
115{
116 if (dapm->card && dapm->card->instantiated)
117 lockdep_assert_held(&dapm->card->dapm_mutex);
118}
119
Troy Kisky12ef1932008-10-13 17:42:14 -0700120static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100121{
122 if (pop_time)
123 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
124}
125
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200126static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100127{
128 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200129 char *buf;
130
131 if (!pop_time)
132 return;
133
134 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
135 if (buf == NULL)
136 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100137
138 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200139 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100140 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100141 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200142
143 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100144}
145
Mark Browndb432b42011-10-03 21:06:40 +0100146static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
147{
148 return !list_empty(&w->dirty);
149}
150
Mark Brown492c0a12014-03-06 16:15:48 +0800151static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100152{
Mark Brownf9fa2b12014-03-06 16:49:11 +0800153 dapm_assert_locked(w->dapm);
154
Mark Brown75c1f892011-10-04 22:28:08 +0100155 if (!dapm_dirty_widget(w)) {
156 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
157 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100158 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100159 }
Mark Browndb432b42011-10-03 21:06:40 +0100160}
161
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200162/*
163 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
164 * paths
165 * @w: The widget for which to invalidate the cached number of input paths
166 *
167 * The function resets the cached number of inputs for the specified widget and
168 * all widgets that can be reached via outgoing paths from the widget.
169 *
170 * This function must be called if the number of input paths for a widget might
171 * have changed. E.g. if the source state of a widget changes or a path is added
172 * or activated with the widget as the sink.
173 */
174static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
175{
176 struct snd_soc_dapm_widget *sink;
177 struct snd_soc_dapm_path *p;
178 LIST_HEAD(list);
179
180 dapm_assert_locked(w->dapm);
181
182 if (w->inputs == -1)
183 return;
184
185 w->inputs = -1;
186 list_add_tail(&w->work_list, &list);
187
188 list_for_each_entry(w, &list, work_list) {
189 list_for_each_entry(p, &w->sinks, list_source) {
190 if (p->is_supply || p->weak || !p->connect)
191 continue;
192 sink = p->sink;
193 if (sink->inputs != -1) {
194 sink->inputs = -1;
195 list_add_tail(&sink->work_list, &list);
196 }
197 }
198 }
199}
200
201/*
202 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
203 * output paths
204 * @w: The widget for which to invalidate the cached number of output paths
205 *
206 * Resets the cached number of outputs for the specified widget and all widgets
207 * that can be reached via incoming paths from the widget.
208 *
209 * This function must be called if the number of output paths for a widget might
210 * have changed. E.g. if the sink state of a widget changes or a path is added
211 * or activated with the widget as the source.
212 */
213static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
214{
215 struct snd_soc_dapm_widget *source;
216 struct snd_soc_dapm_path *p;
217 LIST_HEAD(list);
218
219 dapm_assert_locked(w->dapm);
220
221 if (w->outputs == -1)
222 return;
223
224 w->outputs = -1;
225 list_add_tail(&w->work_list, &list);
226
227 list_for_each_entry(w, &list, work_list) {
228 list_for_each_entry(p, &w->sources, list_sink) {
229 if (p->is_supply || p->weak || !p->connect)
230 continue;
231 source = p->source;
232 if (source->outputs != -1) {
233 source->outputs = -1;
234 list_add_tail(&source->work_list, &list);
235 }
236 }
237 }
238}
239
240/*
241 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
242 * for the widgets connected to a path
243 * @p: The path to invalidate
244 *
245 * Resets the cached number of inputs for the sink of the path and the cached
246 * number of outputs for the source of the path.
247 *
248 * This function must be called when a path is added, removed or the connected
249 * state changes.
250 */
251static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
252{
253 /*
254 * Weak paths or supply paths do not influence the number of input or
255 * output paths of their neighbors.
256 */
257 if (p->weak || p->is_supply)
258 return;
259
260 /*
261 * The number of connected endpoints is the sum of the number of
262 * connected endpoints of all neighbors. If a node with 0 connected
263 * endpoints is either connected or disconnected that sum won't change,
264 * so there is no need to re-check the path.
265 */
266 if (p->source->inputs != 0)
267 dapm_widget_invalidate_input_paths(p->sink);
268 if (p->sink->outputs != 0)
269 dapm_widget_invalidate_output_paths(p->source);
270}
271
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200272void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
Mark Browne2d32ff2012-08-31 17:38:32 -0700273{
Mark Browne2d32ff2012-08-31 17:38:32 -0700274 struct snd_soc_dapm_widget *w;
275
276 mutex_lock(&card->dapm_mutex);
277
278 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200279 if (w->is_sink || w->is_source) {
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200280 dapm_mark_dirty(w, "Rechecking endpoints");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200281 if (w->is_sink)
282 dapm_widget_invalidate_output_paths(w);
283 if (w->is_source)
284 dapm_widget_invalidate_input_paths(w);
285 }
Mark Browne2d32ff2012-08-31 17:38:32 -0700286 }
287
288 mutex_unlock(&card->dapm_mutex);
289}
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200290EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
Mark Browne2d32ff2012-08-31 17:38:32 -0700291
Richard Purdie2b97eab2006-10-06 18:32:18 +0200292/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100293static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200294 const struct snd_soc_dapm_widget *_widget)
295{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100296 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200297}
298
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200299struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200300 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200301 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200302 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200303 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200304};
305
306static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
307 struct snd_kcontrol *kcontrol)
308{
309 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200310 struct soc_mixer_control *mc;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200311
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200312 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100313 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200314 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200315
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200316 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200317
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200318 switch (widget->id) {
319 case snd_soc_dapm_switch:
320 case snd_soc_dapm_mixer:
321 case snd_soc_dapm_mixer_named_ctl:
322 mc = (struct soc_mixer_control *)kcontrol->private_value;
323
324 if (mc->autodisable) {
325 struct snd_soc_dapm_widget template;
326
327 memset(&template, 0, sizeof(template));
328 template.reg = mc->reg;
329 template.mask = (1 << fls(mc->max)) - 1;
330 template.shift = mc->shift;
331 if (mc->invert)
332 template.off_val = mc->max;
333 else
334 template.off_val = 0;
335 template.on_val = template.off_val;
336 template.id = snd_soc_dapm_kcontrol;
337 template.name = kcontrol->id.name;
338
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200339 data->value = template.on_val;
340
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200341 data->widget = snd_soc_dapm_new_control(widget->dapm,
342 &template);
343 if (!data->widget) {
344 kfree(data);
345 return -ENOMEM;
346 }
347 }
348 break;
349 default:
350 break;
351 }
352
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200353 kcontrol->private_data = data;
354
355 return 0;
356}
357
358static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
359{
360 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200361 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200362 kfree(data);
363}
364
365static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
366 const struct snd_kcontrol *kcontrol)
367{
368 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
369
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200370 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200371}
372
373static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
374 struct snd_soc_dapm_widget *widget)
375{
376 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200377 struct snd_soc_dapm_widget_list *new_wlist;
378 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200379
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200380 if (data->wlist)
381 n = data->wlist->num_widgets + 1;
382 else
383 n = 1;
384
385 new_wlist = krealloc(data->wlist,
386 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
387 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200388 return -ENOMEM;
389
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200390 new_wlist->widgets[n - 1] = widget;
391 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200392
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200393 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200394
395 return 0;
396}
397
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200398static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
399 struct snd_soc_dapm_path *path)
400{
401 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
402
403 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200404
405 if (data->widget) {
406 snd_soc_dapm_add_path(data->widget->dapm, data->widget,
407 path->source, NULL, NULL);
408 }
409}
410
411static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
412{
413 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
414
415 if (!data->widget)
416 return true;
417
418 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200419}
420
421static struct list_head *dapm_kcontrol_get_path_list(
422 const struct snd_kcontrol *kcontrol)
423{
424 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
425
426 return &data->paths;
427}
428
429#define dapm_kcontrol_for_each_path(path, kcontrol) \
430 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
431 list_kcontrol)
432
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530433unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200434{
435 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
436
437 return data->value;
438}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530439EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200440
441static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
442 unsigned int value)
443{
444 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
445
446 if (data->value == value)
447 return false;
448
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200449 if (data->widget)
450 data->widget->on_val = value;
451
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200452 data->value = value;
453
454 return true;
455}
456
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200457/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200458 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
459 * kcontrol
460 * @kcontrol: The kcontrol
461 *
462 * Note: This function must only be used on kcontrols that are known to have
463 * been registered for a CODEC. Otherwise the behaviour is undefined.
464 */
465struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
466 struct snd_kcontrol *kcontrol)
467{
468 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
469}
470EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
471
Liam Girdwood6c120e12012-02-15 15:15:34 +0000472static void dapm_reset(struct snd_soc_card *card)
473{
474 struct snd_soc_dapm_widget *w;
475
Mark Brownf9fa2b12014-03-06 16:49:11 +0800476 lockdep_assert_held(&card->dapm_mutex);
477
Liam Girdwood6c120e12012-02-15 15:15:34 +0000478 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
479
480 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200481 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000482 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000483 }
484}
485
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200486static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
487{
488 if (!dapm->component)
489 return NULL;
490 return dapm->component->name_prefix;
491}
492
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200493static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800494 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100495{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200496 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200497 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200498 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100499}
500
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200501static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800502 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100503{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200504 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200505 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000506 return snd_soc_component_update_bits(dapm->component, reg,
507 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000508}
509
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200510static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
511 int reg, unsigned int mask, unsigned int value)
512{
513 if (!dapm->component)
514 return -EIO;
515 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
516}
517
Mark Browneb270e92013-10-09 13:52:52 +0100518static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
519{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200520 if (dapm->component)
521 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100522}
523
Mark Brown452c5ea2009-05-17 21:41:23 +0100524/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200525 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
526 * @dapm: The DAPM context for which to set the level
527 * @level: The level to set
528 *
529 * Forces the DAPM bias level to a specific state. It will call the bias level
530 * callback of DAPM context with the specified level. This will even happen if
531 * the context is already at the same level. Furthermore it will not go through
532 * the normal bias level sequencing, meaning any intermediate states between the
533 * current and the target state will not be entered.
534 *
535 * Note that the change in bias level is only temporary and the next time
536 * snd_soc_dapm_sync() is called the state will be set to the level as
537 * determined by the DAPM core. The function is mainly intended to be used to
538 * used during probe or resume from suspend to power up the device so
539 * initialization can be done, before the DAPM core takes over.
540 */
541int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
542 enum snd_soc_bias_level level)
543{
544 int ret = 0;
545
546 if (dapm->set_bias_level)
547 ret = dapm->set_bias_level(dapm, level);
548
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200549 if (ret == 0)
550 dapm->bias_level = level;
551
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200552 return ret;
553}
554EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
555
556/**
Mark Brown452c5ea2009-05-17 21:41:23 +0100557 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800558 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100559 * @level: level to configure
560 *
561 * Configure the bias (power) levels for the SoC audio device.
562 *
563 * Returns 0 for success else error.
564 */
Mark Browned5a4c42011-02-18 11:12:42 -0800565static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200566 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100567{
Mark Browned5a4c42011-02-18 11:12:42 -0800568 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100569 int ret = 0;
570
Mark Brown84e90932010-11-04 00:07:02 -0400571 trace_snd_soc_bias_level_start(card, level);
572
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000573 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100574 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100575 if (ret != 0)
576 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100577
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200578 if (!card || dapm != &card->dapm)
579 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100580
Mark Brown171ec6b2011-06-06 18:15:19 +0100581 if (ret != 0)
582 goto out;
583
584 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100585 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100586out:
Mark Brown84e90932010-11-04 00:07:02 -0400587 trace_snd_soc_bias_level_done(card, level);
588
Mark Brown452c5ea2009-05-17 21:41:23 +0100589 return ret;
590}
591
Mark Brown74b8f952009-06-06 11:26:15 +0100592/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200593static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200594 struct snd_soc_dapm_path *path, const char *control_name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200595{
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200596 const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200597 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100598 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200599 int i;
600
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100601 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200602 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100603 val = (val >> e->shift_l) & e->mask;
604 item = snd_soc_enum_val_to_item(e, val);
605 } else {
606 /* since a virtual mux has no backing registers to
607 * decide which path to connect, it will try to match
608 * with the first enumeration. This is to ensure
609 * that the default mux choice (the first) will be
610 * correctly powered up during initialization.
611 */
612 item = 0;
613 }
614
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100615 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200616 if (!(strcmp(control_name, e->texts[i]))) {
Rasmus Villemoes98ad73c2014-10-21 17:01:15 +0200617 path->name = e->texts[i];
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100618 if (i == item)
619 path->connect = 1;
620 else
621 path->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200622 return 0;
623 }
624 }
625
626 return -ENODEV;
627}
628
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100629/* set up initial codec paths */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200630static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100631{
632 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200633 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100634 unsigned int reg = mc->reg;
635 unsigned int shift = mc->shift;
636 unsigned int max = mc->max;
637 unsigned int mask = (1 << fls(max)) - 1;
638 unsigned int invert = mc->invert;
639 unsigned int val;
640
641 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200642 soc_dapm_read(p->sink->dapm, reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100643 val = (val >> shift) & mask;
644 if (invert)
645 val = max - val;
646 p->connect = !!val;
647 } else {
648 p->connect = 0;
649 }
650}
651
Mark Brown74b8f952009-06-06 11:26:15 +0100652/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200653static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200654 struct snd_soc_dapm_path *path, const char *control_name)
655{
656 int i;
657
658 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200659 for (i = 0; i < path->sink->num_kcontrols; i++) {
660 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
661 path->name = path->sink->kcontrol_news[i].name;
662 dapm_set_mixer_path_status(path, i);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200663 return 0;
664 }
665 }
666 return -ENODEV;
667}
668
Stephen Warrenaf468002011-04-28 17:38:01 -0600669static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600670 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600671 const struct snd_kcontrol_new *kcontrol_new,
672 struct snd_kcontrol **kcontrol)
673{
674 struct snd_soc_dapm_widget *w;
675 int i;
676
677 *kcontrol = NULL;
678
679 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600680 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
681 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600682 for (i = 0; i < w->num_kcontrols; i++) {
683 if (&w->kcontrol_news[i] == kcontrol_new) {
684 if (w->kcontrols)
685 *kcontrol = w->kcontrols[i];
686 return 1;
687 }
688 }
689 }
690
691 return 0;
692}
693
Stephen Warren85762e72013-03-29 15:40:10 -0600694/*
695 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
696 * create it. Either way, add the widget into the control's widget list
697 */
698static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100699 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200700{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200701 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000702 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000703 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600704 size_t prefix_len;
705 int shared;
706 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600707 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200708 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600709 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200710 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000711
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200712 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000713 if (prefix)
714 prefix_len = strlen(prefix) + 1;
715 else
716 prefix_len = 0;
717
Stephen Warren85762e72013-03-29 15:40:10 -0600718 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
719 &kcontrol);
720
Stephen Warren85762e72013-03-29 15:40:10 -0600721 if (!kcontrol) {
722 if (shared) {
723 wname_in_long_name = false;
724 kcname_in_long_name = true;
725 } else {
726 switch (w->id) {
727 case snd_soc_dapm_switch:
728 case snd_soc_dapm_mixer:
729 wname_in_long_name = true;
730 kcname_in_long_name = true;
731 break;
732 case snd_soc_dapm_mixer_named_ctl:
733 wname_in_long_name = false;
734 kcname_in_long_name = true;
735 break;
736 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600737 wname_in_long_name = true;
738 kcname_in_long_name = false;
739 break;
740 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600741 return -EINVAL;
742 }
743 }
744
745 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600746 /*
747 * The control will get a prefix from the control
748 * creation process but we're also using the same
749 * prefix for widgets so cut the prefix off the
750 * front of the widget name.
751 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200752 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600753 w->name + prefix_len,
754 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200755 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200756 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600757
758 name = long_name;
759 } else if (wname_in_long_name) {
760 long_name = NULL;
761 name = w->name + prefix_len;
762 } else {
763 long_name = NULL;
764 name = w->kcontrol_news[kci].name;
765 }
766
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200767 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600768 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200769 if (!kcontrol) {
770 ret = -ENOMEM;
771 goto exit_free;
772 }
773
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200774 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200775
776 ret = dapm_kcontrol_data_alloc(w, kcontrol);
777 if (ret) {
778 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200779 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200780 }
781
Stephen Warren85762e72013-03-29 15:40:10 -0600782 ret = snd_ctl_add(card, kcontrol);
783 if (ret < 0) {
784 dev_err(dapm->dev,
785 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
786 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200787 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600788 }
Stephen Warren85762e72013-03-29 15:40:10 -0600789 }
790
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200791 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200792 if (ret == 0)
793 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200794
Daniel Macke5092c92014-10-07 13:41:24 +0200795exit_free:
796 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600797
Daniel Macke5092c92014-10-07 13:41:24 +0200798 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600799}
800
801/* create new dapm mixer control */
802static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
803{
804 int i, ret;
805 struct snd_soc_dapm_path *path;
806
Richard Purdie2b97eab2006-10-06 18:32:18 +0200807 /* add kcontrol */
808 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200809 /* match name */
810 list_for_each_entry(path, &w->sources, list_sink) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200811 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600812 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200813 continue;
814
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200815 if (w->kcontrols[i]) {
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200816 dapm_kcontrol_add_path(w->kcontrols[i], path);
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200817 continue;
818 }
819
Mark Brown946d92a2013-08-12 23:28:42 +0100820 ret = dapm_create_or_share_mixmux_kcontrol(w, i);
Stephen Warren85762e72013-03-29 15:40:10 -0600821 if (ret < 0)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200822 return ret;
Mark Brown946d92a2013-08-12 23:28:42 +0100823
824 dapm_kcontrol_add_path(w->kcontrols[i], path);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200825 }
826 }
Stephen Warren85762e72013-03-29 15:40:10 -0600827
828 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200829}
830
831/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200832static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200833{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200834 struct snd_soc_dapm_context *dapm = w->dapm;
Stephen Warren85762e72013-03-29 15:40:10 -0600835 struct snd_soc_dapm_path *path;
Stephen Warrenaf468002011-04-28 17:38:01 -0600836 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200837
Stephen Warrenaf468002011-04-28 17:38:01 -0600838 if (w->num_kcontrols != 1) {
839 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000840 "ASoC: mux %s has incorrect number of controls\n",
Stephen Warrenaf468002011-04-28 17:38:01 -0600841 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200842 return -EINVAL;
843 }
844
Lars-Peter Clausenfe5813912013-08-01 18:30:38 +0200845 if (list_empty(&w->sources)) {
Stephen Warren85762e72013-03-29 15:40:10 -0600846 dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
847 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600848 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200849
Mark Brown946d92a2013-08-12 23:28:42 +0100850 ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600851 if (ret < 0)
852 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600853
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +0200854 list_for_each_entry(path, &w->sources, list_sink) {
855 if (path->name)
856 dapm_kcontrol_add_path(w->kcontrols[0], path);
857 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200858
Stephen Warrenaf468002011-04-28 17:38:01 -0600859 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200860}
861
862/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200863static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200864{
Mark Browna6c65732010-03-03 17:45:21 +0000865 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200866 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000867 "ASoC: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200868
Mark Browna6c65732010-03-03 17:45:21 +0000869 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200870}
871
Nikesh Oswalc6615082015-02-02 17:06:44 +0000872/* create new dapm dai link control */
873static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
874{
875 int i, ret;
876 struct snd_kcontrol *kcontrol;
877 struct snd_soc_dapm_context *dapm = w->dapm;
878 struct snd_card *card = dapm->card->snd_card;
879
880 /* create control for links with > 1 config */
881 if (w->num_params <= 1)
882 return 0;
883
884 /* add kcontrol */
885 for (i = 0; i < w->num_kcontrols; i++) {
886 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
887 w->name, NULL);
888 ret = snd_ctl_add(card, kcontrol);
889 if (ret < 0) {
890 dev_err(dapm->dev,
891 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
892 w->name, w->kcontrol_news[i].name, ret);
893 return ret;
894 }
895 kcontrol->private_data = w;
896 w->kcontrols[i] = kcontrol;
897 }
898
899 return 0;
900}
901
Mark Brown99497882010-05-07 20:24:05 +0100902/* We implement power down on suspend by checking the power state of
903 * the ALSA card - when we are suspending the ALSA state for the card
904 * is set to D3.
905 */
906static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
907{
Mark Brown12ea2c72011-03-02 18:17:32 +0000908 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +0100909
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000910 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +0100911 case SNDRV_CTL_POWER_D3hot:
912 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +0100913 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000914 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200915 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +0100916 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +0100917 default:
918 return 1;
919 }
920}
921
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100922/* add widget to list if it's not already in the list */
923static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
924 struct snd_soc_dapm_widget *w)
925{
926 struct snd_soc_dapm_widget_list *wlist;
927 int wlistsize, wlistentries, i;
928
929 if (*list == NULL)
930 return -EINVAL;
931
932 wlist = *list;
933
934 /* is this widget already in the list */
935 for (i = 0; i < wlist->num_widgets; i++) {
936 if (wlist->widgets[i] == w)
937 return 0;
938 }
939
940 /* allocate some new space */
941 wlistentries = wlist->num_widgets + 1;
942 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
943 wlistentries * sizeof(struct snd_soc_dapm_widget *);
944 *list = krealloc(wlist, wlistsize, GFP_KERNEL);
945 if (*list == NULL) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000946 dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100947 w->name);
948 return -ENOMEM;
949 }
950 wlist = *list;
951
952 /* insert the widget */
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000953 dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100954 w->name, wlist->num_widgets);
955
956 wlist->widgets[wlist->num_widgets] = w;
957 wlist->num_widgets++;
958 return 1;
959}
960
Richard Purdie2b97eab2006-10-06 18:32:18 +0200961/*
962 * Recursively check for a completed path to an active or physically connected
963 * output widget. Returns number of complete paths.
964 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100965static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
966 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200967{
968 struct snd_soc_dapm_path *path;
969 int con = 0;
970
Mark Brown024dc072011-10-09 11:52:05 +0100971 if (widget->outputs >= 0)
972 return widget->outputs;
973
Mark Brownde02d072011-09-20 21:43:24 +0100974 DAPM_UPDATE_STAT(widget, path_checks);
975
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +0200976 if (widget->is_sink && widget->connected) {
977 widget->outputs = snd_soc_dapm_suspend_check(widget);
978 return widget->outputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200979 }
980
981 list_for_each_entry(path, &widget->sinks, list_source) {
Mark Browne56235e02011-09-21 18:19:14 +0100982 DAPM_UPDATE_STAT(widget, neighbour_checks);
983
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +0200984 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +0100985 continue;
986
Mark Brown8af294b2013-02-22 17:48:15 +0000987 if (path->walking)
988 return 1;
989
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100990 trace_snd_soc_dapm_output_path(widget, path);
991
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +0200992 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +0000993 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100994
995 /* do we need to add this widget to the list ? */
996 if (list) {
997 int err;
998 err = dapm_list_add_widget(list, path->sink);
999 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001000 dev_err(widget->dapm->dev,
1001 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001002 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +00001003 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001004 return con;
1005 }
1006 }
1007
1008 con += is_connected_output_ep(path->sink, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001009
1010 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001011 }
1012 }
1013
Mark Brown024dc072011-10-09 11:52:05 +01001014 widget->outputs = con;
1015
Richard Purdie2b97eab2006-10-06 18:32:18 +02001016 return con;
1017}
1018
1019/*
1020 * Recursively check for a completed path to an active or physically connected
1021 * input widget. Returns number of complete paths.
1022 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001023static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
1024 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001025{
1026 struct snd_soc_dapm_path *path;
1027 int con = 0;
1028
Mark Brown024dc072011-10-09 11:52:05 +01001029 if (widget->inputs >= 0)
1030 return widget->inputs;
1031
Mark Brownde02d072011-09-20 21:43:24 +01001032 DAPM_UPDATE_STAT(widget, path_checks);
1033
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001034 if (widget->is_source && widget->connected) {
1035 widget->inputs = snd_soc_dapm_suspend_check(widget);
1036 return widget->inputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001037 }
1038
1039 list_for_each_entry(path, &widget->sources, list_sink) {
Mark Browne56235e02011-09-21 18:19:14 +01001040 DAPM_UPDATE_STAT(widget, neighbour_checks);
1041
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001042 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001043 continue;
1044
Mark Brown8af294b2013-02-22 17:48:15 +00001045 if (path->walking)
1046 return 1;
1047
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001048 trace_snd_soc_dapm_input_path(widget, path);
1049
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001050 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001051 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001052
1053 /* do we need to add this widget to the list ? */
1054 if (list) {
1055 int err;
Liam Girdwood90c6ce02012-06-05 19:27:15 +01001056 err = dapm_list_add_widget(list, path->source);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001057 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001058 dev_err(widget->dapm->dev,
1059 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001060 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +00001061 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001062 return con;
1063 }
1064 }
1065
1066 con += is_connected_input_ep(path->source, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001067
1068 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001069 }
1070 }
1071
Mark Brown024dc072011-10-09 11:52:05 +01001072 widget->inputs = con;
1073
Richard Purdie2b97eab2006-10-06 18:32:18 +02001074 return con;
1075}
1076
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001077/**
1078 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1079 * @dai: the soc DAI.
1080 * @stream: stream direction.
1081 * @list: list of active widgets for this stream.
1082 *
1083 * Queries DAPM graph as to whether an valid audio stream path exists for
1084 * the initial stream specified by name. This takes into account
1085 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1086 *
1087 * Returns the number of valid paths or negative error.
1088 */
1089int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1090 struct snd_soc_dapm_widget_list **list)
1091{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001092 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001093 struct snd_soc_dapm_widget *w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001094 int paths;
1095
1096 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001097
1098 /*
1099 * For is_connected_{output,input}_ep fully discover the graph we need
1100 * to reset the cached number of inputs and outputs.
1101 */
1102 list_for_each_entry(w, &card->widgets, list) {
1103 w->inputs = -1;
1104 w->outputs = -1;
1105 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001106
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001107 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001108 paths = is_connected_output_ep(dai->playback_widget, list);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001109 else
Liam Girdwoodd298caa2012-06-01 18:03:00 +01001110 paths = is_connected_input_ep(dai->capture_widget, list);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001111
1112 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001113 mutex_unlock(&card->dapm_mutex);
1114
1115 return paths;
1116}
1117
Richard Purdie2b97eab2006-10-06 18:32:18 +02001118/*
Mark Brown62ea8742012-01-21 21:14:48 +00001119 * Handler for regulator supply widget.
1120 */
1121int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1122 struct snd_kcontrol *kcontrol, int event)
1123{
Mark Brownc05b84d2012-09-07 12:57:11 +08001124 int ret;
1125
Mark Browneb270e92013-10-09 13:52:52 +01001126 soc_dapm_async_complete(w->dapm);
1127
Mark Brownc05b84d2012-09-07 12:57:11 +08001128 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001129 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001130 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001131 if (ret != 0)
1132 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001133 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001134 w->name, ret);
1135 }
1136
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001137 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001138 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001139 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001140 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001141 if (ret != 0)
1142 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001143 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001144 w->name, ret);
1145 }
1146
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001147 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001148 }
Mark Brown62ea8742012-01-21 21:14:48 +00001149}
1150EXPORT_SYMBOL_GPL(dapm_regulator_event);
1151
Ola Liljad7e7eb92012-05-24 15:26:25 +02001152/*
1153 * Handler for clock supply widget.
1154 */
1155int dapm_clock_event(struct snd_soc_dapm_widget *w,
1156 struct snd_kcontrol *kcontrol, int event)
1157{
1158 if (!w->clk)
1159 return -EIO;
1160
Mark Browneb270e92013-10-09 13:52:52 +01001161 soc_dapm_async_complete(w->dapm);
1162
Mark Brownec029952012-06-04 08:16:20 +01001163#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001164 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001165 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001166 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001167 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001168 return 0;
1169 }
Mark Brownec029952012-06-04 08:16:20 +01001170#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001171 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001172}
1173EXPORT_SYMBOL_GPL(dapm_clock_event);
1174
Mark Brownd8050022011-09-28 18:28:23 +01001175static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1176{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001177 if (w->power_checked)
1178 return w->new_power;
1179
Mark Brownd8050022011-09-28 18:28:23 +01001180 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001181 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001182 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001183 w->new_power = w->power_check(w);
1184
1185 w->power_checked = true;
1186
1187 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001188}
1189
Mark Browncd0f2d42009-04-20 16:56:59 +01001190/* Generic check to see if a widget should be powered.
1191 */
1192static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1193{
1194 int in, out;
1195
Mark Brownde02d072011-09-20 21:43:24 +01001196 DAPM_UPDATE_STAT(w, power_checks);
1197
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001198 in = is_connected_input_ep(w, NULL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001199 out = is_connected_output_ep(w, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001200 return out != 0 && in != 0;
1201}
1202
Mark Brown246d0a12009-04-22 18:24:55 +01001203/* Check to see if a power supply is needed */
1204static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1205{
1206 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001207
Mark Brownde02d072011-09-20 21:43:24 +01001208 DAPM_UPDATE_STAT(w, power_checks);
1209
Mark Brown246d0a12009-04-22 18:24:55 +01001210 /* Check if one of our outputs is connected */
1211 list_for_each_entry(path, &w->sinks, list_source) {
Mark Browna8fdac82011-09-28 18:20:26 +01001212 DAPM_UPDATE_STAT(w, neighbour_checks);
1213
Mark Brownbf3a9e12011-06-13 16:42:29 +01001214 if (path->weak)
1215 continue;
1216
Mark Brown215edda2009-09-08 18:59:05 +01001217 if (path->connected &&
1218 !path->connected(path->source, path->sink))
1219 continue;
1220
Mark Brownf68d7e12011-10-04 22:57:50 +01001221 if (dapm_widget_power_check(path->sink))
1222 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001223 }
1224
Mark Brownf68d7e12011-10-04 22:57:50 +01001225 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001226}
1227
Mark Brown35c64bc2011-09-28 18:23:53 +01001228static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1229{
1230 return 1;
1231}
1232
Mark Brown38357ab2009-06-06 19:03:23 +01001233static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1234 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001235 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001236{
Mark Brown828a8422011-01-15 13:14:30 +00001237 int *sort;
1238
1239 if (power_up)
1240 sort = dapm_up_seq;
1241 else
1242 sort = dapm_down_seq;
1243
Mark Brown38357ab2009-06-06 19:03:23 +01001244 if (sort[a->id] != sort[b->id])
1245 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001246 if (a->subseq != b->subseq) {
1247 if (power_up)
1248 return a->subseq - b->subseq;
1249 else
1250 return b->subseq - a->subseq;
1251 }
Mark Brownb22ead22009-06-07 12:51:26 +01001252 if (a->reg != b->reg)
1253 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001254 if (a->dapm != b->dapm)
1255 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001256
Mark Brown38357ab2009-06-06 19:03:23 +01001257 return 0;
1258}
Mark Brown42aa3412009-03-01 19:21:10 +00001259
Mark Brown38357ab2009-06-06 19:03:23 +01001260/* Insert a widget in order into a DAPM power sequence. */
1261static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1262 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001263 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001264{
1265 struct snd_soc_dapm_widget *w;
1266
1267 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001268 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001269 list_add_tail(&new_widget->power_list, &w->power_list);
1270 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001271 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001272
Mark Brown38357ab2009-06-06 19:03:23 +01001273 list_add_tail(&new_widget->power_list, list);
1274}
Mark Brown42aa3412009-03-01 19:21:10 +00001275
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001276static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001277 struct snd_soc_dapm_widget *w, int event)
1278{
Mark Brown68f89ad2010-11-03 23:51:49 -04001279 const char *ev_name;
1280 int power, ret;
1281
1282 switch (event) {
1283 case SND_SOC_DAPM_PRE_PMU:
1284 ev_name = "PRE_PMU";
1285 power = 1;
1286 break;
1287 case SND_SOC_DAPM_POST_PMU:
1288 ev_name = "POST_PMU";
1289 power = 1;
1290 break;
1291 case SND_SOC_DAPM_PRE_PMD:
1292 ev_name = "PRE_PMD";
1293 power = 0;
1294 break;
1295 case SND_SOC_DAPM_POST_PMD:
1296 ev_name = "POST_PMD";
1297 power = 0;
1298 break;
Mark Brown80114122013-02-25 15:14:19 +00001299 case SND_SOC_DAPM_WILL_PMU:
1300 ev_name = "WILL_PMU";
1301 power = 1;
1302 break;
1303 case SND_SOC_DAPM_WILL_PMD:
1304 ev_name = "WILL_PMD";
1305 power = 0;
1306 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001307 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001308 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001309 return;
1310 }
1311
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001312 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001313 return;
1314
1315 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001316 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001317 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001318 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001319 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001320 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001321 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001322 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001323 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001324 ev_name, w->name, ret);
1325 }
1326}
1327
Mark Brownb22ead22009-06-07 12:51:26 +01001328/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001329static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001330 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001331{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001332 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001333 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001334 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001335 unsigned int value = 0;
1336 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001337
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001338 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1339 reg = w->reg;
1340 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001341
1342 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001343 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001344 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001345
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001346 mask |= w->mask << w->shift;
1347 if (w->power)
1348 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001349 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001350 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001351
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001352 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001353 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1354 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001355
Mark Brown68f89ad2010-11-03 23:51:49 -04001356 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001357 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1358 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001359 }
1360
Mark Brown81628102009-06-07 13:21:24 +01001361 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001362 /* Any widget will do, they should all be updating the
1363 * same register.
1364 */
Mark Brown29376bc2011-06-19 13:49:28 +01001365
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001366 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001367 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001368 value, mask, reg, card->pop_time);
1369 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001370 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001371 }
1372
1373 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001374 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1375 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001376 }
Mark Brown42aa3412009-03-01 19:21:10 +00001377}
1378
Mark Brownb22ead22009-06-07 12:51:26 +01001379/* Apply a DAPM power sequence.
1380 *
1381 * We walk over a pre-sorted list of widgets to apply power to. In
1382 * order to minimise the number of writes to the device required
1383 * multiple widgets will be updated in a single write where possible.
1384 * Currently anything that requires more than a single write is not
1385 * handled.
1386 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001387static void dapm_seq_run(struct snd_soc_card *card,
1388 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001389{
1390 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001391 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001392 LIST_HEAD(pending);
1393 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001394 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001395 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001396 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001397 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001398 int *sort;
1399
1400 if (power_up)
1401 sort = dapm_up_seq;
1402 else
1403 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001404
Mark Brownb22ead22009-06-07 12:51:26 +01001405 list_for_each_entry_safe(w, n, list, power_list) {
1406 ret = 0;
1407
1408 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001409 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001410 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001411 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001412 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001413
Mark Brown474b62d2011-01-18 16:14:44 +00001414 if (cur_dapm && cur_dapm->seq_notifier) {
1415 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1416 if (sort[i] == cur_sort)
1417 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001418 i,
1419 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001420 }
1421
Mark Browneb270e92013-10-09 13:52:52 +01001422 if (cur_dapm && w->dapm != cur_dapm)
1423 soc_dapm_async_complete(cur_dapm);
1424
Mark Brownb22ead22009-06-07 12:51:26 +01001425 INIT_LIST_HEAD(&pending);
1426 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001427 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001428 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001429 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001430 }
1431
Mark Brown163cac02009-06-07 10:12:52 +01001432 switch (w->id) {
1433 case snd_soc_dapm_pre:
1434 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001435 list_for_each_entry_safe_continue(w, n, list,
1436 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001437
Mark Brownb22ead22009-06-07 12:51:26 +01001438 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001439 ret = w->event(w,
1440 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001441 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001442 ret = w->event(w,
1443 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001444 break;
1445
1446 case snd_soc_dapm_post:
1447 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001448 list_for_each_entry_safe_continue(w, n, list,
1449 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001450
Mark Brownb22ead22009-06-07 12:51:26 +01001451 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001452 ret = w->event(w,
1453 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001454 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001455 ret = w->event(w,
1456 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001457 break;
1458
Mark Brown163cac02009-06-07 10:12:52 +01001459 default:
Mark Brown81628102009-06-07 13:21:24 +01001460 /* Queue it up for application */
1461 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001462 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001463 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001464 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001465 list_move(&w->power_list, &pending);
1466 break;
Mark Brown163cac02009-06-07 10:12:52 +01001467 }
Mark Brownb22ead22009-06-07 12:51:26 +01001468
1469 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001470 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001471 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001472 }
Mark Brownb22ead22009-06-07 12:51:26 +01001473
1474 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001475 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001476
1477 if (cur_dapm && cur_dapm->seq_notifier) {
1478 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1479 if (sort[i] == cur_sort)
1480 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001481 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001482 }
Mark Browneb270e92013-10-09 13:52:52 +01001483
1484 list_for_each_entry(d, &card->dapm_list, list) {
1485 soc_dapm_async_complete(d);
1486 }
Mark Brown163cac02009-06-07 10:12:52 +01001487}
1488
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001489static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001490{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001491 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001492 struct snd_soc_dapm_widget_list *wlist;
1493 struct snd_soc_dapm_widget *w = NULL;
1494 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001495 int ret;
1496
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001497 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001498 return;
1499
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001500 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001501
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001502 for (wi = 0; wi < wlist->num_widgets; wi++) {
1503 w = wlist->widgets[wi];
1504
1505 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1506 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1507 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001508 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001509 w->name, ret);
1510 }
Mark Brown97404f22010-12-14 16:13:57 +00001511 }
1512
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001513 if (!w)
1514 return;
1515
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001516 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1517 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001518 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001519 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001520 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001521
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001522 for (wi = 0; wi < wlist->num_widgets; wi++) {
1523 w = wlist->widgets[wi];
1524
1525 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1526 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1527 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001528 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001529 w->name, ret);
1530 }
Mark Brown97404f22010-12-14 16:13:57 +00001531 }
1532}
1533
Mark Brown9d0624a2011-02-18 11:49:43 -08001534/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1535 * they're changing state.
1536 */
1537static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1538{
1539 struct snd_soc_dapm_context *d = data;
1540 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001541
Mark Brown56fba412011-06-04 11:25:10 +01001542 /* If we're off and we're not supposed to be go into STANDBY */
1543 if (d->bias_level == SND_SOC_BIAS_OFF &&
1544 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001545 if (d->dev)
1546 pm_runtime_get_sync(d->dev);
1547
Mark Brown9d0624a2011-02-18 11:49:43 -08001548 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1549 if (ret != 0)
1550 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001551 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001552 }
1553
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001554 /* Prepare for a transition to ON or away from ON */
1555 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1556 d->bias_level != SND_SOC_BIAS_ON) ||
1557 (d->target_bias_level != SND_SOC_BIAS_ON &&
1558 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001559 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1560 if (ret != 0)
1561 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001562 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001563 }
1564}
1565
1566/* Async callback run prior to DAPM sequences - brings to their final
1567 * state.
1568 */
1569static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1570{
1571 struct snd_soc_dapm_context *d = data;
1572 int ret;
1573
1574 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001575 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1576 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1577 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001578 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1579 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001580 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001581 ret);
1582 }
1583
1584 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001585 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1586 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001587 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1588 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001589 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1590 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001591
1592 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001593 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001594 }
1595
1596 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001597 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1598 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001599 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1600 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001601 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001602 ret);
1603 }
1604}
Mark Brown97404f22010-12-14 16:13:57 +00001605
Mark Brownfe4fda52011-10-03 22:36:57 +01001606static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1607 bool power, bool connect)
1608{
1609 /* If a connection is being made or broken then that update
1610 * will have marked the peer dirty, otherwise the widgets are
1611 * not connected and this update has no impact. */
1612 if (!connect)
1613 return;
1614
1615 /* If the peer is already in the state we're moving to then we
1616 * won't have an impact on it. */
1617 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001618 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001619}
1620
Mark Brown05623c42011-09-28 17:02:31 +01001621static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1622 struct list_head *up_list,
1623 struct list_head *down_list)
1624{
Mark Browndb432b42011-10-03 21:06:40 +01001625 struct snd_soc_dapm_path *path;
1626
Mark Brown05623c42011-09-28 17:02:31 +01001627 if (w->power == power)
1628 return;
1629
1630 trace_snd_soc_dapm_widget_power(w, power);
1631
Mark Browndb432b42011-10-03 21:06:40 +01001632 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001633 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001634 */
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001635 list_for_each_entry(path, &w->sources, list_sink)
1636 dapm_widget_set_peer_power(path->source, power, path->connect);
1637
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001638 /* Supplies can't affect their outputs, only their inputs */
1639 if (!w->is_supply) {
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001640 list_for_each_entry(path, &w->sinks, list_source)
1641 dapm_widget_set_peer_power(path->sink, power,
1642 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001643 }
1644
Mark Brown05623c42011-09-28 17:02:31 +01001645 if (power)
1646 dapm_seq_insert(w, up_list, true);
1647 else
1648 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001649}
1650
Mark Brown7c81beb2011-09-20 22:22:32 +01001651static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1652 struct list_head *up_list,
1653 struct list_head *down_list)
1654{
Mark Brown7c81beb2011-09-20 22:22:32 +01001655 int power;
1656
1657 switch (w->id) {
1658 case snd_soc_dapm_pre:
1659 dapm_seq_insert(w, down_list, false);
1660 break;
1661 case snd_soc_dapm_post:
1662 dapm_seq_insert(w, up_list, true);
1663 break;
1664
1665 default:
Mark Brownd8050022011-09-28 18:28:23 +01001666 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001667
Mark Brown05623c42011-09-28 17:02:31 +01001668 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001669 break;
1670 }
1671}
1672
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001673static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1674{
1675 if (dapm->idle_bias_off)
1676 return true;
1677
1678 switch (snd_power_get_state(dapm->card->snd_card)) {
1679 case SNDRV_CTL_POWER_D3hot:
1680 case SNDRV_CTL_POWER_D3cold:
1681 return dapm->suspend_bias_off;
1682 default:
1683 break;
1684 }
1685
1686 return false;
1687}
1688
Mark Brown42aa3412009-03-01 19:21:10 +00001689/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001690 * Scan each dapm widget for complete audio path.
1691 * A complete path is a route that has valid endpoints i.e.:-
1692 *
1693 * o DAC to output pin.
1694 * o Input Pin to ADC.
1695 * o Input pin to Output pin (bypass, sidetone)
1696 * o DAC to ADC (loopback).
1697 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001698static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001699{
1700 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001701 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001702 LIST_HEAD(up_list);
1703 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001704 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001705 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001706
Mark Brownf9fa2b12014-03-06 16:49:11 +08001707 lockdep_assert_held(&card->dapm_mutex);
1708
Mark Brown84e90932010-11-04 00:07:02 -04001709 trace_snd_soc_dapm_start(card);
1710
Mark Brown56fba412011-06-04 11:25:10 +01001711 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001712 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001713 d->target_bias_level = SND_SOC_BIAS_OFF;
1714 else
1715 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001716 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001717
Liam Girdwood6c120e12012-02-15 15:15:34 +00001718 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001719
Mark Brown6d3ddc82009-05-16 17:47:29 +01001720 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001721 * lists indicating if they should be powered up or down. We
1722 * only check widgets that have been flagged as dirty but note
1723 * that new widgets may be added to the dirty list while we
1724 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001725 */
Mark Browndb432b42011-10-03 21:06:40 +01001726 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001727 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001728 }
1729
Mark Brownf9de6d72011-09-28 17:19:47 +01001730 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001731 switch (w->id) {
1732 case snd_soc_dapm_pre:
1733 case snd_soc_dapm_post:
1734 /* These widgets always need to be powered */
1735 break;
1736 default:
1737 list_del_init(&w->dirty);
1738 break;
1739 }
Mark Browndb432b42011-10-03 21:06:40 +01001740
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001741 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001742 d = w->dapm;
1743
1744 /* Supplies and micbiases only bring the
1745 * context up to STANDBY as unless something
1746 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001747 * generally don't require full power. Signal
1748 * generators are virtual pins and have no
1749 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001750 */
1751 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001752 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001753 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001754 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001755 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001756 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001757 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001758 case snd_soc_dapm_micbias:
1759 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1760 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1761 break;
1762 default:
1763 d->target_bias_level = SND_SOC_BIAS_ON;
1764 break;
1765 }
1766 }
1767
1768 }
1769
Mark Brown85a843c2011-09-21 21:29:47 +01001770 /* Force all contexts in the card to the same bias state if
1771 * they're not ground referenced.
1772 */
Mark Brown56fba412011-06-04 11:25:10 +01001773 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001774 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001775 if (d->target_bias_level > bias)
1776 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001777 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001778 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001779 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001780
Mark Brownde02d072011-09-20 21:43:24 +01001781 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001782
Xiang Xiao17282ba2014-03-02 00:04:03 +08001783 /* Run card bias changes at first */
1784 dapm_pre_sequence_async(&card->dapm, 0);
1785 /* Run other bias changes in parallel */
1786 list_for_each_entry(d, &card->dapm_list, list) {
1787 if (d != &card->dapm)
1788 async_schedule_domain(dapm_pre_sequence_async, d,
1789 &async_domain);
1790 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001791 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001792
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001793 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001794 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001795 }
1796
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001797 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001798 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001799 }
1800
Mark Brown6d3ddc82009-05-16 17:47:29 +01001801 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001802 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001803
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001804 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001805
Mark Brown6d3ddc82009-05-16 17:47:29 +01001806 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001807 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001808
Mark Brown9d0624a2011-02-18 11:49:43 -08001809 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001810 list_for_each_entry(d, &card->dapm_list, list) {
1811 if (d != &card->dapm)
1812 async_schedule_domain(dapm_post_sequence_async, d,
1813 &async_domain);
1814 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001815 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001816 /* Run card bias changes at last */
1817 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001818
Liam Girdwood8078d872012-02-15 15:15:35 +00001819 /* do we need to notify any clients that DAPM event is complete */
1820 list_for_each_entry(d, &card->dapm_list, list) {
1821 if (d->stream_event)
1822 d->stream_event(d, event);
1823 }
1824
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001825 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001826 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001827 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001828
Mark Brown84e90932010-11-04 00:07:02 -04001829 trace_snd_soc_dapm_done(card);
1830
Mark Brown42aa3412009-03-01 19:21:10 +00001831 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001832}
1833
Mark Brown79fb9382009-08-21 16:38:13 +01001834#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001835static ssize_t dapm_widget_power_read_file(struct file *file,
1836 char __user *user_buf,
1837 size_t count, loff_t *ppos)
1838{
1839 struct snd_soc_dapm_widget *w = file->private_data;
1840 char *buf;
1841 int in, out;
1842 ssize_t ret;
1843 struct snd_soc_dapm_path *p = NULL;
1844
1845 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1846 if (!buf)
1847 return -ENOMEM;
1848
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001849 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
1850 if (w->is_supply) {
1851 in = 0;
1852 out = 0;
1853 } else {
1854 in = is_connected_input_ep(w, NULL);
1855 out = is_connected_output_ep(w, NULL);
1856 }
Mark Brown79fb9382009-08-21 16:38:13 +01001857
Mark Brownf13ebad2012-03-03 18:01:01 +00001858 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1859 w->name, w->power ? "On" : "Off",
1860 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001861
Mark Brownd033c362009-12-04 15:25:56 +00001862 if (w->reg >= 0)
1863 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001864 " - R%d(0x%x) mask 0x%x",
1865 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00001866
1867 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1868
Mark Brown3eef08b2009-09-14 16:49:00 +01001869 if (w->sname)
1870 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1871 w->sname,
1872 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001873
1874 list_for_each_entry(p, &w->sources, list_sink) {
Takashi Iwaiff186202013-10-28 14:21:49 +01001875 if (p->connected && !p->connected(w, p->source))
Mark Brown215edda2009-09-08 18:59:05 +01001876 continue;
1877
Mark Brown79fb9382009-08-21 16:38:13 +01001878 if (p->connect)
1879 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001880 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001881 p->name ? p->name : "static",
1882 p->source->name);
1883 }
1884 list_for_each_entry(p, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001885 if (p->connected && !p->connected(w, p->sink))
1886 continue;
1887
Mark Brown79fb9382009-08-21 16:38:13 +01001888 if (p->connect)
1889 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001890 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001891 p->name ? p->name : "static",
1892 p->sink->name);
1893 }
1894
1895 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1896
1897 kfree(buf);
1898 return ret;
1899}
1900
1901static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001902 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01001903 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001904 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001905};
1906
Mark Brownef49e4f2011-04-04 20:48:13 +09001907static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1908 size_t count, loff_t *ppos)
1909{
1910 struct snd_soc_dapm_context *dapm = file->private_data;
1911 char *level;
1912
1913 switch (dapm->bias_level) {
1914 case SND_SOC_BIAS_ON:
1915 level = "On\n";
1916 break;
1917 case SND_SOC_BIAS_PREPARE:
1918 level = "Prepare\n";
1919 break;
1920 case SND_SOC_BIAS_STANDBY:
1921 level = "Standby\n";
1922 break;
1923 case SND_SOC_BIAS_OFF:
1924 level = "Off\n";
1925 break;
1926 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001927 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09001928 level = "Unknown\n";
1929 break;
1930 }
1931
1932 return simple_read_from_buffer(user_buf, count, ppos, level,
1933 strlen(level));
1934}
1935
1936static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001937 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09001938 .read = dapm_bias_read_file,
1939 .llseek = default_llseek,
1940};
1941
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001942void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1943 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001944{
Mark Brown79fb9382009-08-21 16:38:13 +01001945 struct dentry *d;
1946
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02001947 if (!parent)
1948 return;
1949
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001950 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
1951
1952 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00001953 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001954 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001955 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001956 }
Mark Brown79fb9382009-08-21 16:38:13 +01001957
Mark Brownef49e4f2011-04-04 20:48:13 +09001958 d = debugfs_create_file("bias_level", 0444,
1959 dapm->debugfs_dapm, dapm,
1960 &dapm_bias_fops);
1961 if (!d)
1962 dev_warn(dapm->dev,
1963 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001964}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001965
1966static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1967{
1968 struct snd_soc_dapm_context *dapm = w->dapm;
1969 struct dentry *d;
1970
1971 if (!dapm->debugfs_dapm || !w->name)
1972 return;
1973
1974 d = debugfs_create_file(w->name, 0444,
1975 dapm->debugfs_dapm, w,
1976 &dapm_widget_power_fops);
1977 if (!d)
1978 dev_warn(w->dapm->dev,
1979 "ASoC: Failed to create %s debugfs file\n",
1980 w->name);
1981}
1982
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001983static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1984{
1985 debugfs_remove_recursive(dapm->debugfs_dapm);
1986}
1987
Mark Brown79fb9382009-08-21 16:38:13 +01001988#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001989void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1990 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001991{
1992}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001993
1994static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1995{
1996}
1997
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001998static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1999{
2000}
2001
Mark Brown79fb9382009-08-21 16:38:13 +01002002#endif
2003
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002004/*
2005 * soc_dapm_connect_path() - Connects or disconnects a path
2006 * @path: The path to update
2007 * @connect: The new connect state of the path. True if the path is connected,
2008 * false if it is disconneted.
2009 * @reason: The reason why the path changed (for debugging only)
2010 */
2011static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2012 bool connect, const char *reason)
2013{
2014 if (path->connect == connect)
2015 return;
2016
2017 path->connect = connect;
2018 dapm_mark_dirty(path->source, reason);
2019 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002020 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002021}
2022
Richard Purdie2b97eab2006-10-06 18:32:18 +02002023/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002024static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002025 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002026{
2027 struct snd_soc_dapm_path *path;
2028 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002029 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002030
Mark Brownf9fa2b12014-03-06 16:49:11 +08002031 lockdep_assert_held(&card->dapm_mutex);
2032
Richard Purdie2b97eab2006-10-06 18:32:18 +02002033 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002034 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002035 found = 1;
2036 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002037 if (!(strcmp(path->name, e->texts[mux])))
2038 connect = true;
2039 else
2040 connect = false;
2041
2042 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002043 }
2044
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002045 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002046 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002047
Liam Girdwood618dae12012-04-25 12:12:51 +01002048 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002049}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002050
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002051int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002052 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2053 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002054{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002055 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002056 int ret;
2057
Liam Girdwood3cd04342012-03-09 12:02:08 +00002058 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002059 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002060 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002061 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002062 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002063 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002064 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002065 return ret;
2066}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002067EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002068
Milan plzik1b075e32008-01-10 14:39:46 +01002069/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002070static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Mark Brown283375c2009-12-07 18:09:03 +00002071 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002072{
2073 struct snd_soc_dapm_path *path;
2074 int found = 0;
2075
Mark Brownf9fa2b12014-03-06 16:49:11 +08002076 lockdep_assert_held(&card->dapm_mutex);
2077
Richard Purdie2b97eab2006-10-06 18:32:18 +02002078 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002079 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002080 found = 1;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002081 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002082 }
2083
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002084 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002085 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002086
Liam Girdwood618dae12012-04-25 12:12:51 +01002087 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002088}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002089
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002090int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002091 struct snd_kcontrol *kcontrol, int connect,
2092 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002093{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002094 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002095 int ret;
2096
Liam Girdwood3cd04342012-03-09 12:02:08 +00002097 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002098 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002099 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002100 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002101 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002102 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002103 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002104 return ret;
2105}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002106EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002107
Benoit Cousson44ba2642014-07-08 23:19:36 +02002108static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002109{
Richard Purdie2b97eab2006-10-06 18:32:18 +02002110 struct snd_soc_dapm_widget *w;
2111 int count = 0;
2112 char *state = "not set";
2113
Lars-Peter Clausen00200102014-07-17 22:01:07 +02002114 list_for_each_entry(w, &codec->component.card->widgets, list) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002115 if (w->dapm != &codec->dapm)
2116 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002117
2118 /* only display widgets that burnm power */
2119 switch (w->id) {
2120 case snd_soc_dapm_hp:
2121 case snd_soc_dapm_mic:
2122 case snd_soc_dapm_spk:
2123 case snd_soc_dapm_line:
2124 case snd_soc_dapm_micbias:
2125 case snd_soc_dapm_dac:
2126 case snd_soc_dapm_adc:
2127 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002128 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002129 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002130 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002131 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002132 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002133 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002134 if (w->name)
2135 count += sprintf(buf + count, "%s: %s\n",
2136 w->name, w->power ? "On":"Off");
2137 break;
2138 default:
2139 break;
2140 }
2141 }
2142
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002143 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02002144 case SND_SOC_BIAS_ON:
2145 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002146 break;
Mark Brown0be98982008-05-19 12:31:28 +02002147 case SND_SOC_BIAS_PREPARE:
2148 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002149 break;
Mark Brown0be98982008-05-19 12:31:28 +02002150 case SND_SOC_BIAS_STANDBY:
2151 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002152 break;
Mark Brown0be98982008-05-19 12:31:28 +02002153 case SND_SOC_BIAS_OFF:
2154 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002155 break;
2156 }
2157 count += sprintf(buf + count, "PM State: %s\n", state);
2158
2159 return count;
2160}
2161
Benoit Cousson44ba2642014-07-08 23:19:36 +02002162/* show dapm widget status in sys fs */
2163static ssize_t dapm_widget_show(struct device *dev,
2164 struct device_attribute *attr, char *buf)
2165{
2166 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2167 int i, count = 0;
2168
2169 for (i = 0; i < rtd->num_codecs; i++) {
2170 struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
2171 count += dapm_widget_show_codec(codec, buf + count);
2172 }
2173
2174 return count;
2175}
2176
Richard Purdie2b97eab2006-10-06 18:32:18 +02002177static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2178
Takashi Iwaid29697d2015-01-30 20:16:37 +01002179struct attribute *soc_dapm_dev_attrs[] = {
2180 &dev_attr_dapm_widget.attr,
2181 NULL
2182};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002183
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002184static void dapm_free_path(struct snd_soc_dapm_path *path)
2185{
2186 list_del(&path->list_sink);
2187 list_del(&path->list_source);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002188 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002189 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002190 kfree(path);
2191}
2192
Richard Purdie2b97eab2006-10-06 18:32:18 +02002193/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002194static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002195{
2196 struct snd_soc_dapm_widget *w, *next_w;
2197 struct snd_soc_dapm_path *p, *next_p;
2198
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002199 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2200 if (w->dapm != dapm)
2201 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002202 list_del(&w->list);
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002203 /*
2204 * remove source and sink paths associated to this widget.
2205 * While removing the path, remove reference to it from both
2206 * source and sink widgets so that path is removed only once.
2207 */
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002208 list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
2209 dapm_free_path(p);
2210
2211 list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
2212 dapm_free_path(p);
2213
Stephen Warrenfad59882011-04-28 17:37:59 -06002214 kfree(w->kcontrols);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002215 kfree(w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002216 kfree(w);
2217 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002218}
2219
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002220static struct snd_soc_dapm_widget *dapm_find_widget(
2221 struct snd_soc_dapm_context *dapm, const char *pin,
2222 bool search_other_contexts)
2223{
2224 struct snd_soc_dapm_widget *w;
2225 struct snd_soc_dapm_widget *fallback = NULL;
2226
2227 list_for_each_entry(w, &dapm->card->widgets, list) {
2228 if (!strcmp(w->name, pin)) {
2229 if (w->dapm == dapm)
2230 return w;
2231 else
2232 fallback = w;
2233 }
2234 }
2235
2236 if (search_other_contexts)
2237 return fallback;
2238
2239 return NULL;
2240}
2241
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002242static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002243 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002244{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002245 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002246
Mark Brownf9fa2b12014-03-06 16:49:11 +08002247 dapm_assert_locked(dapm);
2248
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002249 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002250 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002251 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002252 }
2253
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002254 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002255 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002256 dapm_widget_invalidate_input_paths(w);
2257 dapm_widget_invalidate_output_paths(w);
2258 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002259
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002260 w->connected = status;
2261 if (status == 0)
2262 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002263
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002264 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002265}
2266
Richard Purdie2b97eab2006-10-06 18:32:18 +02002267/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002268 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2269 * @dapm: DAPM context
2270 *
2271 * Walks all dapm audio paths and powers widgets according to their
2272 * stream or path usage.
2273 *
2274 * Requires external locking.
2275 *
2276 * Returns 0 for success.
2277 */
2278int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2279{
2280 /*
2281 * Suppress early reports (eg, jacks syncing their state) to avoid
2282 * silly DAPM runs during card startup.
2283 */
2284 if (!dapm->card || !dapm->card->instantiated)
2285 return 0;
2286
2287 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2288}
2289EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2290
2291/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002292 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002293 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002294 *
2295 * Walks all dapm audio paths and powers widgets according to their
2296 * stream or path usage.
2297 *
2298 * Returns 0 for success.
2299 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002300int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002301{
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002302 int ret;
2303
Liam Girdwood3cd04342012-03-09 12:02:08 +00002304 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002305 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002306 mutex_unlock(&dapm->card->dapm_mutex);
2307 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002308}
Liam Girdwooda5302182008-07-07 13:35:17 +01002309EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002310
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002311/*
2312 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2313 * @w: The widget for which to update the flags
2314 *
2315 * Some widgets have a dynamic category which depends on which neighbors they
2316 * are connected to. This function update the category for these widgets.
2317 *
2318 * This function must be called whenever a path is added or removed to a widget.
2319 */
2320static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2321{
2322 struct snd_soc_dapm_path *p;
2323
2324 switch (w->id) {
2325 case snd_soc_dapm_input:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002326 /* On a fully routed card a input is never a source */
2327 if (w->dapm->card->fully_routed)
2328 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002329 w->is_source = 1;
2330 list_for_each_entry(p, &w->sources, list_sink) {
2331 if (p->source->id == snd_soc_dapm_micbias ||
2332 p->source->id == snd_soc_dapm_mic ||
2333 p->source->id == snd_soc_dapm_line ||
2334 p->source->id == snd_soc_dapm_output) {
2335 w->is_source = 0;
2336 break;
2337 }
2338 }
2339 break;
2340 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002341 /* On a fully routed card a output is never a sink */
2342 if (w->dapm->card->fully_routed)
2343 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002344 w->is_sink = 1;
2345 list_for_each_entry(p, &w->sinks, list_source) {
2346 if (p->sink->id == snd_soc_dapm_spk ||
2347 p->sink->id == snd_soc_dapm_hp ||
2348 p->sink->id == snd_soc_dapm_line ||
2349 p->sink->id == snd_soc_dapm_input) {
2350 w->is_sink = 0;
2351 break;
2352 }
2353 }
2354 break;
2355 case snd_soc_dapm_line:
2356 w->is_sink = !list_empty(&w->sources);
2357 w->is_source = !list_empty(&w->sinks);
2358 break;
2359 default:
2360 break;
2361 }
2362}
2363
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002364static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2365 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2366 const char *control,
2367 int (*connected)(struct snd_soc_dapm_widget *source,
2368 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002369{
2370 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002371 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002372
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002373 if (wsink->is_supply && !wsource->is_supply) {
2374 dev_err(dapm->dev,
2375 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2376 wsource->name, wsink->name);
2377 return -EINVAL;
2378 }
2379
2380 if (connected && !wsource->is_supply) {
2381 dev_err(dapm->dev,
2382 "connected() callback only supported for supply widgets (%s -> %s)\n",
2383 wsource->name, wsink->name);
2384 return -EINVAL;
2385 }
2386
2387 if (wsource->is_supply && control) {
2388 dev_err(dapm->dev,
2389 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2390 wsource->name, control, wsink->name);
2391 return -EINVAL;
2392 }
2393
Richard Purdie2b97eab2006-10-06 18:32:18 +02002394 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2395 if (!path)
2396 return -ENOMEM;
2397
2398 path->source = wsource;
2399 path->sink = wsink;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002400 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002401 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002402 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002403 INIT_LIST_HEAD(&path->list_source);
2404 INIT_LIST_HEAD(&path->list_sink);
2405
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002406 if (wsource->is_supply || wsink->is_supply)
2407 path->is_supply = 1;
2408
Richard Purdie2b97eab2006-10-06 18:32:18 +02002409 /* connect static paths */
2410 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002411 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002412 } else {
2413 /* connect dynamic paths */
2414 switch (wsink->id) {
2415 case snd_soc_dapm_mux:
2416 ret = dapm_connect_mux(dapm, path, control);
2417 if (ret != 0)
2418 goto err;
2419 break;
2420 case snd_soc_dapm_switch:
2421 case snd_soc_dapm_mixer:
2422 case snd_soc_dapm_mixer_named_ctl:
2423 ret = dapm_connect_mixer(dapm, path, control);
2424 if (ret != 0)
2425 goto err;
2426 break;
2427 default:
2428 dev_err(dapm->dev,
2429 "Control not supported for path %s -> [%s] -> %s\n",
2430 wsource->name, control, wsink->name);
2431 ret = -EINVAL;
2432 goto err;
2433 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002434 }
2435
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002436 list_add(&path->list, &dapm->card->paths);
2437 list_add(&path->list_sink, &wsink->sources);
2438 list_add(&path->list_source, &wsource->sinks);
2439
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002440 dapm_update_widget_flags(wsource);
2441 dapm_update_widget_flags(wsink);
2442
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002443 dapm_mark_dirty(wsource, "Route added");
2444 dapm_mark_dirty(wsink, "Route added");
Mark Brownfabd0382012-07-05 17:20:06 +01002445
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002446 if (dapm->card->instantiated && path->connect)
2447 dapm_path_invalidate(path);
2448
Richard Purdie2b97eab2006-10-06 18:32:18 +02002449 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002450err:
2451 kfree(path);
2452 return ret;
2453}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002454
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002455static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002456 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002457{
2458 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2459 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2460 const char *sink;
2461 const char *source;
2462 char prefixed_sink[80];
2463 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002464 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002465 int ret;
2466
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002467 prefix = soc_dapm_prefix(dapm);
2468 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002469 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002470 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002471 sink = prefixed_sink;
2472 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002473 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002474 source = prefixed_source;
2475 } else {
2476 sink = route->sink;
2477 source = route->source;
2478 }
2479
2480 /*
2481 * find src and dest widgets over all widgets but favor a widget from
2482 * current DAPM context
2483 */
2484 list_for_each_entry(w, &dapm->card->widgets, list) {
2485 if (!wsink && !(strcmp(w->name, sink))) {
2486 wtsink = w;
2487 if (w->dapm == dapm)
2488 wsink = w;
2489 continue;
2490 }
2491 if (!wsource && !(strcmp(w->name, source))) {
2492 wtsource = w;
2493 if (w->dapm == dapm)
2494 wsource = w;
2495 }
2496 }
2497 /* use widget from another DAPM context if not found from this */
2498 if (!wsink)
2499 wsink = wtsink;
2500 if (!wsource)
2501 wsource = wtsource;
2502
2503 if (wsource == NULL) {
2504 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2505 route->source);
2506 return -ENODEV;
2507 }
2508 if (wsink == NULL) {
2509 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2510 route->sink);
2511 return -ENODEV;
2512 }
2513
2514 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2515 route->connected);
2516 if (ret)
2517 goto err;
2518
2519 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002520err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002521 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002522 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002523 return ret;
2524}
Mark Brown105f1c22008-05-13 14:52:19 +02002525
Mark Brownefcc3c62012-07-05 17:24:19 +01002526static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2527 const struct snd_soc_dapm_route *route)
2528{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002529 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002530 struct snd_soc_dapm_path *path, *p;
2531 const char *sink;
2532 const char *source;
2533 char prefixed_sink[80];
2534 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002535 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002536
2537 if (route->control) {
2538 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002539 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002540 return -EINVAL;
2541 }
2542
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002543 prefix = soc_dapm_prefix(dapm);
2544 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002545 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002546 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002547 sink = prefixed_sink;
2548 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002549 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002550 source = prefixed_source;
2551 } else {
2552 sink = route->sink;
2553 source = route->source;
2554 }
2555
2556 path = NULL;
2557 list_for_each_entry(p, &dapm->card->paths, list) {
2558 if (strcmp(p->source->name, source) != 0)
2559 continue;
2560 if (strcmp(p->sink->name, sink) != 0)
2561 continue;
2562 path = p;
2563 break;
2564 }
2565
2566 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002567 wsource = path->source;
2568 wsink = path->sink;
2569
2570 dapm_mark_dirty(wsource, "Route removed");
2571 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002572 if (path->connect)
2573 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002574
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002575 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002576
2577 /* Update any path related flags */
2578 dapm_update_widget_flags(wsource);
2579 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002580 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002581 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002582 source, sink);
2583 }
2584
2585 return 0;
2586}
2587
Mark Brown105f1c22008-05-13 14:52:19 +02002588/**
Mark Brown105f1c22008-05-13 14:52:19 +02002589 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002590 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002591 * @route: audio routes
2592 * @num: number of routes
2593 *
2594 * Connects 2 dapm widgets together via a named audio path. The sink is
2595 * the widget receiving the audio signal, whilst the source is the sender
2596 * of the audio signal.
2597 *
2598 * Returns 0 for success else error. On error all resources can be freed
2599 * with a call to snd_soc_card_free().
2600 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002601int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002602 const struct snd_soc_dapm_route *route, int num)
2603{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002604 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002605
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002606 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002607 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002608 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002609 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002610 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2611 route->source,
2612 route->control ? route->control : "direct",
2613 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002614 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002615 }
2616 route++;
2617 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002618 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002619
Dan Carpenter60884c22012-04-13 22:25:43 +03002620 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002621}
2622EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2623
Mark Brownefcc3c62012-07-05 17:24:19 +01002624/**
2625 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2626 * @dapm: DAPM context
2627 * @route: audio routes
2628 * @num: number of routes
2629 *
2630 * Removes routes from the DAPM context.
2631 */
2632int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2633 const struct snd_soc_dapm_route *route, int num)
2634{
2635 int i, ret = 0;
2636
2637 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2638 for (i = 0; i < num; i++) {
2639 snd_soc_dapm_del_route(dapm, route);
2640 route++;
2641 }
2642 mutex_unlock(&dapm->card->dapm_mutex);
2643
2644 return ret;
2645}
2646EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2647
Mark Brownbf3a9e12011-06-13 16:42:29 +01002648static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2649 const struct snd_soc_dapm_route *route)
2650{
2651 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2652 route->source,
2653 true);
2654 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2655 route->sink,
2656 true);
2657 struct snd_soc_dapm_path *path;
2658 int count = 0;
2659
2660 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002661 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002662 route->source);
2663 return -ENODEV;
2664 }
2665
2666 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002667 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002668 route->sink);
2669 return -ENODEV;
2670 }
2671
2672 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002673 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002674 route->source, route->sink);
2675
2676 list_for_each_entry(path, &source->sinks, list_source) {
2677 if (path->sink == sink) {
2678 path->weak = 1;
2679 count++;
2680 }
2681 }
2682
2683 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002684 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002685 route->source, route->sink);
2686 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002687 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002688 count, route->source, route->sink);
2689
2690 return 0;
2691}
2692
2693/**
2694 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2695 * @dapm: DAPM context
2696 * @route: audio routes
2697 * @num: number of routes
2698 *
2699 * Mark existing routes matching those specified in the passed array
2700 * as being weak, meaning that they are ignored for the purpose of
2701 * power decisions. The main intended use case is for sidetone paths
2702 * which couple audio between other independent paths if they are both
2703 * active in order to make the combination work better at the user
2704 * level but which aren't intended to be "used".
2705 *
2706 * Note that CODEC drivers should not use this as sidetone type paths
2707 * can frequently also be used as bypass paths.
2708 */
2709int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2710 const struct snd_soc_dapm_route *route, int num)
2711{
2712 int i, err;
2713 int ret = 0;
2714
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002715 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002716 for (i = 0; i < num; i++) {
2717 err = snd_soc_dapm_weak_route(dapm, route);
2718 if (err)
2719 ret = err;
2720 route++;
2721 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002722 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002723
2724 return ret;
2725}
2726EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2727
Mark Brown105f1c22008-05-13 14:52:19 +02002728/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002729 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002730 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002731 *
2732 * Checks the codec for any new dapm widgets and creates them if found.
2733 *
2734 * Returns 0 for success.
2735 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02002736int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002737{
2738 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002739 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002740
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002741 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002742
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002743 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002744 {
2745 if (w->new)
2746 continue;
2747
Stephen Warrenfad59882011-04-28 17:37:59 -06002748 if (w->num_kcontrols) {
2749 w->kcontrols = kzalloc(w->num_kcontrols *
2750 sizeof(struct snd_kcontrol *),
2751 GFP_KERNEL);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002752 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002753 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002754 return -ENOMEM;
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002755 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002756 }
2757
Richard Purdie2b97eab2006-10-06 18:32:18 +02002758 switch(w->id) {
2759 case snd_soc_dapm_switch:
2760 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002761 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002762 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002763 break;
2764 case snd_soc_dapm_mux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002765 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002766 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002767 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002768 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002769 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002770 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00002771 case snd_soc_dapm_dai_link:
2772 dapm_new_dai_link(w);
2773 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002774 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002775 break;
2776 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002777
2778 /* Read the initial power state from the device */
2779 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002780 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08002781 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002782 val &= w->mask;
2783 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00002784 w->power = 1;
2785 }
2786
Richard Purdie2b97eab2006-10-06 18:32:18 +02002787 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002788
Mark Brown7508b122011-10-05 12:09:12 +01002789 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002790 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002791 }
2792
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002793 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2794 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002795 return 0;
2796}
2797EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2798
2799/**
2800 * snd_soc_dapm_get_volsw - dapm mixer get callback
2801 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002802 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002803 *
2804 * Callback to get the value of a dapm mixer control.
2805 *
2806 * Returns 0 for success.
2807 */
2808int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2809 struct snd_ctl_elem_value *ucontrol)
2810{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002811 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2812 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002813 struct soc_mixer_control *mc =
2814 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002815 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002816 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002817 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002818 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002819 unsigned int invert = mc->invert;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002820 unsigned int val;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002821 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002822
2823 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002824 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002825 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002826 kcontrol->id.name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002827
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002828 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002829 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
2830 ret = soc_dapm_read(dapm, reg, &val);
2831 val = (val >> shift) & mask;
2832 } else {
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002833 val = dapm_kcontrol_get_value(kcontrol);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002834 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002835 mutex_unlock(&card->dapm_mutex);
2836
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002837 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002838 ucontrol->value.integer.value[0] = max - val;
2839 else
2840 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002841
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002842 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002843}
2844EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
2845
2846/**
2847 * snd_soc_dapm_put_volsw - dapm mixer set callback
2848 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002849 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002850 *
2851 * Callback to set the value of a dapm mixer control.
2852 *
2853 * Returns 0 for success.
2854 */
2855int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2856 struct snd_ctl_elem_value *ucontrol)
2857{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002858 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2859 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002860 struct soc_mixer_control *mc =
2861 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002862 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002863 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002864 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002865 unsigned int mask = (1 << fls(max)) - 1;
2866 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002867 unsigned int val;
Jarkko Nikula18626c72014-06-09 14:20:29 +03002868 int connect, change, reg_change = 0;
Mark Brown97404f22010-12-14 16:13:57 +00002869 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08002870 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002871
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002872 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002873 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002874 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002875 kcontrol->id.name);
2876
Richard Purdie2b97eab2006-10-06 18:32:18 +02002877 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02002878 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002879
2880 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002881 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002882
Liam Girdwood3cd04342012-03-09 12:02:08 +00002883 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002884
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002885 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown283375c2009-12-07 18:09:03 +00002886
Jarkko Nikula18626c72014-06-09 14:20:29 +03002887 if (reg != SND_SOC_NOPM) {
2888 mask = mask << shift;
2889 val = val << shift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02002890
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002891 reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
Jarkko Nikula18626c72014-06-09 14:20:29 +03002892 }
2893
2894 if (change || reg_change) {
2895 if (reg_change) {
2896 update.kcontrol = kcontrol;
2897 update.reg = reg;
2898 update.mask = mask;
2899 update.val = val;
2900 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002901 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03002902 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00002903
Nenghua Cao52765972013-12-13 20:13:49 +08002904 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Mark Brown97404f22010-12-14 16:13:57 +00002905
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002906 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00002907 }
2908
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002909 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08002910
2911 if (ret > 0)
2912 soc_dpcm_runtime_update(card);
2913
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02002914 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002915}
2916EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
2917
2918/**
2919 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
2920 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002921 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002922 *
2923 * Callback to get the value of a dapm enumerated double mixer control.
2924 *
2925 * Returns 0 for success.
2926 */
2927int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
2928 struct snd_ctl_elem_value *ucontrol)
2929{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002930 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002931 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002932 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002933
Geert Uytterhoeven69128312014-08-08 17:29:35 +02002934 if (e->reg != SND_SOC_NOPM) {
2935 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
2936 if (ret)
2937 return ret;
2938 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002939 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02002940 }
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002941
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002942 val = (reg_val >> e->shift_l) & e->mask;
2943 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
2944 if (e->shift_l != e->shift_r) {
2945 val = (reg_val >> e->shift_r) & e->mask;
2946 val = snd_soc_enum_val_to_item(e, val);
2947 ucontrol->value.enumerated.item[1] = val;
2948 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002949
Geert Uytterhoeven69128312014-08-08 17:29:35 +02002950 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002951}
2952EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
2953
2954/**
2955 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
2956 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002957 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002958 *
2959 * Callback to set the value of a dapm enumerated double mixer control.
2960 *
2961 * Returns 0 for success.
2962 */
2963int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
2964 struct snd_ctl_elem_value *ucontrol)
2965{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002966 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2967 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002968 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002969 unsigned int *item = ucontrol->value.enumerated.item;
2970 unsigned int val, change;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02002971 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00002972 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08002973 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002974
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002975 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002976 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002977
2978 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02002979 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002980 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002981 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002982 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002983 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02002984 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002985 }
2986
Liam Girdwood3cd04342012-03-09 12:02:08 +00002987 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002988
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002989 if (e->reg != SND_SOC_NOPM)
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002990 change = soc_dapm_test_bits(dapm, e->reg, mask, val);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002991 else
2992 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00002993
Richard Purdie2b97eab2006-10-06 18:32:18 +02002994 if (change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002995 if (e->reg != SND_SOC_NOPM) {
2996 update.kcontrol = kcontrol;
2997 update.reg = e->reg;
2998 update.mask = mask;
2999 update.val = val;
3000 card->update = &update;
3001 }
Mark Brown3a655772009-10-05 17:23:30 +01003002
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003003 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003004
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003005 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003006 }
3007
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003008 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003009
3010 if (ret > 0)
3011 soc_dpcm_runtime_update(card);
3012
Mark Brown97404f22010-12-14 16:13:57 +00003013 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003014}
3015EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3016
3017/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003018 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3019 *
3020 * @kcontrol: mixer control
3021 * @uinfo: control element information
3022 *
3023 * Callback to provide information about a pin switch control.
3024 */
3025int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3026 struct snd_ctl_elem_info *uinfo)
3027{
3028 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3029 uinfo->count = 1;
3030 uinfo->value.integer.min = 0;
3031 uinfo->value.integer.max = 1;
3032
3033 return 0;
3034}
3035EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3036
3037/**
3038 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3039 *
3040 * @kcontrol: mixer control
3041 * @ucontrol: Value
3042 */
3043int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3044 struct snd_ctl_elem_value *ucontrol)
3045{
Mark Brown48a8c392012-02-14 17:11:15 -08003046 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003047 const char *pin = (const char *)kcontrol->private_value;
3048
Liam Girdwood3cd04342012-03-09 12:02:08 +00003049 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003050
3051 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003052 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003053
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003054 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003055
3056 return 0;
3057}
3058EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3059
3060/**
3061 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3062 *
3063 * @kcontrol: mixer control
3064 * @ucontrol: Value
3065 */
3066int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3067 struct snd_ctl_elem_value *ucontrol)
3068{
Mark Brown48a8c392012-02-14 17:11:15 -08003069 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003070 const char *pin = (const char *)kcontrol->private_value;
3071
Mark Brown8b37dbd2009-02-28 21:14:20 +00003072 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003073 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003074 else
Mark Brown48a8c392012-02-14 17:11:15 -08003075 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003076
Mark Brown48a8c392012-02-14 17:11:15 -08003077 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003078 return 0;
3079}
3080EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3081
Mark Brown5ba06fc2012-02-16 11:07:13 -08003082static struct snd_soc_dapm_widget *
3083snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3084 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003085{
3086 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003087 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003088 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003089
3090 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003091 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003092
Mark Brown62ea8742012-01-21 21:14:48 +00003093 switch (w->id) {
3094 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003095 w->regulator = devm_regulator_get(dapm->dev, w->name);
3096 if (IS_ERR(w->regulator)) {
3097 ret = PTR_ERR(w->regulator);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003098 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003099 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003100 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003101 }
Mark Brown8784c772013-01-10 19:33:47 +00003102
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003103 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003104 ret = regulator_allow_bypass(w->regulator, true);
3105 if (ret != 0)
3106 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003107 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003108 w->name, ret);
3109 }
Mark Brown62ea8742012-01-21 21:14:48 +00003110 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003111 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003112#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003113 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003114 if (IS_ERR(w->clk)) {
3115 ret = PTR_ERR(w->clk);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003116 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003117 w->name, ret);
3118 return NULL;
3119 }
Mark Brownec029952012-06-04 08:16:20 +01003120#else
3121 return NULL;
3122#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003123 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003124 default:
3125 break;
3126 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003127
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003128 prefix = soc_dapm_prefix(dapm);
3129 if (prefix)
3130 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausen2b581072013-05-14 11:05:32 +02003131 else
3132 w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
3133
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003134 if (w->name == NULL) {
3135 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003136 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003137 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003138
Mark Brown7ca3a182011-10-08 14:04:50 +01003139 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003140 case snd_soc_dapm_mic:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003141 w->is_source = 1;
3142 w->power_check = dapm_generic_check_power;
3143 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003144 case snd_soc_dapm_input:
3145 if (!dapm->card->fully_routed)
3146 w->is_source = 1;
3147 w->power_check = dapm_generic_check_power;
3148 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003149 case snd_soc_dapm_spk:
3150 case snd_soc_dapm_hp:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003151 w->is_sink = 1;
3152 w->power_check = dapm_generic_check_power;
3153 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003154 case snd_soc_dapm_output:
3155 if (!dapm->card->fully_routed)
3156 w->is_sink = 1;
3157 w->power_check = dapm_generic_check_power;
3158 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003159 case snd_soc_dapm_vmid:
3160 case snd_soc_dapm_siggen:
3161 w->is_source = 1;
3162 w->power_check = dapm_always_on_check_power;
3163 break;
3164 case snd_soc_dapm_mux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003165 case snd_soc_dapm_switch:
3166 case snd_soc_dapm_mixer:
3167 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003168 case snd_soc_dapm_adc:
3169 case snd_soc_dapm_aif_out:
3170 case snd_soc_dapm_dac:
3171 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003172 case snd_soc_dapm_pga:
3173 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003174 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003175 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003176 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003177 case snd_soc_dapm_dai_out:
3178 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003179 w->power_check = dapm_generic_check_power;
3180 break;
3181 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003182 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003183 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003184 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003185 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003186 w->power_check = dapm_supply_check_power;
3187 break;
3188 default:
3189 w->power_check = dapm_always_on_check_power;
3190 break;
3191 }
3192
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003193 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003194 INIT_LIST_HEAD(&w->sources);
3195 INIT_LIST_HEAD(&w->sinks);
3196 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003197 INIT_LIST_HEAD(&w->dirty);
Jarkko Nikula97c866d2010-12-14 12:18:31 +02003198 list_add(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003199
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003200 w->inputs = -1;
3201 w->outputs = -1;
3202
Richard Purdie2b97eab2006-10-06 18:32:18 +02003203 /* machine layer set ups unconnected pins and insertions */
3204 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003205 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003206}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003207
3208/**
Mark Brown4ba13272008-05-13 14:51:19 +02003209 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003210 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003211 * @widget: widget array
3212 * @num: number of widgets
3213 *
3214 * Creates new DAPM controls based upon the templates.
3215 *
3216 * Returns 0 for success else error.
3217 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003218int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003219 const struct snd_soc_dapm_widget *widget,
3220 int num)
3221{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003222 struct snd_soc_dapm_widget *w;
3223 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003224 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003225
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003226 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003227 for (i = 0; i < num; i++) {
Mark Brown5ba06fc2012-02-16 11:07:13 -08003228 w = snd_soc_dapm_new_control(dapm, widget);
3229 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003230 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003231 "ASoC: Failed to create DAPM control %s\n",
3232 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003233 ret = -ENOMEM;
3234 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003235 }
Mark Brown4ba13272008-05-13 14:51:19 +02003236 widget++;
3237 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003238 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003239 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003240}
3241EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3242
Mark Brownc74184e2012-04-04 22:12:09 +01003243static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3244 struct snd_kcontrol *kcontrol, int event)
3245{
3246 struct snd_soc_dapm_path *source_p, *sink_p;
3247 struct snd_soc_dai *source, *sink;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003248 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003249 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003250 struct snd_pcm_hw_params *params = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003251 u64 fmt;
3252 int ret;
3253
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003254 if (WARN_ON(!config) ||
3255 WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
3256 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003257
3258 /* We only support a single source and sink, pick the first */
3259 source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
3260 list_sink);
3261 sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
3262 list_source);
3263
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003264 if (WARN_ON(!source_p || !sink_p) ||
3265 WARN_ON(!sink_p->source || !source_p->sink) ||
3266 WARN_ON(!source_p->source || !sink_p->sink))
3267 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003268
3269 source = source_p->source->priv;
3270 sink = sink_p->sink->priv;
3271
3272 /* Be a little careful as we don't want to overflow the mask array */
3273 if (config->formats) {
3274 fmt = ffs(config->formats) - 1;
3275 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003276 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003277 config->formats);
3278 fmt = 0;
3279 }
3280
3281 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003282 params = kzalloc(sizeof(*params), GFP_KERNEL);
3283 if (!params) {
3284 ret = -ENOMEM;
3285 goto out;
3286 }
3287 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003288
Mark Brown9747cec2012-04-26 19:12:21 +01003289 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003290 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003291 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003292 config->rate_max;
3293
Mark Brown9747cec2012-04-26 19:12:21 +01003294 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003295 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003296 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003297 = config->channels_max;
3298
3299 memset(&substream, 0, sizeof(substream));
3300
3301 switch (event) {
3302 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003303 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3304 ret = soc_dai_hw_params(&substream, params, source);
3305 if (ret < 0)
3306 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003307
Benoit Cousson93e69582014-07-08 23:19:38 +02003308 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3309 ret = soc_dai_hw_params(&substream, params, sink);
3310 if (ret < 0)
3311 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003312 break;
3313
3314 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003315 ret = snd_soc_dai_digital_mute(sink, 0,
3316 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003317 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003318 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003319 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003320 break;
3321
3322 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003323 ret = snd_soc_dai_digital_mute(sink, 1,
3324 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003325 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003326 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003327 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003328 break;
3329
3330 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003331 WARN(1, "Unknown event %d\n", event);
Mark Brownc74184e2012-04-04 22:12:09 +01003332 return -EINVAL;
3333 }
3334
Mark Brown9747cec2012-04-26 19:12:21 +01003335out:
3336 kfree(params);
3337 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003338}
3339
Nikesh Oswalc6615082015-02-02 17:06:44 +00003340static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3341 struct snd_ctl_elem_value *ucontrol)
3342{
3343 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3344
3345 ucontrol->value.integer.value[0] = w->params_select;
3346
3347 return 0;
3348}
3349
3350static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3351 struct snd_ctl_elem_value *ucontrol)
3352{
3353 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3354
3355 /* Can't change the config when widget is already powered */
3356 if (w->power)
3357 return -EBUSY;
3358
3359 if (ucontrol->value.integer.value[0] == w->params_select)
3360 return 0;
3361
3362 if (ucontrol->value.integer.value[0] >= w->num_params)
3363 return -EINVAL;
3364
3365 w->params_select = ucontrol->value.integer.value[0];
3366
3367 return 0;
3368}
3369
Mark Brownc74184e2012-04-04 22:12:09 +01003370int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3371 const struct snd_soc_pcm_stream *params,
Nikesh Oswalc6615082015-02-02 17:06:44 +00003372 unsigned int num_params,
Mark Brownc74184e2012-04-04 22:12:09 +01003373 struct snd_soc_dapm_widget *source,
3374 struct snd_soc_dapm_widget *sink)
3375{
Mark Brownc74184e2012-04-04 22:12:09 +01003376 struct snd_soc_dapm_widget template;
3377 struct snd_soc_dapm_widget *w;
Mark Brownc74184e2012-04-04 22:12:09 +01003378 char *link_name;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003379 int ret, count;
3380 unsigned long private_value;
3381 const char **w_param_text;
3382 struct soc_enum w_param_enum[] = {
3383 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3384 };
3385 struct snd_kcontrol_new kcontrol_dai_link[] = {
3386 SOC_ENUM_EXT(NULL, w_param_enum[0],
3387 snd_soc_dapm_dai_link_get,
3388 snd_soc_dapm_dai_link_put),
3389 };
3390 const struct snd_soc_pcm_stream *config = params;
Mark Brownc74184e2012-04-04 22:12:09 +01003391
Nikesh Oswalc6615082015-02-02 17:06:44 +00003392 w_param_text = devm_kcalloc(card->dev, num_params,
3393 sizeof(char *), GFP_KERNEL);
3394 if (!w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003395 return -ENOMEM;
Mark Brownc74184e2012-04-04 22:12:09 +01003396
Charles Keepax46172b62015-03-25 11:22:35 +00003397 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3398 source->name, sink->name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003399 if (!link_name) {
3400 ret = -ENOMEM;
3401 goto outfree_w_param;
3402 }
Mark Brownc74184e2012-04-04 22:12:09 +01003403
Nikesh Oswalc6615082015-02-02 17:06:44 +00003404 for (count = 0 ; count < num_params; count++) {
3405 if (!config->stream_name) {
3406 dev_warn(card->dapm.dev,
3407 "ASoC: anonymous config %d for dai link %s\n",
3408 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003409 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003410 devm_kasprintf(card->dev, GFP_KERNEL,
3411 "Anonymous Configuration %d",
3412 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003413 if (!w_param_text[count]) {
3414 ret = -ENOMEM;
3415 goto outfree_link_name;
3416 }
Nikesh Oswalc6615082015-02-02 17:06:44 +00003417 } else {
3418 w_param_text[count] = devm_kmemdup(card->dev,
3419 config->stream_name,
3420 strlen(config->stream_name) + 1,
3421 GFP_KERNEL);
3422 if (!w_param_text[count]) {
3423 ret = -ENOMEM;
3424 goto outfree_link_name;
3425 }
3426 }
3427 config++;
3428 }
3429 w_param_enum[0].items = num_params;
3430 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003431
3432 memset(&template, 0, sizeof(template));
3433 template.reg = SND_SOC_NOPM;
3434 template.id = snd_soc_dapm_dai_link;
3435 template.name = link_name;
3436 template.event = snd_soc_dai_link_event;
3437 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3438 SND_SOC_DAPM_PRE_PMD;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003439 template.num_kcontrols = 1;
3440 /* duplicate w_param_enum on heap so that memory persists */
3441 private_value =
3442 (unsigned long) devm_kmemdup(card->dev,
3443 (void *)(kcontrol_dai_link[0].private_value),
3444 sizeof(struct soc_enum), GFP_KERNEL);
3445 if (!private_value) {
3446 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3447 link_name);
3448 ret = -ENOMEM;
3449 goto outfree_link_name;
3450 }
3451 kcontrol_dai_link[0].private_value = private_value;
3452 /* duplicate kcontrol_dai_link on heap so that memory persists */
3453 template.kcontrol_news =
3454 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3455 sizeof(struct snd_kcontrol_new),
3456 GFP_KERNEL);
3457 if (!template.kcontrol_news) {
3458 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3459 link_name);
3460 ret = -ENOMEM;
3461 goto outfree_private_value;
3462 }
Mark Brownc74184e2012-04-04 22:12:09 +01003463
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003464 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003465
3466 w = snd_soc_dapm_new_control(&card->dapm, &template);
3467 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003468 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003469 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003470 ret = -ENOMEM;
3471 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003472 }
3473
3474 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003475 w->num_params = num_params;
Mark Brownc74184e2012-04-04 22:12:09 +01003476
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003477 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3478 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003479 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003480 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003481
3482outfree_w:
3483 devm_kfree(card->dev, w);
3484outfree_kcontrol_news:
3485 devm_kfree(card->dev, (void *)template.kcontrol_news);
3486outfree_private_value:
3487 devm_kfree(card->dev, (void *)private_value);
3488outfree_link_name:
3489 devm_kfree(card->dev, link_name);
3490outfree_w_param:
3491 for (count = 0 ; count < num_params; count++)
3492 devm_kfree(card->dev, (void *)w_param_text[count]);
3493 devm_kfree(card->dev, w_param_text);
3494
3495 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003496}
3497
Mark Brown888df392012-02-16 19:37:51 -08003498int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3499 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003500{
Mark Brown888df392012-02-16 19:37:51 -08003501 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003502 struct snd_soc_dapm_widget *w;
3503
Mark Brown888df392012-02-16 19:37:51 -08003504 WARN_ON(dapm->dev != dai->dev);
3505
3506 memset(&template, 0, sizeof(template));
3507 template.reg = SND_SOC_NOPM;
3508
3509 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003510 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003511 template.name = dai->driver->playback.stream_name;
3512 template.sname = dai->driver->playback.stream_name;
3513
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003514 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003515 template.name);
3516
3517 w = snd_soc_dapm_new_control(dapm, &template);
3518 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003519 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003520 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003521 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003522 }
3523
3524 w->priv = dai;
3525 dai->playback_widget = w;
3526 }
3527
3528 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003529 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003530 template.name = dai->driver->capture.stream_name;
3531 template.sname = dai->driver->capture.stream_name;
3532
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003533 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003534 template.name);
3535
3536 w = snd_soc_dapm_new_control(dapm, &template);
3537 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003538 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003539 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003540 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003541 }
3542
3543 w->priv = dai;
3544 dai->capture_widget = w;
3545 }
3546
3547 return 0;
3548}
3549
3550int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3551{
3552 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003553 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08003554 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003555
3556 /* For each DAI widget... */
3557 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003558 switch (dai_w->id) {
3559 case snd_soc_dapm_dai_in:
3560 case snd_soc_dapm_dai_out:
3561 break;
3562 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003563 continue;
Mark Brown46162742013-06-05 19:36:11 +01003564 }
Mark Brown888df392012-02-16 19:37:51 -08003565
3566 dai = dai_w->priv;
3567
3568 /* ...find all widgets with the same stream and link them */
3569 list_for_each_entry(w, &card->widgets, list) {
3570 if (w->dapm != dai_w->dapm)
3571 continue;
3572
Mark Brown46162742013-06-05 19:36:11 +01003573 switch (w->id) {
3574 case snd_soc_dapm_dai_in:
3575 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08003576 continue;
Mark Brown46162742013-06-05 19:36:11 +01003577 default:
3578 break;
3579 }
Mark Brown888df392012-02-16 19:37:51 -08003580
Russell King19c2c5f2013-08-04 20:24:03 +01003581 if (!w->sname || !strstr(w->sname, dai_w->name))
Mark Brown888df392012-02-16 19:37:51 -08003582 continue;
3583
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003584 if (dai_w->id == snd_soc_dapm_dai_in) {
3585 src = dai_w;
3586 sink = w;
3587 } else {
3588 src = w;
3589 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08003590 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003591 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
3592 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003593 }
3594 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003595
Mark Brown888df392012-02-16 19:37:51 -08003596 return 0;
3597}
Liam Girdwood64a648c2011-07-25 11:15:15 +01003598
Benoit Cousson44ba2642014-07-08 23:19:36 +02003599static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
3600 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003601{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003602 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003603 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003604 int i;
3605
Benoit Cousson44ba2642014-07-08 23:19:36 +02003606 for (i = 0; i < rtd->num_codecs; i++) {
3607 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003608
3609 /* there is no point in connecting BE DAI links with dummies */
3610 if (snd_soc_dai_is_dummy(codec_dai) ||
3611 snd_soc_dai_is_dummy(cpu_dai))
3612 continue;
3613
3614 /* connect BE DAI playback if widgets are valid */
3615 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003616 source = cpu_dai->playback_widget;
3617 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003618 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003619 cpu_dai->component->name, source->name,
3620 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003621
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003622 snd_soc_dapm_add_path(&card->dapm, source, sink,
3623 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003624 }
3625
3626 /* connect BE DAI capture if widgets are valid */
3627 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003628 source = codec_dai->capture_widget;
3629 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003630 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003631 codec_dai->component->name, source->name,
3632 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003633
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003634 snd_soc_dapm_add_path(&card->dapm, source, sink,
3635 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003636 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003637 }
3638}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003639
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003640static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3641 int event)
3642{
3643 struct snd_soc_dapm_widget *w;
3644
3645 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3646 w = dai->playback_widget;
3647 else
3648 w = dai->capture_widget;
3649
3650 if (w) {
3651 dapm_mark_dirty(w, "stream event");
3652
3653 switch (event) {
3654 case SND_SOC_DAPM_STREAM_START:
3655 w->active = 1;
3656 break;
3657 case SND_SOC_DAPM_STREAM_STOP:
3658 w->active = 0;
3659 break;
3660 case SND_SOC_DAPM_STREAM_SUSPEND:
3661 case SND_SOC_DAPM_STREAM_RESUME:
3662 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3663 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3664 break;
3665 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003666
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003667 if (w->id == snd_soc_dapm_dai_in) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003668 w->is_source = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003669 dapm_widget_invalidate_input_paths(w);
3670 } else {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003671 w->is_sink = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003672 dapm_widget_invalidate_output_paths(w);
3673 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003674 }
3675}
3676
Benoit Cousson44ba2642014-07-08 23:19:36 +02003677void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3678{
3679 struct snd_soc_pcm_runtime *rtd = card->rtd;
3680 int i;
3681
3682 /* for each BE DAI link... */
3683 for (i = 0; i < card->num_rtd; i++) {
3684 rtd = &card->rtd[i];
3685
3686 /*
3687 * dynamic FE links have no fixed DAI mapping.
3688 * CODEC<->CODEC links have no direct connection.
3689 */
3690 if (rtd->dai_link->dynamic || rtd->dai_link->params)
3691 continue;
3692
3693 dapm_connect_dai_link_widgets(card, rtd);
3694 }
3695}
3696
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003697static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3698 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003699{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003700 int i;
3701
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003702 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02003703 for (i = 0; i < rtd->num_codecs; i++)
3704 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003705
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003706 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003707}
3708
3709/**
3710 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3711 * @rtd: PCM runtime data
3712 * @stream: stream name
3713 * @event: stream event
3714 *
3715 * Sends a stream event to the dapm core. The core then makes any
3716 * necessary widget power changes.
3717 *
3718 * Returns 0 for success else error.
3719 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003720void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3721 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003722{
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003723 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003724
Liam Girdwood3cd04342012-03-09 12:02:08 +00003725 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003726 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003727 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003728}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003729
3730/**
Charles Keepax11391102014-02-18 15:22:14 +00003731 * snd_soc_dapm_enable_pin_unlocked - enable pin.
3732 * @dapm: DAPM context
3733 * @pin: pin name
3734 *
3735 * Enables input/output pin and its parents or children widgets iff there is
3736 * a valid audio route and active audio stream.
3737 *
3738 * Requires external locking.
3739 *
3740 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3741 * do any widget power switching.
3742 */
3743int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3744 const char *pin)
3745{
3746 return snd_soc_dapm_set_pin(dapm, pin, 1);
3747}
3748EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
3749
3750/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003751 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003752 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003753 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02003754 *
Mark Brown74b8f952009-06-06 11:26:15 +01003755 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01003756 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00003757 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003758 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3759 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02003760 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003761int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003762{
Charles Keepax11391102014-02-18 15:22:14 +00003763 int ret;
3764
3765 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3766
3767 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
3768
3769 mutex_unlock(&dapm->card->dapm_mutex);
3770
3771 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003772}
Liam Girdwooda5302182008-07-07 13:35:17 +01003773EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003774
3775/**
Charles Keepax11391102014-02-18 15:22:14 +00003776 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
3777 * @dapm: DAPM context
3778 * @pin: pin name
3779 *
3780 * Enables input/output pin regardless of any other state. This is
3781 * intended for use with microphone bias supplies used in microphone
3782 * jack detection.
3783 *
3784 * Requires external locking.
3785 *
3786 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3787 * do any widget power switching.
3788 */
3789int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3790 const char *pin)
3791{
3792 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
3793
3794 if (!w) {
3795 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
3796 return -EINVAL;
3797 }
3798
3799 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003800 if (!w->connected) {
3801 /*
3802 * w->force does not affect the number of input or output paths,
3803 * so we only have to recheck if w->connected is changed
3804 */
3805 dapm_widget_invalidate_input_paths(w);
3806 dapm_widget_invalidate_output_paths(w);
3807 w->connected = 1;
3808 }
Charles Keepax11391102014-02-18 15:22:14 +00003809 w->force = 1;
3810 dapm_mark_dirty(w, "force enable");
3811
3812 return 0;
3813}
3814EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
3815
3816/**
Mark Brownda341832010-03-15 19:23:37 +00003817 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003818 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00003819 * @pin: pin name
3820 *
3821 * Enables input/output pin regardless of any other state. This is
3822 * intended for use with microphone bias supplies used in microphone
3823 * jack detection.
3824 *
3825 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3826 * do any widget power switching.
3827 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003828int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
3829 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00003830{
Charles Keepax11391102014-02-18 15:22:14 +00003831 int ret;
Mark Brownda341832010-03-15 19:23:37 +00003832
Charles Keepax11391102014-02-18 15:22:14 +00003833 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00003834
Charles Keepax11391102014-02-18 15:22:14 +00003835 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09003836
Charles Keepax11391102014-02-18 15:22:14 +00003837 mutex_unlock(&dapm->card->dapm_mutex);
3838
3839 return ret;
Mark Brownda341832010-03-15 19:23:37 +00003840}
3841EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
3842
3843/**
Charles Keepax11391102014-02-18 15:22:14 +00003844 * snd_soc_dapm_disable_pin_unlocked - disable pin.
3845 * @dapm: DAPM context
3846 * @pin: pin name
3847 *
3848 * Disables input/output pin and its parents or children widgets.
3849 *
3850 * Requires external locking.
3851 *
3852 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3853 * do any widget power switching.
3854 */
3855int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3856 const char *pin)
3857{
3858 return snd_soc_dapm_set_pin(dapm, pin, 0);
3859}
3860EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
3861
3862/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003863 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003864 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003865 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003866 *
Mark Brown74b8f952009-06-06 11:26:15 +01003867 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00003868 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003869 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3870 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003871 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003872int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
3873 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01003874{
Charles Keepax11391102014-02-18 15:22:14 +00003875 int ret;
3876
3877 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3878
3879 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
3880
3881 mutex_unlock(&dapm->card->dapm_mutex);
3882
3883 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01003884}
3885EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
3886
3887/**
Charles Keepax11391102014-02-18 15:22:14 +00003888 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
3889 * @dapm: DAPM context
3890 * @pin: pin name
3891 *
3892 * Marks the specified pin as being not connected, disabling it along
3893 * any parent or child widgets. At present this is identical to
3894 * snd_soc_dapm_disable_pin() but in future it will be extended to do
3895 * additional things such as disabling controls which only affect
3896 * paths through the pin.
3897 *
3898 * Requires external locking.
3899 *
3900 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3901 * do any widget power switching.
3902 */
3903int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
3904 const char *pin)
3905{
3906 return snd_soc_dapm_set_pin(dapm, pin, 0);
3907}
3908EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
3909
3910/**
Mark Brown5817b522008-09-24 11:23:11 +01003911 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003912 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01003913 * @pin: pin name
3914 *
3915 * Marks the specified pin as being not connected, disabling it along
3916 * any parent or child widgets. At present this is identical to
3917 * snd_soc_dapm_disable_pin() but in future it will be extended to do
3918 * additional things such as disabling controls which only affect
3919 * paths through the pin.
3920 *
3921 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3922 * do any widget power switching.
3923 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003924int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01003925{
Charles Keepax11391102014-02-18 15:22:14 +00003926 int ret;
3927
3928 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3929
3930 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
3931
3932 mutex_unlock(&dapm->card->dapm_mutex);
3933
3934 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01003935}
3936EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
3937
3938/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003939 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003940 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003941 * @pin: audio signal pin endpoint (or start point)
3942 *
3943 * Get audio pin status - connected or disconnected.
3944 *
3945 * Returns 1 for connected otherwise 0.
3946 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003947int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
3948 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003949{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003950 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003951
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003952 if (w)
3953 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06003954
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003955 return 0;
3956}
Liam Girdwooda5302182008-07-07 13:35:17 +01003957EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003958
3959/**
Mark Brown1547aba2010-05-07 21:11:40 +01003960 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003961 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01003962 * @pin: audio signal pin endpoint (or start point)
3963 *
3964 * Mark the given endpoint or pin as ignoring suspend. When the
3965 * system is disabled a path between two endpoints flagged as ignoring
3966 * suspend will not be disabled. The path must already be enabled via
3967 * normal means at suspend time, it will not be turned on if it was not
3968 * already enabled.
3969 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003970int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
3971 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01003972{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003973 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01003974
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003975 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003976 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003977 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01003978 }
3979
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003980 w->ignore_suspend = 1;
3981
3982 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01003983}
3984EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
3985
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02003986/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02003987 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03003988 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02003989 *
3990 * Free all dapm widgets and resources.
3991 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003992void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003993{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02003994 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003995 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02003996 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003997}
3998EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
3999
Xiang Xiao57996352014-03-02 00:04:02 +08004000static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004001{
Liam Girdwood01005a72012-07-06 16:57:05 +01004002 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004003 struct snd_soc_dapm_widget *w;
4004 LIST_HEAD(down_list);
4005 int powerdown = 0;
4006
Liam Girdwood01005a72012-07-06 16:57:05 +01004007 mutex_lock(&card->dapm_mutex);
4008
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004009 list_for_each_entry(w, &dapm->card->widgets, list) {
4010 if (w->dapm != dapm)
4011 continue;
Mark Brown51737472009-06-22 13:16:51 +01004012 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004013 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004014 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004015 powerdown = 1;
4016 }
4017 }
4018
4019 /* If there were no widgets to power down we're already in
4020 * standby.
4021 */
4022 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004023 if (dapm->bias_level == SND_SOC_BIAS_ON)
4024 snd_soc_dapm_set_bias_level(dapm,
4025 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004026 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004027 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4028 snd_soc_dapm_set_bias_level(dapm,
4029 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004030 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004031
4032 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004033}
Mark Brown51737472009-06-22 13:16:51 +01004034
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004035/*
4036 * snd_soc_dapm_shutdown - callback for system shutdown
4037 */
4038void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4039{
Xiang Xiao57996352014-03-02 00:04:02 +08004040 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004041
Xiang Xiao57996352014-03-02 00:04:02 +08004042 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004043 if (dapm != &card->dapm) {
4044 soc_dapm_shutdown_dapm(dapm);
4045 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4046 snd_soc_dapm_set_bias_level(dapm,
4047 SND_SOC_BIAS_OFF);
4048 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004049 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004050
4051 soc_dapm_shutdown_dapm(&card->dapm);
4052 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4053 snd_soc_dapm_set_bias_level(&card->dapm,
4054 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004055}
4056
Richard Purdie2b97eab2006-10-06 18:32:18 +02004057/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004058MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004059MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4060MODULE_LICENSE("GPL");