blob: 10fb7087c405e464e1d15d5565e8372e8a9cb66e [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,
Lars-Peter Clausend714f972015-05-01 18:02:43 +020073 [snd_soc_dapm_demux] = 6,
Mark Brown1dd275b2013-10-09 13:56:37 +010074 [snd_soc_dapm_dac] = 7,
75 [snd_soc_dapm_switch] = 8,
76 [snd_soc_dapm_mixer] = 8,
77 [snd_soc_dapm_mixer_named_ctl] = 8,
78 [snd_soc_dapm_pga] = 9,
79 [snd_soc_dapm_adc] = 10,
80 [snd_soc_dapm_out_drv] = 11,
81 [snd_soc_dapm_hp] = 11,
82 [snd_soc_dapm_spk] = 11,
83 [snd_soc_dapm_line] = 11,
84 [snd_soc_dapm_kcontrol] = 12,
85 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020086};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000087
Richard Purdie2b97eab2006-10-06 18:32:18 +020088static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010089 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +020090 [snd_soc_dapm_kcontrol] = 1,
91 [snd_soc_dapm_adc] = 2,
92 [snd_soc_dapm_hp] = 3,
93 [snd_soc_dapm_spk] = 3,
94 [snd_soc_dapm_line] = 3,
95 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +010096 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +020097 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +010098 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +010099 [snd_soc_dapm_mixer] = 5,
100 [snd_soc_dapm_dac] = 6,
101 [snd_soc_dapm_mic] = 7,
102 [snd_soc_dapm_micbias] = 8,
103 [snd_soc_dapm_mux] = 9,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200104 [snd_soc_dapm_demux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100105 [snd_soc_dapm_aif_in] = 10,
106 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100107 [snd_soc_dapm_dai_in] = 10,
108 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100109 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100110 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100111 [snd_soc_dapm_clock_supply] = 13,
112 [snd_soc_dapm_regulator_supply] = 13,
113 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200114};
115
Mark Brownf9fa2b12014-03-06 16:49:11 +0800116static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
117{
118 if (dapm->card && dapm->card->instantiated)
119 lockdep_assert_held(&dapm->card->dapm_mutex);
120}
121
Troy Kisky12ef1932008-10-13 17:42:14 -0700122static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100123{
124 if (pop_time)
125 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
126}
127
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200128static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100129{
130 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200131 char *buf;
132
133 if (!pop_time)
134 return;
135
136 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
137 if (buf == NULL)
138 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100139
140 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200141 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100142 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100143 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200144
145 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100146}
147
Mark Browndb432b42011-10-03 21:06:40 +0100148static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
149{
150 return !list_empty(&w->dirty);
151}
152
Mark Brown492c0a12014-03-06 16:15:48 +0800153static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100154{
Mark Brownf9fa2b12014-03-06 16:49:11 +0800155 dapm_assert_locked(w->dapm);
156
Mark Brown75c1f892011-10-04 22:28:08 +0100157 if (!dapm_dirty_widget(w)) {
158 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
159 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100160 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100161 }
Mark Browndb432b42011-10-03 21:06:40 +0100162}
163
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200164/*
165 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
166 * paths
167 * @w: The widget for which to invalidate the cached number of input paths
168 *
169 * The function resets the cached number of inputs for the specified widget and
170 * all widgets that can be reached via outgoing paths from the widget.
171 *
172 * This function must be called if the number of input paths for a widget might
173 * have changed. E.g. if the source state of a widget changes or a path is added
174 * or activated with the widget as the sink.
175 */
176static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
177{
178 struct snd_soc_dapm_widget *sink;
179 struct snd_soc_dapm_path *p;
180 LIST_HEAD(list);
181
182 dapm_assert_locked(w->dapm);
183
184 if (w->inputs == -1)
185 return;
186
187 w->inputs = -1;
188 list_add_tail(&w->work_list, &list);
189
190 list_for_each_entry(w, &list, work_list) {
191 list_for_each_entry(p, &w->sinks, list_source) {
192 if (p->is_supply || p->weak || !p->connect)
193 continue;
194 sink = p->sink;
195 if (sink->inputs != -1) {
196 sink->inputs = -1;
197 list_add_tail(&sink->work_list, &list);
198 }
199 }
200 }
201}
202
203/*
204 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
205 * output paths
206 * @w: The widget for which to invalidate the cached number of output paths
207 *
208 * Resets the cached number of outputs for the specified widget and all widgets
209 * that can be reached via incoming paths from the widget.
210 *
211 * This function must be called if the number of output paths for a widget might
212 * have changed. E.g. if the sink state of a widget changes or a path is added
213 * or activated with the widget as the source.
214 */
215static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
216{
217 struct snd_soc_dapm_widget *source;
218 struct snd_soc_dapm_path *p;
219 LIST_HEAD(list);
220
221 dapm_assert_locked(w->dapm);
222
223 if (w->outputs == -1)
224 return;
225
226 w->outputs = -1;
227 list_add_tail(&w->work_list, &list);
228
229 list_for_each_entry(w, &list, work_list) {
230 list_for_each_entry(p, &w->sources, list_sink) {
231 if (p->is_supply || p->weak || !p->connect)
232 continue;
233 source = p->source;
234 if (source->outputs != -1) {
235 source->outputs = -1;
236 list_add_tail(&source->work_list, &list);
237 }
238 }
239 }
240}
241
242/*
243 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
244 * for the widgets connected to a path
245 * @p: The path to invalidate
246 *
247 * Resets the cached number of inputs for the sink of the path and the cached
248 * number of outputs for the source of the path.
249 *
250 * This function must be called when a path is added, removed or the connected
251 * state changes.
252 */
253static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
254{
255 /*
256 * Weak paths or supply paths do not influence the number of input or
257 * output paths of their neighbors.
258 */
259 if (p->weak || p->is_supply)
260 return;
261
262 /*
263 * The number of connected endpoints is the sum of the number of
264 * connected endpoints of all neighbors. If a node with 0 connected
265 * endpoints is either connected or disconnected that sum won't change,
266 * so there is no need to re-check the path.
267 */
268 if (p->source->inputs != 0)
269 dapm_widget_invalidate_input_paths(p->sink);
270 if (p->sink->outputs != 0)
271 dapm_widget_invalidate_output_paths(p->source);
272}
273
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200274void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
Mark Browne2d32ff2012-08-31 17:38:32 -0700275{
Mark Browne2d32ff2012-08-31 17:38:32 -0700276 struct snd_soc_dapm_widget *w;
277
278 mutex_lock(&card->dapm_mutex);
279
280 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200281 if (w->is_sink || w->is_source) {
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200282 dapm_mark_dirty(w, "Rechecking endpoints");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200283 if (w->is_sink)
284 dapm_widget_invalidate_output_paths(w);
285 if (w->is_source)
286 dapm_widget_invalidate_input_paths(w);
287 }
Mark Browne2d32ff2012-08-31 17:38:32 -0700288 }
289
290 mutex_unlock(&card->dapm_mutex);
291}
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200292EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
Mark Browne2d32ff2012-08-31 17:38:32 -0700293
Richard Purdie2b97eab2006-10-06 18:32:18 +0200294/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100295static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200296 const struct snd_soc_dapm_widget *_widget)
297{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100298 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200299}
300
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200301struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200302 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200303 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200304 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200305 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200306};
307
308static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
309 struct snd_kcontrol *kcontrol)
310{
311 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200312 struct soc_mixer_control *mc;
Charles Keepax561ed682015-05-01 12:37:26 +0100313 struct soc_enum *e;
Charles Keepax773da9b2015-05-01 12:37:25 +0100314 const char *name;
315 int ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200316
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200317 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100318 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200319 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200320
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200321 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200322
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200323 switch (widget->id) {
324 case snd_soc_dapm_switch:
325 case snd_soc_dapm_mixer:
326 case snd_soc_dapm_mixer_named_ctl:
327 mc = (struct soc_mixer_control *)kcontrol->private_value;
328
329 if (mc->autodisable) {
330 struct snd_soc_dapm_widget template;
331
Charles Keepax773da9b2015-05-01 12:37:25 +0100332 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
333 "Autodisable");
334 if (!name) {
335 ret = -ENOMEM;
336 goto err_data;
337 }
338
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200339 memset(&template, 0, sizeof(template));
340 template.reg = mc->reg;
341 template.mask = (1 << fls(mc->max)) - 1;
342 template.shift = mc->shift;
343 if (mc->invert)
344 template.off_val = mc->max;
345 else
346 template.off_val = 0;
347 template.on_val = template.off_val;
348 template.id = snd_soc_dapm_kcontrol;
Charles Keepax773da9b2015-05-01 12:37:25 +0100349 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200350
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200351 data->value = template.on_val;
352
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200353 data->widget = snd_soc_dapm_new_control(widget->dapm,
354 &template);
355 if (!data->widget) {
Charles Keepax773da9b2015-05-01 12:37:25 +0100356 ret = -ENOMEM;
357 goto err_name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200358 }
359 }
360 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200361 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100362 case snd_soc_dapm_mux:
363 e = (struct soc_enum *)kcontrol->private_value;
364
365 if (e->autodisable) {
366 struct snd_soc_dapm_widget template;
367
368 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
369 "Autodisable");
370 if (!name) {
371 ret = -ENOMEM;
372 goto err_data;
373 }
374
375 memset(&template, 0, sizeof(template));
376 template.reg = e->reg;
377 template.mask = e->mask << e->shift_l;
378 template.shift = e->shift_l;
379 template.off_val = snd_soc_enum_item_to_val(e, 0);
380 template.on_val = template.off_val;
381 template.id = snd_soc_dapm_kcontrol;
382 template.name = name;
383
384 data->value = template.on_val;
385
386 data->widget = snd_soc_dapm_new_control(widget->dapm,
387 &template);
388 if (!data->widget) {
389 ret = -ENOMEM;
390 goto err_name;
391 }
392
393 snd_soc_dapm_add_path(widget->dapm, data->widget,
394 widget, NULL, NULL);
395 }
396 break;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200397 default:
398 break;
399 }
400
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200401 kcontrol->private_data = data;
402
403 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100404
405err_name:
406 kfree(name);
407err_data:
408 kfree(data);
409 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200410}
411
412static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
413{
414 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Charles Keepax773da9b2015-05-01 12:37:25 +0100415 if (data->widget)
416 kfree(data->widget->name);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200417 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200418 kfree(data);
419}
420
421static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
422 const struct snd_kcontrol *kcontrol)
423{
424 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
425
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200426 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200427}
428
429static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
430 struct snd_soc_dapm_widget *widget)
431{
432 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200433 struct snd_soc_dapm_widget_list *new_wlist;
434 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200435
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200436 if (data->wlist)
437 n = data->wlist->num_widgets + 1;
438 else
439 n = 1;
440
441 new_wlist = krealloc(data->wlist,
442 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
443 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200444 return -ENOMEM;
445
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200446 new_wlist->widgets[n - 1] = widget;
447 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200448
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200449 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200450
451 return 0;
452}
453
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200454static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
455 struct snd_soc_dapm_path *path)
456{
457 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
458
459 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200460}
461
462static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
463{
464 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
465
466 if (!data->widget)
467 return true;
468
469 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200470}
471
472static struct list_head *dapm_kcontrol_get_path_list(
473 const struct snd_kcontrol *kcontrol)
474{
475 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
476
477 return &data->paths;
478}
479
480#define dapm_kcontrol_for_each_path(path, kcontrol) \
481 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
482 list_kcontrol)
483
Subhransu S. Prusty5dc01582014-09-19 16:46:05 +0530484unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200485{
486 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
487
488 return data->value;
489}
Subhransu S. Prusty5dc01582014-09-19 16:46:05 +0530490EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200491
492static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
493 unsigned int value)
494{
495 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
496
497 if (data->value == value)
498 return false;
499
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200500 if (data->widget)
501 data->widget->on_val = value;
502
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200503 data->value = value;
504
505 return true;
506}
507
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200508/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200509 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
510 * kcontrol
511 * @kcontrol: The kcontrol
512 *
513 * Note: This function must only be used on kcontrols that are known to have
514 * been registered for a CODEC. Otherwise the behaviour is undefined.
515 */
516struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
517 struct snd_kcontrol *kcontrol)
518{
519 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
520}
521EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
522
Liam Girdwood6c120e12012-02-15 15:15:34 +0000523static void dapm_reset(struct snd_soc_card *card)
524{
525 struct snd_soc_dapm_widget *w;
526
Mark Brownf9fa2b12014-03-06 16:49:11 +0800527 lockdep_assert_held(&card->dapm_mutex);
528
Liam Girdwood6c120e12012-02-15 15:15:34 +0000529 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
530
531 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200532 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000533 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000534 }
535}
536
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200537static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
538{
539 if (!dapm->component)
540 return NULL;
541 return dapm->component->name_prefix;
542}
543
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200544static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800545 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100546{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200547 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200548 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200549 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100550}
551
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200552static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800553 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100554{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200555 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200556 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000557 return snd_soc_component_update_bits(dapm->component, reg,
558 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000559}
560
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200561static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
562 int reg, unsigned int mask, unsigned int value)
563{
564 if (!dapm->component)
565 return -EIO;
566 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
567}
568
Mark Browneb270e92013-10-09 13:52:52 +0100569static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
570{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200571 if (dapm->component)
572 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100573}
574
Charles Keepax45a110a2015-05-11 13:50:30 +0100575static struct snd_soc_dapm_widget *
576dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
577{
578 struct snd_soc_dapm_widget *w = wcache->widget;
579 struct list_head *wlist;
580 const int depth = 2;
581 int i = 0;
582
583 if (w) {
584 wlist = &w->dapm->card->widgets;
585
586 list_for_each_entry_from(w, wlist, list) {
587 if (!strcmp(name, w->name))
588 return w;
589
590 if (++i == depth)
591 break;
592 }
593 }
594
595 return NULL;
596}
597
598static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
599 struct snd_soc_dapm_widget *w)
600{
601 wcache->widget = w;
602}
603
Mark Brown452c5ea2009-05-17 21:41:23 +0100604/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200605 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
606 * @dapm: The DAPM context for which to set the level
607 * @level: The level to set
608 *
609 * Forces the DAPM bias level to a specific state. It will call the bias level
610 * callback of DAPM context with the specified level. This will even happen if
611 * the context is already at the same level. Furthermore it will not go through
612 * the normal bias level sequencing, meaning any intermediate states between the
613 * current and the target state will not be entered.
614 *
615 * Note that the change in bias level is only temporary and the next time
616 * snd_soc_dapm_sync() is called the state will be set to the level as
617 * determined by the DAPM core. The function is mainly intended to be used to
618 * used during probe or resume from suspend to power up the device so
619 * initialization can be done, before the DAPM core takes over.
620 */
621int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
622 enum snd_soc_bias_level level)
623{
624 int ret = 0;
625
626 if (dapm->set_bias_level)
627 ret = dapm->set_bias_level(dapm, level);
628
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200629 if (ret == 0)
630 dapm->bias_level = level;
631
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200632 return ret;
633}
634EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
635
636/**
Mark Brown452c5ea2009-05-17 21:41:23 +0100637 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800638 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100639 * @level: level to configure
640 *
641 * Configure the bias (power) levels for the SoC audio device.
642 *
643 * Returns 0 for success else error.
644 */
Mark Browned5a4c42011-02-18 11:12:42 -0800645static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200646 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100647{
Mark Browned5a4c42011-02-18 11:12:42 -0800648 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100649 int ret = 0;
650
Mark Brown84e90932010-11-04 00:07:02 -0400651 trace_snd_soc_bias_level_start(card, level);
652
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000653 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100654 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100655 if (ret != 0)
656 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100657
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200658 if (!card || dapm != &card->dapm)
659 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100660
Mark Brown171ec6b2011-06-06 18:15:19 +0100661 if (ret != 0)
662 goto out;
663
664 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100665 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100666out:
Mark Brown84e90932010-11-04 00:07:02 -0400667 trace_snd_soc_bias_level_done(card, level);
668
Mark Brown452c5ea2009-05-17 21:41:23 +0100669 return ret;
670}
671
Mark Brown74b8f952009-06-06 11:26:15 +0100672/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200673static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200674 struct snd_soc_dapm_path *path, const char *control_name,
675 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200676{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200677 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200678 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100679 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200680 int i;
681
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100682 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200683 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100684 val = (val >> e->shift_l) & e->mask;
685 item = snd_soc_enum_val_to_item(e, val);
686 } else {
687 /* since a virtual mux has no backing registers to
688 * decide which path to connect, it will try to match
689 * with the first enumeration. This is to ensure
690 * that the default mux choice (the first) will be
691 * correctly powered up during initialization.
692 */
693 item = 0;
694 }
695
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100696 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200697 if (!(strcmp(control_name, e->texts[i]))) {
Rasmus Villemoes98ad73c2014-10-21 17:01:15 +0200698 path->name = e->texts[i];
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100699 if (i == item)
700 path->connect = 1;
701 else
702 path->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200703 return 0;
704 }
705 }
706
707 return -ENODEV;
708}
709
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100710/* set up initial codec paths */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200711static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100712{
713 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200714 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100715 unsigned int reg = mc->reg;
716 unsigned int shift = mc->shift;
717 unsigned int max = mc->max;
718 unsigned int mask = (1 << fls(max)) - 1;
719 unsigned int invert = mc->invert;
720 unsigned int val;
721
722 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200723 soc_dapm_read(p->sink->dapm, reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100724 val = (val >> shift) & mask;
725 if (invert)
726 val = max - val;
727 p->connect = !!val;
728 } else {
729 p->connect = 0;
730 }
731}
732
Mark Brown74b8f952009-06-06 11:26:15 +0100733/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200734static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200735 struct snd_soc_dapm_path *path, const char *control_name)
736{
737 int i;
738
739 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200740 for (i = 0; i < path->sink->num_kcontrols; i++) {
741 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
742 path->name = path->sink->kcontrol_news[i].name;
743 dapm_set_mixer_path_status(path, i);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200744 return 0;
745 }
746 }
747 return -ENODEV;
748}
749
Stephen Warrenaf468002011-04-28 17:38:01 -0600750static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600751 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600752 const struct snd_kcontrol_new *kcontrol_new,
753 struct snd_kcontrol **kcontrol)
754{
755 struct snd_soc_dapm_widget *w;
756 int i;
757
758 *kcontrol = NULL;
759
760 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600761 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
762 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600763 for (i = 0; i < w->num_kcontrols; i++) {
764 if (&w->kcontrol_news[i] == kcontrol_new) {
765 if (w->kcontrols)
766 *kcontrol = w->kcontrols[i];
767 return 1;
768 }
769 }
770 }
771
772 return 0;
773}
774
Stephen Warren85762e72013-03-29 15:40:10 -0600775/*
776 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
777 * create it. Either way, add the widget into the control's widget list
778 */
779static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100780 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200781{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200782 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000783 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000784 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600785 size_t prefix_len;
786 int shared;
787 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600788 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200789 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600790 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200791 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000792
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200793 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000794 if (prefix)
795 prefix_len = strlen(prefix) + 1;
796 else
797 prefix_len = 0;
798
Stephen Warren85762e72013-03-29 15:40:10 -0600799 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
800 &kcontrol);
801
Stephen Warren85762e72013-03-29 15:40:10 -0600802 if (!kcontrol) {
803 if (shared) {
804 wname_in_long_name = false;
805 kcname_in_long_name = true;
806 } else {
807 switch (w->id) {
808 case snd_soc_dapm_switch:
809 case snd_soc_dapm_mixer:
810 wname_in_long_name = true;
811 kcname_in_long_name = true;
812 break;
813 case snd_soc_dapm_mixer_named_ctl:
814 wname_in_long_name = false;
815 kcname_in_long_name = true;
816 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200817 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600818 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600819 wname_in_long_name = true;
820 kcname_in_long_name = false;
821 break;
822 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600823 return -EINVAL;
824 }
825 }
826
827 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600828 /*
829 * The control will get a prefix from the control
830 * creation process but we're also using the same
831 * prefix for widgets so cut the prefix off the
832 * front of the widget name.
833 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200834 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600835 w->name + prefix_len,
836 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200837 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200838 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600839
840 name = long_name;
841 } else if (wname_in_long_name) {
842 long_name = NULL;
843 name = w->name + prefix_len;
844 } else {
845 long_name = NULL;
846 name = w->kcontrol_news[kci].name;
847 }
848
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200849 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600850 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200851 if (!kcontrol) {
852 ret = -ENOMEM;
853 goto exit_free;
854 }
855
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200856 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200857
858 ret = dapm_kcontrol_data_alloc(w, kcontrol);
859 if (ret) {
860 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200861 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200862 }
863
Stephen Warren85762e72013-03-29 15:40:10 -0600864 ret = snd_ctl_add(card, kcontrol);
865 if (ret < 0) {
866 dev_err(dapm->dev,
867 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
868 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200869 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600870 }
Stephen Warren85762e72013-03-29 15:40:10 -0600871 }
872
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200873 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200874 if (ret == 0)
875 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200876
Daniel Macke5092c92014-10-07 13:41:24 +0200877exit_free:
878 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600879
Daniel Macke5092c92014-10-07 13:41:24 +0200880 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600881}
882
883/* create new dapm mixer control */
884static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
885{
886 int i, ret;
887 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100888 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600889
Richard Purdie2b97eab2006-10-06 18:32:18 +0200890 /* add kcontrol */
891 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200892 /* match name */
893 list_for_each_entry(path, &w->sources, list_sink) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200894 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600895 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200896 continue;
897
Charles Keepax561ed682015-05-01 12:37:26 +0100898 if (!w->kcontrols[i]) {
899 ret = dapm_create_or_share_mixmux_kcontrol(w, i);
900 if (ret < 0)
901 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200902 }
903
Mark Brown946d92a2013-08-12 23:28:42 +0100904 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100905
906 data = snd_kcontrol_chip(w->kcontrols[i]);
907 if (data->widget)
908 snd_soc_dapm_add_path(data->widget->dapm,
909 data->widget,
910 path->source,
911 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200912 }
913 }
Stephen Warren85762e72013-03-29 15:40:10 -0600914
915 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200916}
917
918/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200919static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200920{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200921 struct snd_soc_dapm_context *dapm = w->dapm;
Stephen Warren85762e72013-03-29 15:40:10 -0600922 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200923 struct list_head *paths;
924 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600925 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200926
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200927 switch (w->id) {
928 case snd_soc_dapm_mux:
929 paths = &w->sources;
930 type = "mux";
931 break;
932 case snd_soc_dapm_demux:
933 paths = &w->sinks;
934 type = "demux";
935 break;
936 default:
937 return -EINVAL;
938 }
939
Stephen Warrenaf468002011-04-28 17:38:01 -0600940 if (w->num_kcontrols != 1) {
941 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200942 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600943 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200944 return -EINVAL;
945 }
946
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200947 if (list_empty(paths)) {
948 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600949 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600950 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200951
Mark Brown946d92a2013-08-12 23:28:42 +0100952 ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600953 if (ret < 0)
954 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600955
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200956 if (w->id == snd_soc_dapm_mux) {
957 list_for_each_entry(path, &w->sources, list_sink) {
958 if (path->name)
959 dapm_kcontrol_add_path(w->kcontrols[0], path);
960 }
961 } else {
962 list_for_each_entry(path, &w->sinks, list_source) {
963 if (path->name)
964 dapm_kcontrol_add_path(w->kcontrols[0], path);
965 }
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +0200966 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200967
Stephen Warrenaf468002011-04-28 17:38:01 -0600968 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200969}
970
971/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200972static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200973{
Mark Browna6c65732010-03-03 17:45:21 +0000974 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200975 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000976 "ASoC: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200977
Mark Browna6c65732010-03-03 17:45:21 +0000978 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200979}
980
Nikesh Oswalc6615082015-02-02 17:06:44 +0000981/* create new dapm dai link control */
982static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
983{
984 int i, ret;
985 struct snd_kcontrol *kcontrol;
986 struct snd_soc_dapm_context *dapm = w->dapm;
987 struct snd_card *card = dapm->card->snd_card;
988
989 /* create control for links with > 1 config */
990 if (w->num_params <= 1)
991 return 0;
992
993 /* add kcontrol */
994 for (i = 0; i < w->num_kcontrols; i++) {
995 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
996 w->name, NULL);
997 ret = snd_ctl_add(card, kcontrol);
998 if (ret < 0) {
999 dev_err(dapm->dev,
1000 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1001 w->name, w->kcontrol_news[i].name, ret);
1002 return ret;
1003 }
1004 kcontrol->private_data = w;
1005 w->kcontrols[i] = kcontrol;
1006 }
1007
1008 return 0;
1009}
1010
Mark Brown99497882010-05-07 20:24:05 +01001011/* We implement power down on suspend by checking the power state of
1012 * the ALSA card - when we are suspending the ALSA state for the card
1013 * is set to D3.
1014 */
1015static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1016{
Mark Brown12ea2c72011-03-02 18:17:32 +00001017 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +01001018
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001019 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +01001020 case SNDRV_CTL_POWER_D3hot:
1021 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +01001022 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001023 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001024 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +01001025 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +01001026 default:
1027 return 1;
1028 }
1029}
1030
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001031/* add widget to list if it's not already in the list */
1032static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
1033 struct snd_soc_dapm_widget *w)
1034{
1035 struct snd_soc_dapm_widget_list *wlist;
1036 int wlistsize, wlistentries, i;
1037
1038 if (*list == NULL)
1039 return -EINVAL;
1040
1041 wlist = *list;
1042
1043 /* is this widget already in the list */
1044 for (i = 0; i < wlist->num_widgets; i++) {
1045 if (wlist->widgets[i] == w)
1046 return 0;
1047 }
1048
1049 /* allocate some new space */
1050 wlistentries = wlist->num_widgets + 1;
1051 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
1052 wlistentries * sizeof(struct snd_soc_dapm_widget *);
1053 *list = krealloc(wlist, wlistsize, GFP_KERNEL);
1054 if (*list == NULL) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001055 dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001056 w->name);
1057 return -ENOMEM;
1058 }
1059 wlist = *list;
1060
1061 /* insert the widget */
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001062 dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001063 w->name, wlist->num_widgets);
1064
1065 wlist->widgets[wlist->num_widgets] = w;
1066 wlist->num_widgets++;
1067 return 1;
1068}
1069
Richard Purdie2b97eab2006-10-06 18:32:18 +02001070/*
1071 * Recursively check for a completed path to an active or physically connected
1072 * output widget. Returns number of complete paths.
1073 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001074static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
1075 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001076{
1077 struct snd_soc_dapm_path *path;
1078 int con = 0;
1079
Mark Brown024dc072011-10-09 11:52:05 +01001080 if (widget->outputs >= 0)
1081 return widget->outputs;
1082
Mark Brownde02d072011-09-20 21:43:24 +01001083 DAPM_UPDATE_STAT(widget, path_checks);
1084
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001085 if (widget->is_sink && widget->connected) {
1086 widget->outputs = snd_soc_dapm_suspend_check(widget);
1087 return widget->outputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001088 }
1089
1090 list_for_each_entry(path, &widget->sinks, list_source) {
Mark Browne56235e2011-09-21 18:19:14 +01001091 DAPM_UPDATE_STAT(widget, neighbour_checks);
1092
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001093 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001094 continue;
1095
Mark Brown8af294b2013-02-22 17:48:15 +00001096 if (path->walking)
1097 return 1;
1098
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001099 trace_snd_soc_dapm_output_path(widget, path);
1100
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001101 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001102 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001103
1104 /* do we need to add this widget to the list ? */
1105 if (list) {
1106 int err;
1107 err = dapm_list_add_widget(list, path->sink);
1108 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001109 dev_err(widget->dapm->dev,
1110 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001111 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +00001112 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001113 return con;
1114 }
1115 }
1116
1117 con += is_connected_output_ep(path->sink, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001118
1119 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001120 }
1121 }
1122
Mark Brown024dc072011-10-09 11:52:05 +01001123 widget->outputs = con;
1124
Richard Purdie2b97eab2006-10-06 18:32:18 +02001125 return con;
1126}
1127
1128/*
1129 * Recursively check for a completed path to an active or physically connected
1130 * input widget. Returns number of complete paths.
1131 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001132static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
1133 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001134{
1135 struct snd_soc_dapm_path *path;
1136 int con = 0;
1137
Mark Brown024dc072011-10-09 11:52:05 +01001138 if (widget->inputs >= 0)
1139 return widget->inputs;
1140
Mark Brownde02d072011-09-20 21:43:24 +01001141 DAPM_UPDATE_STAT(widget, path_checks);
1142
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001143 if (widget->is_source && widget->connected) {
1144 widget->inputs = snd_soc_dapm_suspend_check(widget);
1145 return widget->inputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001146 }
1147
1148 list_for_each_entry(path, &widget->sources, list_sink) {
Mark Browne56235e2011-09-21 18:19:14 +01001149 DAPM_UPDATE_STAT(widget, neighbour_checks);
1150
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001151 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001152 continue;
1153
Mark Brown8af294b2013-02-22 17:48:15 +00001154 if (path->walking)
1155 return 1;
1156
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001157 trace_snd_soc_dapm_input_path(widget, path);
1158
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001159 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001160 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001161
1162 /* do we need to add this widget to the list ? */
1163 if (list) {
1164 int err;
Liam Girdwood90c6ce02012-06-05 19:27:15 +01001165 err = dapm_list_add_widget(list, path->source);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001166 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001167 dev_err(widget->dapm->dev,
1168 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001169 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +00001170 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001171 return con;
1172 }
1173 }
1174
1175 con += is_connected_input_ep(path->source, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001176
1177 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001178 }
1179 }
1180
Mark Brown024dc072011-10-09 11:52:05 +01001181 widget->inputs = con;
1182
Richard Purdie2b97eab2006-10-06 18:32:18 +02001183 return con;
1184}
1185
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001186/**
1187 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1188 * @dai: the soc DAI.
1189 * @stream: stream direction.
1190 * @list: list of active widgets for this stream.
1191 *
1192 * Queries DAPM graph as to whether an valid audio stream path exists for
1193 * the initial stream specified by name. This takes into account
1194 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1195 *
1196 * Returns the number of valid paths or negative error.
1197 */
1198int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1199 struct snd_soc_dapm_widget_list **list)
1200{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001201 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001202 struct snd_soc_dapm_widget *w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001203 int paths;
1204
1205 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001206
1207 /*
1208 * For is_connected_{output,input}_ep fully discover the graph we need
1209 * to reset the cached number of inputs and outputs.
1210 */
1211 list_for_each_entry(w, &card->widgets, list) {
1212 w->inputs = -1;
1213 w->outputs = -1;
1214 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001215
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001216 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001217 paths = is_connected_output_ep(dai->playback_widget, list);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001218 else
Liam Girdwoodd298caa2012-06-01 18:03:00 +01001219 paths = is_connected_input_ep(dai->capture_widget, list);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001220
1221 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001222 mutex_unlock(&card->dapm_mutex);
1223
1224 return paths;
1225}
1226
Richard Purdie2b97eab2006-10-06 18:32:18 +02001227/*
Mark Brown62ea8742012-01-21 21:14:48 +00001228 * Handler for regulator supply widget.
1229 */
1230int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1231 struct snd_kcontrol *kcontrol, int event)
1232{
Mark Brownc05b84d2012-09-07 12:57:11 +08001233 int ret;
1234
Mark Browneb270e92013-10-09 13:52:52 +01001235 soc_dapm_async_complete(w->dapm);
1236
Mark Brownc05b84d2012-09-07 12:57:11 +08001237 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001238 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001239 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001240 if (ret != 0)
1241 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001242 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001243 w->name, ret);
1244 }
1245
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001246 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001247 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001248 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001249 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001250 if (ret != 0)
1251 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001252 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001253 w->name, ret);
1254 }
1255
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001256 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001257 }
Mark Brown62ea8742012-01-21 21:14:48 +00001258}
1259EXPORT_SYMBOL_GPL(dapm_regulator_event);
1260
Ola Liljad7e7eb92012-05-24 15:26:25 +02001261/*
1262 * Handler for clock supply widget.
1263 */
1264int dapm_clock_event(struct snd_soc_dapm_widget *w,
1265 struct snd_kcontrol *kcontrol, int event)
1266{
1267 if (!w->clk)
1268 return -EIO;
1269
Mark Browneb270e92013-10-09 13:52:52 +01001270 soc_dapm_async_complete(w->dapm);
1271
Mark Brownec029952012-06-04 08:16:20 +01001272#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001273 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001274 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001275 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001276 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001277 return 0;
1278 }
Mark Brownec029952012-06-04 08:16:20 +01001279#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001280 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001281}
1282EXPORT_SYMBOL_GPL(dapm_clock_event);
1283
Mark Brownd8050022011-09-28 18:28:23 +01001284static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1285{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001286 if (w->power_checked)
1287 return w->new_power;
1288
Mark Brownd8050022011-09-28 18:28:23 +01001289 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001290 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001291 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001292 w->new_power = w->power_check(w);
1293
1294 w->power_checked = true;
1295
1296 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001297}
1298
Mark Browncd0f2d42009-04-20 16:56:59 +01001299/* Generic check to see if a widget should be powered.
1300 */
1301static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1302{
1303 int in, out;
1304
Mark Brownde02d072011-09-20 21:43:24 +01001305 DAPM_UPDATE_STAT(w, power_checks);
1306
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001307 in = is_connected_input_ep(w, NULL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001308 out = is_connected_output_ep(w, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001309 return out != 0 && in != 0;
1310}
1311
Mark Brown246d0a12009-04-22 18:24:55 +01001312/* Check to see if a power supply is needed */
1313static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1314{
1315 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001316
Mark Brownde02d072011-09-20 21:43:24 +01001317 DAPM_UPDATE_STAT(w, power_checks);
1318
Mark Brown246d0a12009-04-22 18:24:55 +01001319 /* Check if one of our outputs is connected */
1320 list_for_each_entry(path, &w->sinks, list_source) {
Mark Browna8fdac82011-09-28 18:20:26 +01001321 DAPM_UPDATE_STAT(w, neighbour_checks);
1322
Mark Brownbf3a9e12011-06-13 16:42:29 +01001323 if (path->weak)
1324 continue;
1325
Mark Brown215edda2009-09-08 18:59:05 +01001326 if (path->connected &&
1327 !path->connected(path->source, path->sink))
1328 continue;
1329
Mark Brownf68d7e12011-10-04 22:57:50 +01001330 if (dapm_widget_power_check(path->sink))
1331 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001332 }
1333
Mark Brownf68d7e12011-10-04 22:57:50 +01001334 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001335}
1336
Mark Brown35c64bc2011-09-28 18:23:53 +01001337static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1338{
1339 return 1;
1340}
1341
Mark Brown38357ab2009-06-06 19:03:23 +01001342static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1343 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001344 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001345{
Mark Brown828a8422011-01-15 13:14:30 +00001346 int *sort;
1347
1348 if (power_up)
1349 sort = dapm_up_seq;
1350 else
1351 sort = dapm_down_seq;
1352
Mark Brown38357ab2009-06-06 19:03:23 +01001353 if (sort[a->id] != sort[b->id])
1354 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001355 if (a->subseq != b->subseq) {
1356 if (power_up)
1357 return a->subseq - b->subseq;
1358 else
1359 return b->subseq - a->subseq;
1360 }
Mark Brownb22ead22009-06-07 12:51:26 +01001361 if (a->reg != b->reg)
1362 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001363 if (a->dapm != b->dapm)
1364 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001365
Mark Brown38357ab2009-06-06 19:03:23 +01001366 return 0;
1367}
Mark Brown42aa3412009-03-01 19:21:10 +00001368
Mark Brown38357ab2009-06-06 19:03:23 +01001369/* Insert a widget in order into a DAPM power sequence. */
1370static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1371 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001372 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001373{
1374 struct snd_soc_dapm_widget *w;
1375
1376 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001377 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001378 list_add_tail(&new_widget->power_list, &w->power_list);
1379 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001380 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001381
Mark Brown38357ab2009-06-06 19:03:23 +01001382 list_add_tail(&new_widget->power_list, list);
1383}
Mark Brown42aa3412009-03-01 19:21:10 +00001384
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001385static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001386 struct snd_soc_dapm_widget *w, int event)
1387{
Mark Brown68f89ad2010-11-03 23:51:49 -04001388 const char *ev_name;
1389 int power, ret;
1390
1391 switch (event) {
1392 case SND_SOC_DAPM_PRE_PMU:
1393 ev_name = "PRE_PMU";
1394 power = 1;
1395 break;
1396 case SND_SOC_DAPM_POST_PMU:
1397 ev_name = "POST_PMU";
1398 power = 1;
1399 break;
1400 case SND_SOC_DAPM_PRE_PMD:
1401 ev_name = "PRE_PMD";
1402 power = 0;
1403 break;
1404 case SND_SOC_DAPM_POST_PMD:
1405 ev_name = "POST_PMD";
1406 power = 0;
1407 break;
Mark Brown80114122013-02-25 15:14:19 +00001408 case SND_SOC_DAPM_WILL_PMU:
1409 ev_name = "WILL_PMU";
1410 power = 1;
1411 break;
1412 case SND_SOC_DAPM_WILL_PMD:
1413 ev_name = "WILL_PMD";
1414 power = 0;
1415 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001416 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001417 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001418 return;
1419 }
1420
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001421 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001422 return;
1423
1424 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001425 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001426 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001427 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001428 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001429 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001430 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001431 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001432 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001433 ev_name, w->name, ret);
1434 }
1435}
1436
Mark Brownb22ead22009-06-07 12:51:26 +01001437/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001438static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001439 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001440{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001441 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001442 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001443 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001444 unsigned int value = 0;
1445 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001446
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001447 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1448 reg = w->reg;
1449 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001450
1451 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001452 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001453 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001454
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001455 mask |= w->mask << w->shift;
1456 if (w->power)
1457 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001458 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001459 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001460
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001461 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001462 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1463 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001464
Mark Brown68f89ad2010-11-03 23:51:49 -04001465 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001466 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1467 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001468 }
1469
Mark Brown81628102009-06-07 13:21:24 +01001470 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001471 /* Any widget will do, they should all be updating the
1472 * same register.
1473 */
Mark Brown29376bc2011-06-19 13:49:28 +01001474
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001475 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001476 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001477 value, mask, reg, card->pop_time);
1478 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001479 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001480 }
1481
1482 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001483 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1484 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001485 }
Mark Brown42aa3412009-03-01 19:21:10 +00001486}
1487
Mark Brownb22ead22009-06-07 12:51:26 +01001488/* Apply a DAPM power sequence.
1489 *
1490 * We walk over a pre-sorted list of widgets to apply power to. In
1491 * order to minimise the number of writes to the device required
1492 * multiple widgets will be updated in a single write where possible.
1493 * Currently anything that requires more than a single write is not
1494 * handled.
1495 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001496static void dapm_seq_run(struct snd_soc_card *card,
1497 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001498{
1499 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001500 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001501 LIST_HEAD(pending);
1502 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001503 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001504 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001505 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001506 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001507 int *sort;
1508
1509 if (power_up)
1510 sort = dapm_up_seq;
1511 else
1512 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001513
Mark Brownb22ead22009-06-07 12:51:26 +01001514 list_for_each_entry_safe(w, n, list, power_list) {
1515 ret = 0;
1516
1517 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001518 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001519 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001520 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001521 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001522
Mark Brown474b62d2011-01-18 16:14:44 +00001523 if (cur_dapm && cur_dapm->seq_notifier) {
1524 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1525 if (sort[i] == cur_sort)
1526 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001527 i,
1528 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001529 }
1530
Mark Browneb270e92013-10-09 13:52:52 +01001531 if (cur_dapm && w->dapm != cur_dapm)
1532 soc_dapm_async_complete(cur_dapm);
1533
Mark Brownb22ead22009-06-07 12:51:26 +01001534 INIT_LIST_HEAD(&pending);
1535 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001536 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001537 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001538 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001539 }
1540
Mark Brown163cac02009-06-07 10:12:52 +01001541 switch (w->id) {
1542 case snd_soc_dapm_pre:
1543 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001544 list_for_each_entry_safe_continue(w, n, list,
1545 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001546
Mark Brownb22ead22009-06-07 12:51:26 +01001547 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001548 ret = w->event(w,
1549 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001550 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001551 ret = w->event(w,
1552 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001553 break;
1554
1555 case snd_soc_dapm_post:
1556 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001557 list_for_each_entry_safe_continue(w, n, list,
1558 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001559
Mark Brownb22ead22009-06-07 12:51:26 +01001560 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001561 ret = w->event(w,
1562 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001563 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001564 ret = w->event(w,
1565 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001566 break;
1567
Mark Brown163cac02009-06-07 10:12:52 +01001568 default:
Mark Brown81628102009-06-07 13:21:24 +01001569 /* Queue it up for application */
1570 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001571 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001572 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001573 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001574 list_move(&w->power_list, &pending);
1575 break;
Mark Brown163cac02009-06-07 10:12:52 +01001576 }
Mark Brownb22ead22009-06-07 12:51:26 +01001577
1578 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001579 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001580 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001581 }
Mark Brownb22ead22009-06-07 12:51:26 +01001582
1583 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001584 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001585
1586 if (cur_dapm && cur_dapm->seq_notifier) {
1587 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1588 if (sort[i] == cur_sort)
1589 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001590 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001591 }
Mark Browneb270e92013-10-09 13:52:52 +01001592
1593 list_for_each_entry(d, &card->dapm_list, list) {
1594 soc_dapm_async_complete(d);
1595 }
Mark Brown163cac02009-06-07 10:12:52 +01001596}
1597
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001598static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001599{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001600 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001601 struct snd_soc_dapm_widget_list *wlist;
1602 struct snd_soc_dapm_widget *w = NULL;
1603 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001604 int ret;
1605
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001606 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001607 return;
1608
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001609 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001610
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001611 for (wi = 0; wi < wlist->num_widgets; wi++) {
1612 w = wlist->widgets[wi];
1613
1614 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1615 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1616 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001617 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001618 w->name, ret);
1619 }
Mark Brown97404f22010-12-14 16:13:57 +00001620 }
1621
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001622 if (!w)
1623 return;
1624
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001625 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1626 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001627 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001628 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001629 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001630
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001631 for (wi = 0; wi < wlist->num_widgets; wi++) {
1632 w = wlist->widgets[wi];
1633
1634 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1635 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1636 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001637 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001638 w->name, ret);
1639 }
Mark Brown97404f22010-12-14 16:13:57 +00001640 }
1641}
1642
Mark Brown9d0624a2011-02-18 11:49:43 -08001643/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1644 * they're changing state.
1645 */
1646static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1647{
1648 struct snd_soc_dapm_context *d = data;
1649 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001650
Mark Brown56fba412011-06-04 11:25:10 +01001651 /* If we're off and we're not supposed to be go into STANDBY */
1652 if (d->bias_level == SND_SOC_BIAS_OFF &&
1653 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001654 if (d->dev)
1655 pm_runtime_get_sync(d->dev);
1656
Mark Brown9d0624a2011-02-18 11:49:43 -08001657 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1658 if (ret != 0)
1659 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001660 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001661 }
1662
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001663 /* Prepare for a transition to ON or away from ON */
1664 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1665 d->bias_level != SND_SOC_BIAS_ON) ||
1666 (d->target_bias_level != SND_SOC_BIAS_ON &&
1667 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001668 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1669 if (ret != 0)
1670 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001671 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001672 }
1673}
1674
1675/* Async callback run prior to DAPM sequences - brings to their final
1676 * state.
1677 */
1678static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1679{
1680 struct snd_soc_dapm_context *d = data;
1681 int ret;
1682
1683 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001684 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1685 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1686 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001687 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1688 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001689 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001690 ret);
1691 }
1692
1693 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001694 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1695 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001696 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1697 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001698 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1699 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001700
1701 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001702 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001703 }
1704
1705 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001706 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1707 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001708 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1709 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001710 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001711 ret);
1712 }
1713}
Mark Brown97404f22010-12-14 16:13:57 +00001714
Mark Brownfe4fda52011-10-03 22:36:57 +01001715static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1716 bool power, bool connect)
1717{
1718 /* If a connection is being made or broken then that update
1719 * will have marked the peer dirty, otherwise the widgets are
1720 * not connected and this update has no impact. */
1721 if (!connect)
1722 return;
1723
1724 /* If the peer is already in the state we're moving to then we
1725 * won't have an impact on it. */
1726 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001727 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001728}
1729
Mark Brown05623c42011-09-28 17:02:31 +01001730static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1731 struct list_head *up_list,
1732 struct list_head *down_list)
1733{
Mark Browndb432b42011-10-03 21:06:40 +01001734 struct snd_soc_dapm_path *path;
1735
Mark Brown05623c42011-09-28 17:02:31 +01001736 if (w->power == power)
1737 return;
1738
1739 trace_snd_soc_dapm_widget_power(w, power);
1740
Mark Browndb432b42011-10-03 21:06:40 +01001741 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001742 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001743 */
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001744 list_for_each_entry(path, &w->sources, list_sink)
1745 dapm_widget_set_peer_power(path->source, power, path->connect);
1746
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001747 /* Supplies can't affect their outputs, only their inputs */
1748 if (!w->is_supply) {
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001749 list_for_each_entry(path, &w->sinks, list_source)
1750 dapm_widget_set_peer_power(path->sink, power,
1751 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001752 }
1753
Mark Brown05623c42011-09-28 17:02:31 +01001754 if (power)
1755 dapm_seq_insert(w, up_list, true);
1756 else
1757 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001758}
1759
Mark Brown7c81beb2011-09-20 22:22:32 +01001760static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1761 struct list_head *up_list,
1762 struct list_head *down_list)
1763{
Mark Brown7c81beb2011-09-20 22:22:32 +01001764 int power;
1765
1766 switch (w->id) {
1767 case snd_soc_dapm_pre:
1768 dapm_seq_insert(w, down_list, false);
1769 break;
1770 case snd_soc_dapm_post:
1771 dapm_seq_insert(w, up_list, true);
1772 break;
1773
1774 default:
Mark Brownd8050022011-09-28 18:28:23 +01001775 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001776
Mark Brown05623c42011-09-28 17:02:31 +01001777 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001778 break;
1779 }
1780}
1781
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001782static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1783{
1784 if (dapm->idle_bias_off)
1785 return true;
1786
1787 switch (snd_power_get_state(dapm->card->snd_card)) {
1788 case SNDRV_CTL_POWER_D3hot:
1789 case SNDRV_CTL_POWER_D3cold:
1790 return dapm->suspend_bias_off;
1791 default:
1792 break;
1793 }
1794
1795 return false;
1796}
1797
Mark Brown42aa3412009-03-01 19:21:10 +00001798/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001799 * Scan each dapm widget for complete audio path.
1800 * A complete path is a route that has valid endpoints i.e.:-
1801 *
1802 * o DAC to output pin.
1803 * o Input Pin to ADC.
1804 * o Input pin to Output pin (bypass, sidetone)
1805 * o DAC to ADC (loopback).
1806 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001807static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001808{
1809 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001810 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001811 LIST_HEAD(up_list);
1812 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001813 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001814 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001815
Mark Brownf9fa2b12014-03-06 16:49:11 +08001816 lockdep_assert_held(&card->dapm_mutex);
1817
Mark Brown84e90932010-11-04 00:07:02 -04001818 trace_snd_soc_dapm_start(card);
1819
Mark Brown56fba412011-06-04 11:25:10 +01001820 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001821 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001822 d->target_bias_level = SND_SOC_BIAS_OFF;
1823 else
1824 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001825 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001826
Liam Girdwood6c120e12012-02-15 15:15:34 +00001827 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001828
Mark Brown6d3ddc82009-05-16 17:47:29 +01001829 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001830 * lists indicating if they should be powered up or down. We
1831 * only check widgets that have been flagged as dirty but note
1832 * that new widgets may be added to the dirty list while we
1833 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001834 */
Mark Browndb432b42011-10-03 21:06:40 +01001835 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001836 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001837 }
1838
Mark Brownf9de6d72011-09-28 17:19:47 +01001839 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001840 switch (w->id) {
1841 case snd_soc_dapm_pre:
1842 case snd_soc_dapm_post:
1843 /* These widgets always need to be powered */
1844 break;
1845 default:
1846 list_del_init(&w->dirty);
1847 break;
1848 }
Mark Browndb432b42011-10-03 21:06:40 +01001849
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001850 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001851 d = w->dapm;
1852
1853 /* Supplies and micbiases only bring the
1854 * context up to STANDBY as unless something
1855 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001856 * generally don't require full power. Signal
1857 * generators are virtual pins and have no
1858 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001859 */
1860 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001861 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001862 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001863 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001864 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001865 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001866 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001867 case snd_soc_dapm_micbias:
1868 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1869 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1870 break;
1871 default:
1872 d->target_bias_level = SND_SOC_BIAS_ON;
1873 break;
1874 }
1875 }
1876
1877 }
1878
Mark Brown85a843c2011-09-21 21:29:47 +01001879 /* Force all contexts in the card to the same bias state if
1880 * they're not ground referenced.
1881 */
Mark Brown56fba412011-06-04 11:25:10 +01001882 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001883 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001884 if (d->target_bias_level > bias)
1885 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001886 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001887 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001888 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001889
Mark Brownde02d072011-09-20 21:43:24 +01001890 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001891
Xiang Xiao17282ba2014-03-02 00:04:03 +08001892 /* Run card bias changes at first */
1893 dapm_pre_sequence_async(&card->dapm, 0);
1894 /* Run other bias changes in parallel */
1895 list_for_each_entry(d, &card->dapm_list, list) {
1896 if (d != &card->dapm)
1897 async_schedule_domain(dapm_pre_sequence_async, d,
1898 &async_domain);
1899 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001900 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001901
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001902 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001903 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001904 }
1905
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001906 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001907 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001908 }
1909
Mark Brown6d3ddc82009-05-16 17:47:29 +01001910 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001911 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001912
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001913 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001914
Mark Brown6d3ddc82009-05-16 17:47:29 +01001915 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001916 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001917
Mark Brown9d0624a2011-02-18 11:49:43 -08001918 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001919 list_for_each_entry(d, &card->dapm_list, list) {
1920 if (d != &card->dapm)
1921 async_schedule_domain(dapm_post_sequence_async, d,
1922 &async_domain);
1923 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001924 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001925 /* Run card bias changes at last */
1926 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001927
Liam Girdwood8078d872012-02-15 15:15:35 +00001928 /* do we need to notify any clients that DAPM event is complete */
1929 list_for_each_entry(d, &card->dapm_list, list) {
1930 if (d->stream_event)
1931 d->stream_event(d, event);
1932 }
1933
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001934 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001935 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001936 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001937
Mark Brown84e90932010-11-04 00:07:02 -04001938 trace_snd_soc_dapm_done(card);
1939
Mark Brown42aa3412009-03-01 19:21:10 +00001940 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001941}
1942
Mark Brown79fb9382009-08-21 16:38:13 +01001943#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001944static ssize_t dapm_widget_power_read_file(struct file *file,
1945 char __user *user_buf,
1946 size_t count, loff_t *ppos)
1947{
1948 struct snd_soc_dapm_widget *w = file->private_data;
1949 char *buf;
1950 int in, out;
1951 ssize_t ret;
1952 struct snd_soc_dapm_path *p = NULL;
1953
1954 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1955 if (!buf)
1956 return -ENOMEM;
1957
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001958 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
1959 if (w->is_supply) {
1960 in = 0;
1961 out = 0;
1962 } else {
1963 in = is_connected_input_ep(w, NULL);
1964 out = is_connected_output_ep(w, NULL);
1965 }
Mark Brown79fb9382009-08-21 16:38:13 +01001966
Mark Brownf13ebad2012-03-03 18:01:01 +00001967 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1968 w->name, w->power ? "On" : "Off",
1969 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001970
Mark Brownd033c362009-12-04 15:25:56 +00001971 if (w->reg >= 0)
1972 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001973 " - R%d(0x%x) mask 0x%x",
1974 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00001975
1976 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1977
Mark Brown3eef08b2009-09-14 16:49:00 +01001978 if (w->sname)
1979 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1980 w->sname,
1981 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001982
1983 list_for_each_entry(p, &w->sources, list_sink) {
Takashi Iwaiff186202013-10-28 14:21:49 +01001984 if (p->connected && !p->connected(w, p->source))
Mark Brown215edda2009-09-08 18:59:05 +01001985 continue;
1986
Mark Brown79fb9382009-08-21 16:38:13 +01001987 if (p->connect)
1988 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001989 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001990 p->name ? p->name : "static",
1991 p->source->name);
1992 }
1993 list_for_each_entry(p, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001994 if (p->connected && !p->connected(w, p->sink))
1995 continue;
1996
Mark Brown79fb9382009-08-21 16:38:13 +01001997 if (p->connect)
1998 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001999 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01002000 p->name ? p->name : "static",
2001 p->sink->name);
2002 }
2003
2004 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
2005
2006 kfree(buf);
2007 return ret;
2008}
2009
2010static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002011 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01002012 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002013 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01002014};
2015
Mark Brownef49e4f2011-04-04 20:48:13 +09002016static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
2017 size_t count, loff_t *ppos)
2018{
2019 struct snd_soc_dapm_context *dapm = file->private_data;
2020 char *level;
2021
2022 switch (dapm->bias_level) {
2023 case SND_SOC_BIAS_ON:
2024 level = "On\n";
2025 break;
2026 case SND_SOC_BIAS_PREPARE:
2027 level = "Prepare\n";
2028 break;
2029 case SND_SOC_BIAS_STANDBY:
2030 level = "Standby\n";
2031 break;
2032 case SND_SOC_BIAS_OFF:
2033 level = "Off\n";
2034 break;
2035 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002036 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002037 level = "Unknown\n";
2038 break;
2039 }
2040
2041 return simple_read_from_buffer(user_buf, count, ppos, level,
2042 strlen(level));
2043}
2044
2045static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002046 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002047 .read = dapm_bias_read_file,
2048 .llseek = default_llseek,
2049};
2050
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002051void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2052 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002053{
Mark Brown79fb9382009-08-21 16:38:13 +01002054 struct dentry *d;
2055
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002056 if (!parent)
2057 return;
2058
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002059 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2060
2061 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002062 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002063 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002064 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002065 }
Mark Brown79fb9382009-08-21 16:38:13 +01002066
Mark Brownef49e4f2011-04-04 20:48:13 +09002067 d = debugfs_create_file("bias_level", 0444,
2068 dapm->debugfs_dapm, dapm,
2069 &dapm_bias_fops);
2070 if (!d)
2071 dev_warn(dapm->dev,
2072 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002073}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002074
2075static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2076{
2077 struct snd_soc_dapm_context *dapm = w->dapm;
2078 struct dentry *d;
2079
2080 if (!dapm->debugfs_dapm || !w->name)
2081 return;
2082
2083 d = debugfs_create_file(w->name, 0444,
2084 dapm->debugfs_dapm, w,
2085 &dapm_widget_power_fops);
2086 if (!d)
2087 dev_warn(w->dapm->dev,
2088 "ASoC: Failed to create %s debugfs file\n",
2089 w->name);
2090}
2091
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002092static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2093{
2094 debugfs_remove_recursive(dapm->debugfs_dapm);
2095}
2096
Mark Brown79fb9382009-08-21 16:38:13 +01002097#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002098void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2099 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002100{
2101}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002102
2103static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2104{
2105}
2106
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002107static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2108{
2109}
2110
Mark Brown79fb9382009-08-21 16:38:13 +01002111#endif
2112
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002113/*
2114 * soc_dapm_connect_path() - Connects or disconnects a path
2115 * @path: The path to update
2116 * @connect: The new connect state of the path. True if the path is connected,
2117 * false if it is disconneted.
2118 * @reason: The reason why the path changed (for debugging only)
2119 */
2120static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2121 bool connect, const char *reason)
2122{
2123 if (path->connect == connect)
2124 return;
2125
2126 path->connect = connect;
2127 dapm_mark_dirty(path->source, reason);
2128 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002129 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002130}
2131
Richard Purdie2b97eab2006-10-06 18:32:18 +02002132/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002133static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002134 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002135{
2136 struct snd_soc_dapm_path *path;
2137 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002138 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002139
Mark Brownf9fa2b12014-03-06 16:49:11 +08002140 lockdep_assert_held(&card->dapm_mutex);
2141
Richard Purdie2b97eab2006-10-06 18:32:18 +02002142 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002143 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002144 found = 1;
2145 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002146 if (!(strcmp(path->name, e->texts[mux])))
2147 connect = true;
2148 else
2149 connect = false;
2150
2151 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002152 }
2153
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002154 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002155 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002156
Liam Girdwood618dae12012-04-25 12:12:51 +01002157 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002158}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002159
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002160int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002161 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2162 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002163{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002164 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002165 int ret;
2166
Liam Girdwood3cd04342012-03-09 12:02:08 +00002167 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002168 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002169 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002170 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002171 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002172 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002173 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002174 return ret;
2175}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002176EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002177
Milan plzik1b075e32008-01-10 14:39:46 +01002178/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002179static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Mark Brown283375c2009-12-07 18:09:03 +00002180 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002181{
2182 struct snd_soc_dapm_path *path;
2183 int found = 0;
2184
Mark Brownf9fa2b12014-03-06 16:49:11 +08002185 lockdep_assert_held(&card->dapm_mutex);
2186
Richard Purdie2b97eab2006-10-06 18:32:18 +02002187 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002188 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002189 found = 1;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002190 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002191 }
2192
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002193 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002194 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002195
Liam Girdwood618dae12012-04-25 12:12:51 +01002196 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002197}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002198
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002199int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002200 struct snd_kcontrol *kcontrol, int connect,
2201 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002202{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002203 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002204 int ret;
2205
Liam Girdwood3cd04342012-03-09 12:02:08 +00002206 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002207 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002208 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002209 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002210 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002211 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002212 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002213 return ret;
2214}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002215EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002216
Benoit Cousson44ba2642014-07-08 23:19:36 +02002217static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002218{
Richard Purdie2b97eab2006-10-06 18:32:18 +02002219 struct snd_soc_dapm_widget *w;
2220 int count = 0;
2221 char *state = "not set";
2222
Lars-Peter Clausen00200102014-07-17 22:01:07 +02002223 list_for_each_entry(w, &codec->component.card->widgets, list) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002224 if (w->dapm != &codec->dapm)
2225 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002226
2227 /* only display widgets that burnm power */
2228 switch (w->id) {
2229 case snd_soc_dapm_hp:
2230 case snd_soc_dapm_mic:
2231 case snd_soc_dapm_spk:
2232 case snd_soc_dapm_line:
2233 case snd_soc_dapm_micbias:
2234 case snd_soc_dapm_dac:
2235 case snd_soc_dapm_adc:
2236 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002237 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002238 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002239 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002240 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002241 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002242 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002243 if (w->name)
2244 count += sprintf(buf + count, "%s: %s\n",
2245 w->name, w->power ? "On":"Off");
2246 break;
2247 default:
2248 break;
2249 }
2250 }
2251
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002252 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02002253 case SND_SOC_BIAS_ON:
2254 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002255 break;
Mark Brown0be98982008-05-19 12:31:28 +02002256 case SND_SOC_BIAS_PREPARE:
2257 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002258 break;
Mark Brown0be98982008-05-19 12:31:28 +02002259 case SND_SOC_BIAS_STANDBY:
2260 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002261 break;
Mark Brown0be98982008-05-19 12:31:28 +02002262 case SND_SOC_BIAS_OFF:
2263 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002264 break;
2265 }
2266 count += sprintf(buf + count, "PM State: %s\n", state);
2267
2268 return count;
2269}
2270
Benoit Cousson44ba2642014-07-08 23:19:36 +02002271/* show dapm widget status in sys fs */
2272static ssize_t dapm_widget_show(struct device *dev,
2273 struct device_attribute *attr, char *buf)
2274{
2275 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2276 int i, count = 0;
2277
2278 for (i = 0; i < rtd->num_codecs; i++) {
2279 struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
2280 count += dapm_widget_show_codec(codec, buf + count);
2281 }
2282
2283 return count;
2284}
2285
Richard Purdie2b97eab2006-10-06 18:32:18 +02002286static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2287
Takashi Iwaid29697d2015-01-30 20:16:37 +01002288struct attribute *soc_dapm_dev_attrs[] = {
2289 &dev_attr_dapm_widget.attr,
2290 NULL
2291};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002292
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002293static void dapm_free_path(struct snd_soc_dapm_path *path)
2294{
2295 list_del(&path->list_sink);
2296 list_del(&path->list_source);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002297 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002298 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002299 kfree(path);
2300}
2301
Richard Purdie2b97eab2006-10-06 18:32:18 +02002302/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002303static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002304{
2305 struct snd_soc_dapm_widget *w, *next_w;
2306 struct snd_soc_dapm_path *p, *next_p;
2307
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002308 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2309 if (w->dapm != dapm)
2310 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002311 list_del(&w->list);
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002312 /*
2313 * remove source and sink paths associated to this widget.
2314 * While removing the path, remove reference to it from both
2315 * source and sink widgets so that path is removed only once.
2316 */
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002317 list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
2318 dapm_free_path(p);
2319
2320 list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
2321 dapm_free_path(p);
2322
Stephen Warrenfad59882011-04-28 17:37:59 -06002323 kfree(w->kcontrols);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002324 kfree(w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002325 kfree(w);
2326 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002327}
2328
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002329static struct snd_soc_dapm_widget *dapm_find_widget(
2330 struct snd_soc_dapm_context *dapm, const char *pin,
2331 bool search_other_contexts)
2332{
2333 struct snd_soc_dapm_widget *w;
2334 struct snd_soc_dapm_widget *fallback = NULL;
2335
2336 list_for_each_entry(w, &dapm->card->widgets, list) {
2337 if (!strcmp(w->name, pin)) {
2338 if (w->dapm == dapm)
2339 return w;
2340 else
2341 fallback = w;
2342 }
2343 }
2344
2345 if (search_other_contexts)
2346 return fallback;
2347
2348 return NULL;
2349}
2350
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002351static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002352 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002353{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002354 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002355
Mark Brownf9fa2b12014-03-06 16:49:11 +08002356 dapm_assert_locked(dapm);
2357
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002358 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002359 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002360 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002361 }
2362
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002363 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002364 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002365 dapm_widget_invalidate_input_paths(w);
2366 dapm_widget_invalidate_output_paths(w);
2367 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002368
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002369 w->connected = status;
2370 if (status == 0)
2371 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002372
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002373 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002374}
2375
Richard Purdie2b97eab2006-10-06 18:32:18 +02002376/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002377 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2378 * @dapm: DAPM context
2379 *
2380 * Walks all dapm audio paths and powers widgets according to their
2381 * stream or path usage.
2382 *
2383 * Requires external locking.
2384 *
2385 * Returns 0 for success.
2386 */
2387int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2388{
2389 /*
2390 * Suppress early reports (eg, jacks syncing their state) to avoid
2391 * silly DAPM runs during card startup.
2392 */
2393 if (!dapm->card || !dapm->card->instantiated)
2394 return 0;
2395
2396 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2397}
2398EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2399
2400/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002401 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002402 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002403 *
2404 * Walks all dapm audio paths and powers widgets according to their
2405 * stream or path usage.
2406 *
2407 * Returns 0 for success.
2408 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002409int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002410{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002411 int ret;
2412
Liam Girdwood3cd04342012-03-09 12:02:08 +00002413 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002414 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002415 mutex_unlock(&dapm->card->dapm_mutex);
2416 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002417}
Liam Girdwooda5302182008-07-07 13:35:17 +01002418EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002419
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002420/*
2421 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2422 * @w: The widget for which to update the flags
2423 *
2424 * Some widgets have a dynamic category which depends on which neighbors they
2425 * are connected to. This function update the category for these widgets.
2426 *
2427 * This function must be called whenever a path is added or removed to a widget.
2428 */
2429static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2430{
2431 struct snd_soc_dapm_path *p;
2432
2433 switch (w->id) {
2434 case snd_soc_dapm_input:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002435 /* On a fully routed card a input is never a source */
2436 if (w->dapm->card->fully_routed)
2437 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002438 w->is_source = 1;
2439 list_for_each_entry(p, &w->sources, list_sink) {
2440 if (p->source->id == snd_soc_dapm_micbias ||
2441 p->source->id == snd_soc_dapm_mic ||
2442 p->source->id == snd_soc_dapm_line ||
2443 p->source->id == snd_soc_dapm_output) {
2444 w->is_source = 0;
2445 break;
2446 }
2447 }
2448 break;
2449 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002450 /* On a fully routed card a output is never a sink */
2451 if (w->dapm->card->fully_routed)
2452 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002453 w->is_sink = 1;
2454 list_for_each_entry(p, &w->sinks, list_source) {
2455 if (p->sink->id == snd_soc_dapm_spk ||
2456 p->sink->id == snd_soc_dapm_hp ||
2457 p->sink->id == snd_soc_dapm_line ||
2458 p->sink->id == snd_soc_dapm_input) {
2459 w->is_sink = 0;
2460 break;
2461 }
2462 }
2463 break;
2464 case snd_soc_dapm_line:
2465 w->is_sink = !list_empty(&w->sources);
2466 w->is_source = !list_empty(&w->sinks);
2467 break;
2468 default:
2469 break;
2470 }
2471}
2472
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002473static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2474 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2475 const char *control)
2476{
2477 bool dynamic_source = false;
2478 bool dynamic_sink = false;
2479
2480 if (!control)
2481 return 0;
2482
2483 switch (source->id) {
2484 case snd_soc_dapm_demux:
2485 dynamic_source = true;
2486 break;
2487 default:
2488 break;
2489 }
2490
2491 switch (sink->id) {
2492 case snd_soc_dapm_mux:
2493 case snd_soc_dapm_switch:
2494 case snd_soc_dapm_mixer:
2495 case snd_soc_dapm_mixer_named_ctl:
2496 dynamic_sink = true;
2497 break;
2498 default:
2499 break;
2500 }
2501
2502 if (dynamic_source && dynamic_sink) {
2503 dev_err(dapm->dev,
2504 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2505 source->name, control, sink->name);
2506 return -EINVAL;
2507 } else if (!dynamic_source && !dynamic_sink) {
2508 dev_err(dapm->dev,
2509 "Control not supported for path %s -> [%s] -> %s\n",
2510 source->name, control, sink->name);
2511 return -EINVAL;
2512 }
2513
2514 return 0;
2515}
2516
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002517static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2518 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2519 const char *control,
2520 int (*connected)(struct snd_soc_dapm_widget *source,
2521 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002522{
2523 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002524 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002525
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002526 if (wsink->is_supply && !wsource->is_supply) {
2527 dev_err(dapm->dev,
2528 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2529 wsource->name, wsink->name);
2530 return -EINVAL;
2531 }
2532
2533 if (connected && !wsource->is_supply) {
2534 dev_err(dapm->dev,
2535 "connected() callback only supported for supply widgets (%s -> %s)\n",
2536 wsource->name, wsink->name);
2537 return -EINVAL;
2538 }
2539
2540 if (wsource->is_supply && control) {
2541 dev_err(dapm->dev,
2542 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2543 wsource->name, control, wsink->name);
2544 return -EINVAL;
2545 }
2546
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002547 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2548 if (ret)
2549 return ret;
2550
Richard Purdie2b97eab2006-10-06 18:32:18 +02002551 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2552 if (!path)
2553 return -ENOMEM;
2554
2555 path->source = wsource;
2556 path->sink = wsink;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002557 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002558 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002559 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002560 INIT_LIST_HEAD(&path->list_source);
2561 INIT_LIST_HEAD(&path->list_sink);
2562
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002563 if (wsource->is_supply || wsink->is_supply)
2564 path->is_supply = 1;
2565
Richard Purdie2b97eab2006-10-06 18:32:18 +02002566 /* connect static paths */
2567 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002568 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002569 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002570 switch (wsource->id) {
2571 case snd_soc_dapm_demux:
2572 ret = dapm_connect_mux(dapm, path, control, wsource);
2573 if (ret)
2574 goto err;
2575 break;
2576 default:
2577 break;
2578 }
2579
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002580 switch (wsink->id) {
2581 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002582 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002583 if (ret != 0)
2584 goto err;
2585 break;
2586 case snd_soc_dapm_switch:
2587 case snd_soc_dapm_mixer:
2588 case snd_soc_dapm_mixer_named_ctl:
2589 ret = dapm_connect_mixer(dapm, path, control);
2590 if (ret != 0)
2591 goto err;
2592 break;
2593 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002594 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002595 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002596 }
2597
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002598 list_add(&path->list, &dapm->card->paths);
2599 list_add(&path->list_sink, &wsink->sources);
2600 list_add(&path->list_source, &wsource->sinks);
2601
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002602 dapm_update_widget_flags(wsource);
2603 dapm_update_widget_flags(wsink);
2604
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002605 dapm_mark_dirty(wsource, "Route added");
2606 dapm_mark_dirty(wsink, "Route added");
Mark Brownfabd0382012-07-05 17:20:06 +01002607
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002608 if (dapm->card->instantiated && path->connect)
2609 dapm_path_invalidate(path);
2610
Richard Purdie2b97eab2006-10-06 18:32:18 +02002611 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002612err:
2613 kfree(path);
2614 return ret;
2615}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002616
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002617static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002618 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002619{
2620 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2621 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2622 const char *sink;
2623 const char *source;
2624 char prefixed_sink[80];
2625 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002626 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002627 int ret;
2628
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002629 prefix = soc_dapm_prefix(dapm);
2630 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002631 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002632 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002633 sink = prefixed_sink;
2634 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002635 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002636 source = prefixed_source;
2637 } else {
2638 sink = route->sink;
2639 source = route->source;
2640 }
2641
Charles Keepax45a110a2015-05-11 13:50:30 +01002642 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2643 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2644
2645 if (wsink && wsource)
2646 goto skip_search;
2647
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002648 /*
2649 * find src and dest widgets over all widgets but favor a widget from
2650 * current DAPM context
2651 */
2652 list_for_each_entry(w, &dapm->card->widgets, list) {
2653 if (!wsink && !(strcmp(w->name, sink))) {
2654 wtsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002655 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002656 wsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002657 if (wsource)
2658 break;
2659 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002660 continue;
2661 }
2662 if (!wsource && !(strcmp(w->name, source))) {
2663 wtsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002664 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002665 wsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002666 if (wsink)
2667 break;
2668 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002669 }
2670 }
2671 /* use widget from another DAPM context if not found from this */
2672 if (!wsink)
2673 wsink = wtsink;
2674 if (!wsource)
2675 wsource = wtsource;
2676
2677 if (wsource == NULL) {
2678 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2679 route->source);
2680 return -ENODEV;
2681 }
2682 if (wsink == NULL) {
2683 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2684 route->sink);
2685 return -ENODEV;
2686 }
2687
Charles Keepax45a110a2015-05-11 13:50:30 +01002688skip_search:
2689 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2690 dapm_wcache_update(&dapm->path_source_cache, wsource);
2691
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002692 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2693 route->connected);
2694 if (ret)
2695 goto err;
2696
2697 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002698err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002699 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002700 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002701 return ret;
2702}
Mark Brown105f1c22008-05-13 14:52:19 +02002703
Mark Brownefcc3c62012-07-05 17:24:19 +01002704static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2705 const struct snd_soc_dapm_route *route)
2706{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002707 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002708 struct snd_soc_dapm_path *path, *p;
2709 const char *sink;
2710 const char *source;
2711 char prefixed_sink[80];
2712 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002713 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002714
2715 if (route->control) {
2716 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002717 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002718 return -EINVAL;
2719 }
2720
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002721 prefix = soc_dapm_prefix(dapm);
2722 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002723 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002724 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002725 sink = prefixed_sink;
2726 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002727 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002728 source = prefixed_source;
2729 } else {
2730 sink = route->sink;
2731 source = route->source;
2732 }
2733
2734 path = NULL;
2735 list_for_each_entry(p, &dapm->card->paths, list) {
2736 if (strcmp(p->source->name, source) != 0)
2737 continue;
2738 if (strcmp(p->sink->name, sink) != 0)
2739 continue;
2740 path = p;
2741 break;
2742 }
2743
2744 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002745 wsource = path->source;
2746 wsink = path->sink;
2747
2748 dapm_mark_dirty(wsource, "Route removed");
2749 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002750 if (path->connect)
2751 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002752
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002753 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002754
2755 /* Update any path related flags */
2756 dapm_update_widget_flags(wsource);
2757 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002758 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002759 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002760 source, sink);
2761 }
2762
2763 return 0;
2764}
2765
Mark Brown105f1c22008-05-13 14:52:19 +02002766/**
Mark Brown105f1c22008-05-13 14:52:19 +02002767 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002768 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002769 * @route: audio routes
2770 * @num: number of routes
2771 *
2772 * Connects 2 dapm widgets together via a named audio path. The sink is
2773 * the widget receiving the audio signal, whilst the source is the sender
2774 * of the audio signal.
2775 *
2776 * Returns 0 for success else error. On error all resources can be freed
2777 * with a call to snd_soc_card_free().
2778 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002779int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002780 const struct snd_soc_dapm_route *route, int num)
2781{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002782 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002783
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002784 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002785 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002786 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002787 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002788 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2789 route->source,
2790 route->control ? route->control : "direct",
2791 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002792 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002793 }
2794 route++;
2795 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002796 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002797
Dan Carpenter60884c22012-04-13 22:25:43 +03002798 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002799}
2800EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2801
Mark Brownefcc3c62012-07-05 17:24:19 +01002802/**
2803 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2804 * @dapm: DAPM context
2805 * @route: audio routes
2806 * @num: number of routes
2807 *
2808 * Removes routes from the DAPM context.
2809 */
2810int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2811 const struct snd_soc_dapm_route *route, int num)
2812{
2813 int i, ret = 0;
2814
2815 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2816 for (i = 0; i < num; i++) {
2817 snd_soc_dapm_del_route(dapm, route);
2818 route++;
2819 }
2820 mutex_unlock(&dapm->card->dapm_mutex);
2821
2822 return ret;
2823}
2824EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2825
Mark Brownbf3a9e12011-06-13 16:42:29 +01002826static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2827 const struct snd_soc_dapm_route *route)
2828{
2829 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2830 route->source,
2831 true);
2832 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2833 route->sink,
2834 true);
2835 struct snd_soc_dapm_path *path;
2836 int count = 0;
2837
2838 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002839 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002840 route->source);
2841 return -ENODEV;
2842 }
2843
2844 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002845 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002846 route->sink);
2847 return -ENODEV;
2848 }
2849
2850 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002851 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002852 route->source, route->sink);
2853
2854 list_for_each_entry(path, &source->sinks, list_source) {
2855 if (path->sink == sink) {
2856 path->weak = 1;
2857 count++;
2858 }
2859 }
2860
2861 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002862 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002863 route->source, route->sink);
2864 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002865 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002866 count, route->source, route->sink);
2867
2868 return 0;
2869}
2870
2871/**
2872 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2873 * @dapm: DAPM context
2874 * @route: audio routes
2875 * @num: number of routes
2876 *
2877 * Mark existing routes matching those specified in the passed array
2878 * as being weak, meaning that they are ignored for the purpose of
2879 * power decisions. The main intended use case is for sidetone paths
2880 * which couple audio between other independent paths if they are both
2881 * active in order to make the combination work better at the user
2882 * level but which aren't intended to be "used".
2883 *
2884 * Note that CODEC drivers should not use this as sidetone type paths
2885 * can frequently also be used as bypass paths.
2886 */
2887int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2888 const struct snd_soc_dapm_route *route, int num)
2889{
2890 int i, err;
2891 int ret = 0;
2892
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002893 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002894 for (i = 0; i < num; i++) {
2895 err = snd_soc_dapm_weak_route(dapm, route);
2896 if (err)
2897 ret = err;
2898 route++;
2899 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002900 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002901
2902 return ret;
2903}
2904EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2905
Mark Brown105f1c22008-05-13 14:52:19 +02002906/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002907 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002908 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002909 *
2910 * Checks the codec for any new dapm widgets and creates them if found.
2911 *
2912 * Returns 0 for success.
2913 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02002914int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002915{
2916 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002917 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002918
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002919 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002920
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002921 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002922 {
2923 if (w->new)
2924 continue;
2925
Stephen Warrenfad59882011-04-28 17:37:59 -06002926 if (w->num_kcontrols) {
2927 w->kcontrols = kzalloc(w->num_kcontrols *
2928 sizeof(struct snd_kcontrol *),
2929 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002930 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002931 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002932 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002933 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002934 }
2935
Richard Purdie2b97eab2006-10-06 18:32:18 +02002936 switch(w->id) {
2937 case snd_soc_dapm_switch:
2938 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002939 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002940 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002941 break;
2942 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002943 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002944 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002945 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002946 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002947 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002948 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002949 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00002950 case snd_soc_dapm_dai_link:
2951 dapm_new_dai_link(w);
2952 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002953 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002954 break;
2955 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002956
2957 /* Read the initial power state from the device */
2958 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002959 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08002960 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002961 val &= w->mask;
2962 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00002963 w->power = 1;
2964 }
2965
Richard Purdie2b97eab2006-10-06 18:32:18 +02002966 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002967
Mark Brown7508b122011-10-05 12:09:12 +01002968 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002969 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002970 }
2971
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002972 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2973 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002974 return 0;
2975}
2976EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2977
2978/**
2979 * snd_soc_dapm_get_volsw - dapm mixer get callback
2980 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002981 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002982 *
2983 * Callback to get the value of a dapm mixer control.
2984 *
2985 * Returns 0 for success.
2986 */
2987int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2988 struct snd_ctl_elem_value *ucontrol)
2989{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002990 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2991 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002992 struct soc_mixer_control *mc =
2993 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002994 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002995 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002996 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002997 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002998 unsigned int invert = mc->invert;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002999 unsigned int val;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003000 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003001
3002 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003003 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003004 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003005 kcontrol->id.name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003006
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003007 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003008 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
3009 ret = soc_dapm_read(dapm, reg, &val);
3010 val = (val >> shift) & mask;
3011 } else {
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003012 val = dapm_kcontrol_get_value(kcontrol);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003013 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003014 mutex_unlock(&card->dapm_mutex);
3015
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003016 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003017 ucontrol->value.integer.value[0] = max - val;
3018 else
3019 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003020
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003021 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003022}
3023EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3024
3025/**
3026 * snd_soc_dapm_put_volsw - dapm mixer set callback
3027 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003028 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003029 *
3030 * Callback to set the value of a dapm mixer control.
3031 *
3032 * Returns 0 for success.
3033 */
3034int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3035 struct snd_ctl_elem_value *ucontrol)
3036{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003037 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3038 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003039 struct soc_mixer_control *mc =
3040 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003041 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003042 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003043 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003044 unsigned int mask = (1 << fls(max)) - 1;
3045 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07003046 unsigned int val;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003047 int connect, change, reg_change = 0;
Mark Brown97404f22010-12-14 16:13:57 +00003048 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003049 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003050
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003051 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003052 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003053 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003054 kcontrol->id.name);
3055
Richard Purdie2b97eab2006-10-06 18:32:18 +02003056 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003057 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003058
3059 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003060 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003061
Liam Girdwood3cd04342012-03-09 12:02:08 +00003062 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003063
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003064 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown283375c2009-12-07 18:09:03 +00003065
Jarkko Nikula18626c72014-06-09 14:20:29 +03003066 if (reg != SND_SOC_NOPM) {
3067 mask = mask << shift;
3068 val = val << shift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003069
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003070 reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003071 }
3072
3073 if (change || reg_change) {
3074 if (reg_change) {
3075 update.kcontrol = kcontrol;
3076 update.reg = reg;
3077 update.mask = mask;
3078 update.val = val;
3079 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003080 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003081 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003082
Nenghua Cao52765972013-12-13 20:13:49 +08003083 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Mark Brown97404f22010-12-14 16:13:57 +00003084
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003085 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003086 }
3087
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003088 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003089
3090 if (ret > 0)
3091 soc_dpcm_runtime_update(card);
3092
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003093 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003094}
3095EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3096
3097/**
3098 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3099 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003100 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003101 *
3102 * Callback to get the value of a dapm enumerated double mixer control.
3103 *
3104 * Returns 0 for success.
3105 */
3106int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3107 struct snd_ctl_elem_value *ucontrol)
3108{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003109 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003110 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003111 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003112 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003113
Charles Keepax561ed682015-05-01 12:37:26 +01003114 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3115 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003116 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003117 if (ret) {
3118 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003119 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003120 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003121 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003122 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003123 }
Charles Keepax561ed682015-05-01 12:37:26 +01003124 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003125
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003126 val = (reg_val >> e->shift_l) & e->mask;
3127 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3128 if (e->shift_l != e->shift_r) {
3129 val = (reg_val >> e->shift_r) & e->mask;
3130 val = snd_soc_enum_val_to_item(e, val);
3131 ucontrol->value.enumerated.item[1] = val;
3132 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003133
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003134 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003135}
3136EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3137
3138/**
3139 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3140 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003141 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003142 *
3143 * Callback to set the value of a dapm enumerated double mixer control.
3144 *
3145 * Returns 0 for success.
3146 */
3147int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3148 struct snd_ctl_elem_value *ucontrol)
3149{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003150 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3151 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003152 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003153 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003154 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003155 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00003156 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003157 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003158
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003159 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003160 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003161
3162 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003163 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003164 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003165 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003166 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003167 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003168 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003169 }
3170
Liam Girdwood3cd04342012-03-09 12:02:08 +00003171 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003172
Charles Keepax561ed682015-05-01 12:37:26 +01003173 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003174
Charles Keepax561ed682015-05-01 12:37:26 +01003175 if (e->reg != SND_SOC_NOPM)
3176 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3177
3178 if (change || reg_change) {
3179 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003180 update.kcontrol = kcontrol;
3181 update.reg = e->reg;
3182 update.mask = mask;
3183 update.val = val;
3184 card->update = &update;
3185 }
Charles Keepax561ed682015-05-01 12:37:26 +01003186 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003187
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003188 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003189
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003190 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003191 }
3192
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003193 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003194
3195 if (ret > 0)
3196 soc_dpcm_runtime_update(card);
3197
Mark Brown97404f22010-12-14 16:13:57 +00003198 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003199}
3200EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3201
3202/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003203 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3204 *
3205 * @kcontrol: mixer control
3206 * @uinfo: control element information
3207 *
3208 * Callback to provide information about a pin switch control.
3209 */
3210int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3211 struct snd_ctl_elem_info *uinfo)
3212{
3213 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3214 uinfo->count = 1;
3215 uinfo->value.integer.min = 0;
3216 uinfo->value.integer.max = 1;
3217
3218 return 0;
3219}
3220EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3221
3222/**
3223 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3224 *
3225 * @kcontrol: mixer control
3226 * @ucontrol: Value
3227 */
3228int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3229 struct snd_ctl_elem_value *ucontrol)
3230{
Mark Brown48a8c392012-02-14 17:11:15 -08003231 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003232 const char *pin = (const char *)kcontrol->private_value;
3233
Liam Girdwood3cd04342012-03-09 12:02:08 +00003234 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003235
3236 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003237 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003238
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003239 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003240
3241 return 0;
3242}
3243EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3244
3245/**
3246 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3247 *
3248 * @kcontrol: mixer control
3249 * @ucontrol: Value
3250 */
3251int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3252 struct snd_ctl_elem_value *ucontrol)
3253{
Mark Brown48a8c392012-02-14 17:11:15 -08003254 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003255 const char *pin = (const char *)kcontrol->private_value;
3256
Mark Brown8b37dbd2009-02-28 21:14:20 +00003257 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003258 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003259 else
Mark Brown48a8c392012-02-14 17:11:15 -08003260 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003261
Mark Brown48a8c392012-02-14 17:11:15 -08003262 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003263 return 0;
3264}
3265EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3266
Mark Brown5ba06fc2012-02-16 11:07:13 -08003267static struct snd_soc_dapm_widget *
3268snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3269 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003270{
3271 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003272 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003273 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003274
3275 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003276 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003277
Mark Brown62ea8742012-01-21 21:14:48 +00003278 switch (w->id) {
3279 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003280 w->regulator = devm_regulator_get(dapm->dev, w->name);
3281 if (IS_ERR(w->regulator)) {
3282 ret = PTR_ERR(w->regulator);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003283 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003284 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003285 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003286 }
Mark Brown8784c772013-01-10 19:33:47 +00003287
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003288 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003289 ret = regulator_allow_bypass(w->regulator, true);
3290 if (ret != 0)
3291 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003292 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003293 w->name, ret);
3294 }
Mark Brown62ea8742012-01-21 21:14:48 +00003295 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003296 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003297#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003298 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003299 if (IS_ERR(w->clk)) {
3300 ret = PTR_ERR(w->clk);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003301 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003302 w->name, ret);
3303 return NULL;
3304 }
Mark Brownec029952012-06-04 08:16:20 +01003305#else
3306 return NULL;
3307#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003308 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003309 default:
3310 break;
3311 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003312
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003313 prefix = soc_dapm_prefix(dapm);
3314 if (prefix)
3315 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausen2b581072013-05-14 11:05:32 +02003316 else
3317 w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
3318
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003319 if (w->name == NULL) {
3320 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003321 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003322 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003323
Mark Brown7ca3a182011-10-08 14:04:50 +01003324 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003325 case snd_soc_dapm_mic:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003326 w->is_source = 1;
3327 w->power_check = dapm_generic_check_power;
3328 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003329 case snd_soc_dapm_input:
3330 if (!dapm->card->fully_routed)
3331 w->is_source = 1;
3332 w->power_check = dapm_generic_check_power;
3333 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003334 case snd_soc_dapm_spk:
3335 case snd_soc_dapm_hp:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003336 w->is_sink = 1;
3337 w->power_check = dapm_generic_check_power;
3338 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003339 case snd_soc_dapm_output:
3340 if (!dapm->card->fully_routed)
3341 w->is_sink = 1;
3342 w->power_check = dapm_generic_check_power;
3343 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003344 case snd_soc_dapm_vmid:
3345 case snd_soc_dapm_siggen:
3346 w->is_source = 1;
3347 w->power_check = dapm_always_on_check_power;
3348 break;
3349 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003350 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003351 case snd_soc_dapm_switch:
3352 case snd_soc_dapm_mixer:
3353 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003354 case snd_soc_dapm_adc:
3355 case snd_soc_dapm_aif_out:
3356 case snd_soc_dapm_dac:
3357 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003358 case snd_soc_dapm_pga:
3359 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003360 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003361 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003362 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003363 case snd_soc_dapm_dai_out:
3364 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003365 w->power_check = dapm_generic_check_power;
3366 break;
3367 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003368 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003369 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003370 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003371 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003372 w->power_check = dapm_supply_check_power;
3373 break;
3374 default:
3375 w->power_check = dapm_always_on_check_power;
3376 break;
3377 }
3378
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003379 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003380 INIT_LIST_HEAD(&w->sources);
3381 INIT_LIST_HEAD(&w->sinks);
3382 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003383 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003384 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003385
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003386 w->inputs = -1;
3387 w->outputs = -1;
3388
Richard Purdie2b97eab2006-10-06 18:32:18 +02003389 /* machine layer set ups unconnected pins and insertions */
3390 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003391 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003392}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003393
3394/**
Mark Brown4ba13272008-05-13 14:51:19 +02003395 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003396 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003397 * @widget: widget array
3398 * @num: number of widgets
3399 *
3400 * Creates new DAPM controls based upon the templates.
3401 *
3402 * Returns 0 for success else error.
3403 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003404int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003405 const struct snd_soc_dapm_widget *widget,
3406 int num)
3407{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003408 struct snd_soc_dapm_widget *w;
3409 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003410 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003411
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003412 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003413 for (i = 0; i < num; i++) {
Mark Brown5ba06fc2012-02-16 11:07:13 -08003414 w = snd_soc_dapm_new_control(dapm, widget);
3415 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003416 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003417 "ASoC: Failed to create DAPM control %s\n",
3418 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003419 ret = -ENOMEM;
3420 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003421 }
Mark Brown4ba13272008-05-13 14:51:19 +02003422 widget++;
3423 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003424 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003425 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003426}
3427EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3428
Mark Brownc74184e2012-04-04 22:12:09 +01003429static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3430 struct snd_kcontrol *kcontrol, int event)
3431{
3432 struct snd_soc_dapm_path *source_p, *sink_p;
3433 struct snd_soc_dai *source, *sink;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003434 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003435 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003436 struct snd_pcm_hw_params *params = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003437 u64 fmt;
3438 int ret;
3439
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003440 if (WARN_ON(!config) ||
3441 WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
3442 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003443
3444 /* We only support a single source and sink, pick the first */
3445 source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
3446 list_sink);
3447 sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
3448 list_source);
3449
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003450 if (WARN_ON(!source_p || !sink_p) ||
3451 WARN_ON(!sink_p->source || !source_p->sink) ||
3452 WARN_ON(!source_p->source || !sink_p->sink))
3453 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003454
3455 source = source_p->source->priv;
3456 sink = sink_p->sink->priv;
3457
3458 /* Be a little careful as we don't want to overflow the mask array */
3459 if (config->formats) {
3460 fmt = ffs(config->formats) - 1;
3461 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003462 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003463 config->formats);
3464 fmt = 0;
3465 }
3466
3467 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003468 params = kzalloc(sizeof(*params), GFP_KERNEL);
3469 if (!params) {
3470 ret = -ENOMEM;
3471 goto out;
3472 }
3473 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003474
Mark Brown9747cec2012-04-26 19:12:21 +01003475 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003476 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003477 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003478 config->rate_max;
3479
Mark Brown9747cec2012-04-26 19:12:21 +01003480 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003481 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003482 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003483 = config->channels_max;
3484
3485 memset(&substream, 0, sizeof(substream));
3486
3487 switch (event) {
3488 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003489 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3490 ret = soc_dai_hw_params(&substream, params, source);
3491 if (ret < 0)
3492 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003493
Benoit Cousson93e69582014-07-08 23:19:38 +02003494 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3495 ret = soc_dai_hw_params(&substream, params, sink);
3496 if (ret < 0)
3497 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003498 break;
3499
3500 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003501 ret = snd_soc_dai_digital_mute(sink, 0,
3502 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003503 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003504 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003505 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003506 break;
3507
3508 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003509 ret = snd_soc_dai_digital_mute(sink, 1,
3510 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003511 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003512 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003513 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003514 break;
3515
3516 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003517 WARN(1, "Unknown event %d\n", event);
Mark Brownc74184e2012-04-04 22:12:09 +01003518 return -EINVAL;
3519 }
3520
Mark Brown9747cec2012-04-26 19:12:21 +01003521out:
3522 kfree(params);
3523 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003524}
3525
Nikesh Oswalc6615082015-02-02 17:06:44 +00003526static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3527 struct snd_ctl_elem_value *ucontrol)
3528{
3529 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3530
3531 ucontrol->value.integer.value[0] = w->params_select;
3532
3533 return 0;
3534}
3535
3536static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3537 struct snd_ctl_elem_value *ucontrol)
3538{
3539 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3540
3541 /* Can't change the config when widget is already powered */
3542 if (w->power)
3543 return -EBUSY;
3544
3545 if (ucontrol->value.integer.value[0] == w->params_select)
3546 return 0;
3547
3548 if (ucontrol->value.integer.value[0] >= w->num_params)
3549 return -EINVAL;
3550
3551 w->params_select = ucontrol->value.integer.value[0];
3552
3553 return 0;
3554}
3555
Mark Brownc74184e2012-04-04 22:12:09 +01003556int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3557 const struct snd_soc_pcm_stream *params,
Nikesh Oswalc6615082015-02-02 17:06:44 +00003558 unsigned int num_params,
Mark Brownc74184e2012-04-04 22:12:09 +01003559 struct snd_soc_dapm_widget *source,
3560 struct snd_soc_dapm_widget *sink)
3561{
Mark Brownc74184e2012-04-04 22:12:09 +01003562 struct snd_soc_dapm_widget template;
3563 struct snd_soc_dapm_widget *w;
Mark Brownc74184e2012-04-04 22:12:09 +01003564 char *link_name;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003565 int ret, count;
3566 unsigned long private_value;
3567 const char **w_param_text;
3568 struct soc_enum w_param_enum[] = {
3569 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3570 };
3571 struct snd_kcontrol_new kcontrol_dai_link[] = {
3572 SOC_ENUM_EXT(NULL, w_param_enum[0],
3573 snd_soc_dapm_dai_link_get,
3574 snd_soc_dapm_dai_link_put),
3575 };
3576 const struct snd_soc_pcm_stream *config = params;
Mark Brownc74184e2012-04-04 22:12:09 +01003577
Nikesh Oswalc6615082015-02-02 17:06:44 +00003578 w_param_text = devm_kcalloc(card->dev, num_params,
3579 sizeof(char *), GFP_KERNEL);
3580 if (!w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003581 return -ENOMEM;
Mark Brownc74184e2012-04-04 22:12:09 +01003582
Charles Keepax46172b62015-03-25 11:22:35 +00003583 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3584 source->name, sink->name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003585 if (!link_name) {
3586 ret = -ENOMEM;
3587 goto outfree_w_param;
3588 }
Mark Brownc74184e2012-04-04 22:12:09 +01003589
Nikesh Oswalc6615082015-02-02 17:06:44 +00003590 for (count = 0 ; count < num_params; count++) {
3591 if (!config->stream_name) {
3592 dev_warn(card->dapm.dev,
3593 "ASoC: anonymous config %d for dai link %s\n",
3594 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003595 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003596 devm_kasprintf(card->dev, GFP_KERNEL,
3597 "Anonymous Configuration %d",
3598 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003599 if (!w_param_text[count]) {
3600 ret = -ENOMEM;
3601 goto outfree_link_name;
3602 }
Nikesh Oswalc6615082015-02-02 17:06:44 +00003603 } else {
3604 w_param_text[count] = devm_kmemdup(card->dev,
3605 config->stream_name,
3606 strlen(config->stream_name) + 1,
3607 GFP_KERNEL);
3608 if (!w_param_text[count]) {
3609 ret = -ENOMEM;
3610 goto outfree_link_name;
3611 }
3612 }
3613 config++;
3614 }
3615 w_param_enum[0].items = num_params;
3616 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003617
3618 memset(&template, 0, sizeof(template));
3619 template.reg = SND_SOC_NOPM;
3620 template.id = snd_soc_dapm_dai_link;
3621 template.name = link_name;
3622 template.event = snd_soc_dai_link_event;
3623 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3624 SND_SOC_DAPM_PRE_PMD;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003625 template.num_kcontrols = 1;
3626 /* duplicate w_param_enum on heap so that memory persists */
3627 private_value =
3628 (unsigned long) devm_kmemdup(card->dev,
3629 (void *)(kcontrol_dai_link[0].private_value),
3630 sizeof(struct soc_enum), GFP_KERNEL);
3631 if (!private_value) {
3632 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3633 link_name);
3634 ret = -ENOMEM;
3635 goto outfree_link_name;
3636 }
3637 kcontrol_dai_link[0].private_value = private_value;
3638 /* duplicate kcontrol_dai_link on heap so that memory persists */
3639 template.kcontrol_news =
3640 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3641 sizeof(struct snd_kcontrol_new),
3642 GFP_KERNEL);
3643 if (!template.kcontrol_news) {
3644 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3645 link_name);
3646 ret = -ENOMEM;
3647 goto outfree_private_value;
3648 }
Mark Brownc74184e2012-04-04 22:12:09 +01003649
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003650 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003651
3652 w = snd_soc_dapm_new_control(&card->dapm, &template);
3653 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003654 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003655 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003656 ret = -ENOMEM;
3657 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003658 }
3659
3660 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003661 w->num_params = num_params;
Mark Brownc74184e2012-04-04 22:12:09 +01003662
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003663 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3664 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003665 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003666 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003667
3668outfree_w:
3669 devm_kfree(card->dev, w);
3670outfree_kcontrol_news:
3671 devm_kfree(card->dev, (void *)template.kcontrol_news);
3672outfree_private_value:
3673 devm_kfree(card->dev, (void *)private_value);
3674outfree_link_name:
3675 devm_kfree(card->dev, link_name);
3676outfree_w_param:
3677 for (count = 0 ; count < num_params; count++)
3678 devm_kfree(card->dev, (void *)w_param_text[count]);
3679 devm_kfree(card->dev, w_param_text);
3680
3681 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003682}
3683
Mark Brown888df392012-02-16 19:37:51 -08003684int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3685 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003686{
Mark Brown888df392012-02-16 19:37:51 -08003687 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003688 struct snd_soc_dapm_widget *w;
3689
Mark Brown888df392012-02-16 19:37:51 -08003690 WARN_ON(dapm->dev != dai->dev);
3691
3692 memset(&template, 0, sizeof(template));
3693 template.reg = SND_SOC_NOPM;
3694
3695 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003696 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003697 template.name = dai->driver->playback.stream_name;
3698 template.sname = dai->driver->playback.stream_name;
3699
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003700 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003701 template.name);
3702
3703 w = snd_soc_dapm_new_control(dapm, &template);
3704 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003705 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003706 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003707 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003708 }
3709
3710 w->priv = dai;
3711 dai->playback_widget = w;
3712 }
3713
3714 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003715 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003716 template.name = dai->driver->capture.stream_name;
3717 template.sname = dai->driver->capture.stream_name;
3718
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003719 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003720 template.name);
3721
3722 w = snd_soc_dapm_new_control(dapm, &template);
3723 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003724 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003725 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003726 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003727 }
3728
3729 w->priv = dai;
3730 dai->capture_widget = w;
3731 }
3732
3733 return 0;
3734}
3735
3736int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3737{
3738 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003739 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08003740 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003741
3742 /* For each DAI widget... */
3743 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003744 switch (dai_w->id) {
3745 case snd_soc_dapm_dai_in:
3746 case snd_soc_dapm_dai_out:
3747 break;
3748 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003749 continue;
Mark Brown46162742013-06-05 19:36:11 +01003750 }
Mark Brown888df392012-02-16 19:37:51 -08003751
3752 dai = dai_w->priv;
3753
3754 /* ...find all widgets with the same stream and link them */
3755 list_for_each_entry(w, &card->widgets, list) {
3756 if (w->dapm != dai_w->dapm)
3757 continue;
3758
Mark Brown46162742013-06-05 19:36:11 +01003759 switch (w->id) {
3760 case snd_soc_dapm_dai_in:
3761 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08003762 continue;
Mark Brown46162742013-06-05 19:36:11 +01003763 default:
3764 break;
3765 }
Mark Brown888df392012-02-16 19:37:51 -08003766
Russell King19c2c5f2013-08-04 20:24:03 +01003767 if (!w->sname || !strstr(w->sname, dai_w->name))
Mark Brown888df392012-02-16 19:37:51 -08003768 continue;
3769
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003770 if (dai_w->id == snd_soc_dapm_dai_in) {
3771 src = dai_w;
3772 sink = w;
3773 } else {
3774 src = w;
3775 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08003776 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003777 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
3778 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003779 }
3780 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003781
Mark Brown888df392012-02-16 19:37:51 -08003782 return 0;
3783}
Liam Girdwood64a648c2011-07-25 11:15:15 +01003784
Benoit Cousson44ba2642014-07-08 23:19:36 +02003785static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
3786 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003787{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003788 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003789 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003790 int i;
3791
Benoit Cousson44ba2642014-07-08 23:19:36 +02003792 for (i = 0; i < rtd->num_codecs; i++) {
3793 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003794
3795 /* there is no point in connecting BE DAI links with dummies */
3796 if (snd_soc_dai_is_dummy(codec_dai) ||
3797 snd_soc_dai_is_dummy(cpu_dai))
3798 continue;
3799
3800 /* connect BE DAI playback if widgets are valid */
3801 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003802 source = cpu_dai->playback_widget;
3803 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003804 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003805 cpu_dai->component->name, source->name,
3806 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003807
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003808 snd_soc_dapm_add_path(&card->dapm, source, sink,
3809 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003810 }
3811
3812 /* connect BE DAI capture if widgets are valid */
3813 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003814 source = codec_dai->capture_widget;
3815 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003816 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003817 codec_dai->component->name, source->name,
3818 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003819
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003820 snd_soc_dapm_add_path(&card->dapm, source, sink,
3821 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003822 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003823 }
3824}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003825
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003826static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3827 int event)
3828{
3829 struct snd_soc_dapm_widget *w;
3830
3831 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3832 w = dai->playback_widget;
3833 else
3834 w = dai->capture_widget;
3835
3836 if (w) {
3837 dapm_mark_dirty(w, "stream event");
3838
3839 switch (event) {
3840 case SND_SOC_DAPM_STREAM_START:
3841 w->active = 1;
3842 break;
3843 case SND_SOC_DAPM_STREAM_STOP:
3844 w->active = 0;
3845 break;
3846 case SND_SOC_DAPM_STREAM_SUSPEND:
3847 case SND_SOC_DAPM_STREAM_RESUME:
3848 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3849 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3850 break;
3851 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003852
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003853 if (w->id == snd_soc_dapm_dai_in) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003854 w->is_source = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003855 dapm_widget_invalidate_input_paths(w);
3856 } else {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003857 w->is_sink = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003858 dapm_widget_invalidate_output_paths(w);
3859 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003860 }
3861}
3862
Benoit Cousson44ba2642014-07-08 23:19:36 +02003863void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3864{
3865 struct snd_soc_pcm_runtime *rtd = card->rtd;
3866 int i;
3867
3868 /* for each BE DAI link... */
3869 for (i = 0; i < card->num_rtd; i++) {
3870 rtd = &card->rtd[i];
3871
3872 /*
3873 * dynamic FE links have no fixed DAI mapping.
3874 * CODEC<->CODEC links have no direct connection.
3875 */
3876 if (rtd->dai_link->dynamic || rtd->dai_link->params)
3877 continue;
3878
3879 dapm_connect_dai_link_widgets(card, rtd);
3880 }
3881}
3882
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003883static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3884 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003885{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003886 int i;
3887
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003888 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02003889 for (i = 0; i < rtd->num_codecs; i++)
3890 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003891
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003892 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003893}
3894
3895/**
3896 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3897 * @rtd: PCM runtime data
3898 * @stream: stream name
3899 * @event: stream event
3900 *
3901 * Sends a stream event to the dapm core. The core then makes any
3902 * necessary widget power changes.
3903 *
3904 * Returns 0 for success else error.
3905 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003906void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3907 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003908{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003909 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003910
Liam Girdwood3cd04342012-03-09 12:02:08 +00003911 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003912 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003913 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003914}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003915
3916/**
Charles Keepax11391102014-02-18 15:22:14 +00003917 * snd_soc_dapm_enable_pin_unlocked - enable pin.
3918 * @dapm: DAPM context
3919 * @pin: pin name
3920 *
3921 * Enables input/output pin and its parents or children widgets iff there is
3922 * a valid audio route and active audio stream.
3923 *
3924 * Requires external locking.
3925 *
3926 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3927 * do any widget power switching.
3928 */
3929int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3930 const char *pin)
3931{
3932 return snd_soc_dapm_set_pin(dapm, pin, 1);
3933}
3934EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
3935
3936/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003937 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003938 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003939 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02003940 *
Mark Brown74b8f952009-06-06 11:26:15 +01003941 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01003942 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00003943 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003944 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3945 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02003946 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003947int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003948{
Charles Keepax11391102014-02-18 15:22:14 +00003949 int ret;
3950
3951 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3952
3953 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
3954
3955 mutex_unlock(&dapm->card->dapm_mutex);
3956
3957 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003958}
Liam Girdwooda5302182008-07-07 13:35:17 +01003959EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003960
3961/**
Charles Keepax11391102014-02-18 15:22:14 +00003962 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
3963 * @dapm: DAPM context
3964 * @pin: pin name
3965 *
3966 * Enables input/output pin regardless of any other state. This is
3967 * intended for use with microphone bias supplies used in microphone
3968 * jack detection.
3969 *
3970 * Requires external locking.
3971 *
3972 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3973 * do any widget power switching.
3974 */
3975int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3976 const char *pin)
3977{
3978 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
3979
3980 if (!w) {
3981 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
3982 return -EINVAL;
3983 }
3984
3985 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003986 if (!w->connected) {
3987 /*
3988 * w->force does not affect the number of input or output paths,
3989 * so we only have to recheck if w->connected is changed
3990 */
3991 dapm_widget_invalidate_input_paths(w);
3992 dapm_widget_invalidate_output_paths(w);
3993 w->connected = 1;
3994 }
Charles Keepax11391102014-02-18 15:22:14 +00003995 w->force = 1;
3996 dapm_mark_dirty(w, "force enable");
3997
3998 return 0;
3999}
4000EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4001
4002/**
Mark Brownda341832010-03-15 19:23:37 +00004003 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004004 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00004005 * @pin: pin name
4006 *
4007 * Enables input/output pin regardless of any other state. This is
4008 * intended for use with microphone bias supplies used in microphone
4009 * jack detection.
4010 *
4011 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4012 * do any widget power switching.
4013 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004014int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4015 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00004016{
Charles Keepax11391102014-02-18 15:22:14 +00004017 int ret;
Mark Brownda341832010-03-15 19:23:37 +00004018
Charles Keepax11391102014-02-18 15:22:14 +00004019 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00004020
Charles Keepax11391102014-02-18 15:22:14 +00004021 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09004022
Charles Keepax11391102014-02-18 15:22:14 +00004023 mutex_unlock(&dapm->card->dapm_mutex);
4024
4025 return ret;
Mark Brownda341832010-03-15 19:23:37 +00004026}
4027EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4028
4029/**
Charles Keepax11391102014-02-18 15:22:14 +00004030 * snd_soc_dapm_disable_pin_unlocked - disable pin.
4031 * @dapm: DAPM context
4032 * @pin: pin name
4033 *
4034 * Disables input/output pin and its parents or children widgets.
4035 *
4036 * Requires external locking.
4037 *
4038 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4039 * do any widget power switching.
4040 */
4041int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4042 const char *pin)
4043{
4044 return snd_soc_dapm_set_pin(dapm, pin, 0);
4045}
4046EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4047
4048/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004049 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004050 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004051 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004052 *
Mark Brown74b8f952009-06-06 11:26:15 +01004053 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004054 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004055 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4056 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004057 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004058int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4059 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004060{
Charles Keepax11391102014-02-18 15:22:14 +00004061 int ret;
4062
4063 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4064
4065 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4066
4067 mutex_unlock(&dapm->card->dapm_mutex);
4068
4069 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004070}
4071EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4072
4073/**
Charles Keepax11391102014-02-18 15:22:14 +00004074 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4075 * @dapm: DAPM context
4076 * @pin: pin name
4077 *
4078 * Marks the specified pin as being not connected, disabling it along
4079 * any parent or child widgets. At present this is identical to
4080 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4081 * additional things such as disabling controls which only affect
4082 * paths through the pin.
4083 *
4084 * Requires external locking.
4085 *
4086 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4087 * do any widget power switching.
4088 */
4089int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4090 const char *pin)
4091{
4092 return snd_soc_dapm_set_pin(dapm, pin, 0);
4093}
4094EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4095
4096/**
Mark Brown5817b522008-09-24 11:23:11 +01004097 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004098 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004099 * @pin: pin name
4100 *
4101 * Marks the specified pin as being not connected, disabling it along
4102 * any parent or child widgets. At present this is identical to
4103 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4104 * additional things such as disabling controls which only affect
4105 * paths through the pin.
4106 *
4107 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4108 * do any widget power switching.
4109 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004110int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004111{
Charles Keepax11391102014-02-18 15:22:14 +00004112 int ret;
4113
4114 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4115
4116 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4117
4118 mutex_unlock(&dapm->card->dapm_mutex);
4119
4120 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004121}
4122EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4123
4124/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004125 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004126 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004127 * @pin: audio signal pin endpoint (or start point)
4128 *
4129 * Get audio pin status - connected or disconnected.
4130 *
4131 * Returns 1 for connected otherwise 0.
4132 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004133int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4134 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004135{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004136 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004137
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004138 if (w)
4139 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004140
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004141 return 0;
4142}
Liam Girdwooda5302182008-07-07 13:35:17 +01004143EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004144
4145/**
Mark Brown1547aba2010-05-07 21:11:40 +01004146 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004147 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004148 * @pin: audio signal pin endpoint (or start point)
4149 *
4150 * Mark the given endpoint or pin as ignoring suspend. When the
4151 * system is disabled a path between two endpoints flagged as ignoring
4152 * suspend will not be disabled. The path must already be enabled via
4153 * normal means at suspend time, it will not be turned on if it was not
4154 * already enabled.
4155 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004156int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4157 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004158{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004159 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004160
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004161 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004162 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004163 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004164 }
4165
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004166 w->ignore_suspend = 1;
4167
4168 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004169}
4170EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4171
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004172/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004173 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004174 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004175 *
4176 * Free all dapm widgets and resources.
4177 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004178void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004179{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004180 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004181 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004182 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004183}
4184EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4185
Xiang Xiao57996352014-03-02 00:04:02 +08004186static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004187{
Liam Girdwood01005a72012-07-06 16:57:05 +01004188 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004189 struct snd_soc_dapm_widget *w;
4190 LIST_HEAD(down_list);
4191 int powerdown = 0;
4192
Liam Girdwood01005a72012-07-06 16:57:05 +01004193 mutex_lock(&card->dapm_mutex);
4194
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004195 list_for_each_entry(w, &dapm->card->widgets, list) {
4196 if (w->dapm != dapm)
4197 continue;
Mark Brown51737472009-06-22 13:16:51 +01004198 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004199 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004200 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004201 powerdown = 1;
4202 }
4203 }
4204
4205 /* If there were no widgets to power down we're already in
4206 * standby.
4207 */
4208 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004209 if (dapm->bias_level == SND_SOC_BIAS_ON)
4210 snd_soc_dapm_set_bias_level(dapm,
4211 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004212 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004213 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4214 snd_soc_dapm_set_bias_level(dapm,
4215 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004216 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004217
4218 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004219}
Mark Brown51737472009-06-22 13:16:51 +01004220
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004221/*
4222 * snd_soc_dapm_shutdown - callback for system shutdown
4223 */
4224void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4225{
Xiang Xiao57996352014-03-02 00:04:02 +08004226 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004227
Xiang Xiao57996352014-03-02 00:04:02 +08004228 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004229 if (dapm != &card->dapm) {
4230 soc_dapm_shutdown_dapm(dapm);
4231 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4232 snd_soc_dapm_set_bias_level(dapm,
4233 SND_SOC_BIAS_OFF);
4234 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004235 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004236
4237 soc_dapm_shutdown_dapm(&card->dapm);
4238 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4239 snd_soc_dapm_set_bias_level(&card->dapm,
4240 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004241}
4242
Richard Purdie2b97eab2006-10-06 18:32:18 +02004243/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004244MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004245MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4246MODULE_LICENSE("GPL");