blob: ac506cfb9ed20b8486717aa21f9852574f380b87 [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));
Vladimir Zapolskiy5353f652015-06-02 00:57:53 +030055
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +010056struct snd_soc_dapm_widget *
Lars-Peter Clausen57295072013-08-05 11:27:31 +020057snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
58 const struct snd_soc_dapm_widget *widget);
59
Liam Girdwood02aa78a2015-05-25 18:21:17 +010060struct snd_soc_dapm_widget *
61snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +020062 const struct snd_soc_dapm_widget *widget);
63
Richard Purdie2b97eab2006-10-06 18:32:18 +020064/* dapm power sequences - make this per codec in the future */
65static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010066 [snd_soc_dapm_pre] = 0,
Mark Brown62ea8742012-01-21 21:14:48 +000067 [snd_soc_dapm_regulator_supply] = 1,
Ola Liljad7e7eb92012-05-24 15:26:25 +020068 [snd_soc_dapm_clock_supply] = 1,
Mark Brown1dd275b2013-10-09 13:56:37 +010069 [snd_soc_dapm_supply] = 2,
70 [snd_soc_dapm_micbias] = 3,
Mark Brownc74184e2012-04-04 22:12:09 +010071 [snd_soc_dapm_dai_link] = 2,
Mark Brown1dd275b2013-10-09 13:56:37 +010072 [snd_soc_dapm_dai_in] = 4,
73 [snd_soc_dapm_dai_out] = 4,
74 [snd_soc_dapm_aif_in] = 4,
75 [snd_soc_dapm_aif_out] = 4,
76 [snd_soc_dapm_mic] = 5,
77 [snd_soc_dapm_mux] = 6,
Lars-Peter Clausend714f972015-05-01 18:02:43 +020078 [snd_soc_dapm_demux] = 6,
Mark Brown1dd275b2013-10-09 13:56:37 +010079 [snd_soc_dapm_dac] = 7,
80 [snd_soc_dapm_switch] = 8,
81 [snd_soc_dapm_mixer] = 8,
82 [snd_soc_dapm_mixer_named_ctl] = 8,
83 [snd_soc_dapm_pga] = 9,
84 [snd_soc_dapm_adc] = 10,
85 [snd_soc_dapm_out_drv] = 11,
86 [snd_soc_dapm_hp] = 11,
87 [snd_soc_dapm_spk] = 11,
88 [snd_soc_dapm_line] = 11,
89 [snd_soc_dapm_kcontrol] = 12,
90 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020091};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000092
Richard Purdie2b97eab2006-10-06 18:32:18 +020093static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010094 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +020095 [snd_soc_dapm_kcontrol] = 1,
96 [snd_soc_dapm_adc] = 2,
97 [snd_soc_dapm_hp] = 3,
98 [snd_soc_dapm_spk] = 3,
99 [snd_soc_dapm_line] = 3,
100 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +0100101 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +0200102 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +0100103 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +0100104 [snd_soc_dapm_mixer] = 5,
105 [snd_soc_dapm_dac] = 6,
106 [snd_soc_dapm_mic] = 7,
107 [snd_soc_dapm_micbias] = 8,
108 [snd_soc_dapm_mux] = 9,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200109 [snd_soc_dapm_demux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100110 [snd_soc_dapm_aif_in] = 10,
111 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100112 [snd_soc_dapm_dai_in] = 10,
113 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100114 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100115 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100116 [snd_soc_dapm_clock_supply] = 13,
117 [snd_soc_dapm_regulator_supply] = 13,
118 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200119};
120
Mark Brownf9fa2b12014-03-06 16:49:11 +0800121static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
122{
123 if (dapm->card && dapm->card->instantiated)
124 lockdep_assert_held(&dapm->card->dapm_mutex);
125}
126
Troy Kisky12ef1932008-10-13 17:42:14 -0700127static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100128{
129 if (pop_time)
130 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
131}
132
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200133static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100134{
135 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200136 char *buf;
137
138 if (!pop_time)
139 return;
140
141 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
142 if (buf == NULL)
143 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100144
145 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200146 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100147 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100148 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200149
150 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100151}
152
Mark Browndb432b42011-10-03 21:06:40 +0100153static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
154{
155 return !list_empty(&w->dirty);
156}
157
Mark Brown492c0a12014-03-06 16:15:48 +0800158static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100159{
Mark Brownf9fa2b12014-03-06 16:49:11 +0800160 dapm_assert_locked(w->dapm);
161
Mark Brown75c1f892011-10-04 22:28:08 +0100162 if (!dapm_dirty_widget(w)) {
163 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
164 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100165 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100166 }
Mark Browndb432b42011-10-03 21:06:40 +0100167}
168
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200169/*
170 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
171 * paths
172 * @w: The widget for which to invalidate the cached number of input paths
173 *
174 * The function resets the cached number of inputs for the specified widget and
175 * all widgets that can be reached via outgoing paths from the widget.
176 *
177 * This function must be called if the number of input paths for a widget might
178 * have changed. E.g. if the source state of a widget changes or a path is added
179 * or activated with the widget as the sink.
180 */
181static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
182{
183 struct snd_soc_dapm_widget *sink;
184 struct snd_soc_dapm_path *p;
185 LIST_HEAD(list);
186
187 dapm_assert_locked(w->dapm);
188
189 if (w->inputs == -1)
190 return;
191
192 w->inputs = -1;
193 list_add_tail(&w->work_list, &list);
194
195 list_for_each_entry(w, &list, work_list) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200196 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200197 if (p->is_supply || p->weak || !p->connect)
198 continue;
199 sink = p->sink;
200 if (sink->inputs != -1) {
201 sink->inputs = -1;
202 list_add_tail(&sink->work_list, &list);
203 }
204 }
205 }
206}
207
208/*
209 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
210 * output paths
211 * @w: The widget for which to invalidate the cached number of output paths
212 *
213 * Resets the cached number of outputs for the specified widget and all widgets
214 * that can be reached via incoming paths from the widget.
215 *
216 * This function must be called if the number of output paths for a widget might
217 * have changed. E.g. if the sink state of a widget changes or a path is added
218 * or activated with the widget as the source.
219 */
220static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
221{
222 struct snd_soc_dapm_widget *source;
223 struct snd_soc_dapm_path *p;
224 LIST_HEAD(list);
225
226 dapm_assert_locked(w->dapm);
227
228 if (w->outputs == -1)
229 return;
230
231 w->outputs = -1;
232 list_add_tail(&w->work_list, &list);
233
234 list_for_each_entry(w, &list, work_list) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200235 snd_soc_dapm_widget_for_each_source_path(w, p) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200236 if (p->is_supply || p->weak || !p->connect)
237 continue;
238 source = p->source;
239 if (source->outputs != -1) {
240 source->outputs = -1;
241 list_add_tail(&source->work_list, &list);
242 }
243 }
244 }
245}
246
247/*
248 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
249 * for the widgets connected to a path
250 * @p: The path to invalidate
251 *
252 * Resets the cached number of inputs for the sink of the path and the cached
253 * number of outputs for the source of the path.
254 *
255 * This function must be called when a path is added, removed or the connected
256 * state changes.
257 */
258static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
259{
260 /*
261 * Weak paths or supply paths do not influence the number of input or
262 * output paths of their neighbors.
263 */
264 if (p->weak || p->is_supply)
265 return;
266
267 /*
268 * The number of connected endpoints is the sum of the number of
269 * connected endpoints of all neighbors. If a node with 0 connected
270 * endpoints is either connected or disconnected that sum won't change,
271 * so there is no need to re-check the path.
272 */
273 if (p->source->inputs != 0)
274 dapm_widget_invalidate_input_paths(p->sink);
275 if (p->sink->outputs != 0)
276 dapm_widget_invalidate_output_paths(p->source);
277}
278
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200279void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
Mark Browne2d32ff2012-08-31 17:38:32 -0700280{
Mark Browne2d32ff2012-08-31 17:38:32 -0700281 struct snd_soc_dapm_widget *w;
282
283 mutex_lock(&card->dapm_mutex);
284
285 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200286 if (w->is_sink || w->is_source) {
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200287 dapm_mark_dirty(w, "Rechecking endpoints");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200288 if (w->is_sink)
289 dapm_widget_invalidate_output_paths(w);
290 if (w->is_source)
291 dapm_widget_invalidate_input_paths(w);
292 }
Mark Browne2d32ff2012-08-31 17:38:32 -0700293 }
294
295 mutex_unlock(&card->dapm_mutex);
296}
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200297EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
Mark Browne2d32ff2012-08-31 17:38:32 -0700298
Richard Purdie2b97eab2006-10-06 18:32:18 +0200299/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100300static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200301 const struct snd_soc_dapm_widget *_widget)
302{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100303 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200304}
305
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200306struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200307 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200308 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200309 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200310 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200311};
312
313static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
314 struct snd_kcontrol *kcontrol)
315{
316 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200317 struct soc_mixer_control *mc;
Charles Keepax561ed682015-05-01 12:37:26 +0100318 struct soc_enum *e;
Charles Keepax773da9b2015-05-01 12:37:25 +0100319 const char *name;
320 int ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200321
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200322 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100323 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200324 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200325
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200326 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200327
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200328 switch (widget->id) {
329 case snd_soc_dapm_switch:
330 case snd_soc_dapm_mixer:
331 case snd_soc_dapm_mixer_named_ctl:
332 mc = (struct soc_mixer_control *)kcontrol->private_value;
333
334 if (mc->autodisable) {
335 struct snd_soc_dapm_widget template;
336
Charles Keepax773da9b2015-05-01 12:37:25 +0100337 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
338 "Autodisable");
339 if (!name) {
340 ret = -ENOMEM;
341 goto err_data;
342 }
343
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200344 memset(&template, 0, sizeof(template));
345 template.reg = mc->reg;
346 template.mask = (1 << fls(mc->max)) - 1;
347 template.shift = mc->shift;
348 if (mc->invert)
349 template.off_val = mc->max;
350 else
351 template.off_val = 0;
352 template.on_val = template.off_val;
353 template.id = snd_soc_dapm_kcontrol;
Charles Keepax773da9b2015-05-01 12:37:25 +0100354 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200355
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200356 data->value = template.on_val;
357
Liam Girdwood02aa78a2015-05-25 18:21:17 +0100358 data->widget =
359 snd_soc_dapm_new_control_unlocked(widget->dapm,
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200360 &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200361 kfree(name);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200362 if (!data->widget) {
Charles Keepax773da9b2015-05-01 12:37:25 +0100363 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200364 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200365 }
366 }
367 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200368 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100369 case snd_soc_dapm_mux:
370 e = (struct soc_enum *)kcontrol->private_value;
371
372 if (e->autodisable) {
373 struct snd_soc_dapm_widget template;
374
375 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
376 "Autodisable");
377 if (!name) {
378 ret = -ENOMEM;
379 goto err_data;
380 }
381
382 memset(&template, 0, sizeof(template));
383 template.reg = e->reg;
384 template.mask = e->mask << e->shift_l;
385 template.shift = e->shift_l;
386 template.off_val = snd_soc_enum_item_to_val(e, 0);
387 template.on_val = template.off_val;
388 template.id = snd_soc_dapm_kcontrol;
389 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200390
391 data->value = template.on_val;
392
Charles Keepaxffacb482015-06-26 10:39:43 +0100393 data->widget = snd_soc_dapm_new_control_unlocked(
394 widget->dapm, &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200395 kfree(name);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200396 if (!data->widget) {
Charles Keepax561ed682015-05-01 12:37:26 +0100397 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200398 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200399 }
Charles Keepax561ed682015-05-01 12:37:26 +0100400
401 snd_soc_dapm_add_path(widget->dapm, data->widget,
402 widget, NULL, NULL);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200403 }
404 break;
405 default:
406 break;
407 }
408
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200409 kcontrol->private_data = data;
410
411 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100412
Charles Keepax773da9b2015-05-01 12:37:25 +0100413err_data:
414 kfree(data);
415 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200416}
417
418static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
419{
420 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200421 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200422 kfree(data);
423}
424
425static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
426 const struct snd_kcontrol *kcontrol)
427{
428 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
429
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200430 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200431}
432
433static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
434 struct snd_soc_dapm_widget *widget)
435{
436 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200437 struct snd_soc_dapm_widget_list *new_wlist;
438 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200439
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200440 if (data->wlist)
441 n = data->wlist->num_widgets + 1;
442 else
443 n = 1;
444
445 new_wlist = krealloc(data->wlist,
446 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
447 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200448 return -ENOMEM;
449
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200450 new_wlist->widgets[n - 1] = widget;
451 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200452
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200453 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200454
455 return 0;
456}
457
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200458static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
459 struct snd_soc_dapm_path *path)
460{
461 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
462
463 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200464}
465
466static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
467{
468 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
469
470 if (!data->widget)
471 return true;
472
473 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200474}
475
476static struct list_head *dapm_kcontrol_get_path_list(
477 const struct snd_kcontrol *kcontrol)
478{
479 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
480
481 return &data->paths;
482}
483
484#define dapm_kcontrol_for_each_path(path, kcontrol) \
485 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
486 list_kcontrol)
487
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530488unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200489{
490 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
491
492 return data->value;
493}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530494EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200495
496static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
497 unsigned int value)
498{
499 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
500
501 if (data->value == value)
502 return false;
503
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200504 if (data->widget)
505 data->widget->on_val = value;
506
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200507 data->value = value;
508
509 return true;
510}
511
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200512/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200513 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
514 * kcontrol
515 * @kcontrol: The kcontrol
516 *
517 * Note: This function must only be used on kcontrols that are known to have
518 * been registered for a CODEC. Otherwise the behaviour is undefined.
519 */
520struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
521 struct snd_kcontrol *kcontrol)
522{
523 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
524}
525EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
526
Liam Girdwood6c120e12012-02-15 15:15:34 +0000527static void dapm_reset(struct snd_soc_card *card)
528{
529 struct snd_soc_dapm_widget *w;
530
Mark Brownf9fa2b12014-03-06 16:49:11 +0800531 lockdep_assert_held(&card->dapm_mutex);
532
Liam Girdwood6c120e12012-02-15 15:15:34 +0000533 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
534
535 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200536 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000537 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000538 }
539}
540
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200541static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
542{
543 if (!dapm->component)
544 return NULL;
545 return dapm->component->name_prefix;
546}
547
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200548static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800549 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100550{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200551 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200552 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200553 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100554}
555
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200556static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800557 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100558{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200559 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200560 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000561 return snd_soc_component_update_bits(dapm->component, reg,
562 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000563}
564
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200565static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
566 int reg, unsigned int mask, unsigned int value)
567{
568 if (!dapm->component)
569 return -EIO;
570 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
571}
572
Mark Browneb270e92013-10-09 13:52:52 +0100573static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
574{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200575 if (dapm->component)
576 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100577}
578
Charles Keepax45a110a2015-05-11 13:50:30 +0100579static struct snd_soc_dapm_widget *
580dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
581{
582 struct snd_soc_dapm_widget *w = wcache->widget;
583 struct list_head *wlist;
584 const int depth = 2;
585 int i = 0;
586
587 if (w) {
588 wlist = &w->dapm->card->widgets;
589
590 list_for_each_entry_from(w, wlist, list) {
591 if (!strcmp(name, w->name))
592 return w;
593
594 if (++i == depth)
595 break;
596 }
597 }
598
599 return NULL;
600}
601
602static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
603 struct snd_soc_dapm_widget *w)
604{
605 wcache->widget = w;
606}
607
Mark Brown452c5ea2009-05-17 21:41:23 +0100608/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200609 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
610 * @dapm: The DAPM context for which to set the level
611 * @level: The level to set
612 *
613 * Forces the DAPM bias level to a specific state. It will call the bias level
614 * callback of DAPM context with the specified level. This will even happen if
615 * the context is already at the same level. Furthermore it will not go through
616 * the normal bias level sequencing, meaning any intermediate states between the
617 * current and the target state will not be entered.
618 *
619 * Note that the change in bias level is only temporary and the next time
620 * snd_soc_dapm_sync() is called the state will be set to the level as
621 * determined by the DAPM core. The function is mainly intended to be used to
622 * used during probe or resume from suspend to power up the device so
623 * initialization can be done, before the DAPM core takes over.
624 */
625int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
626 enum snd_soc_bias_level level)
627{
628 int ret = 0;
629
630 if (dapm->set_bias_level)
631 ret = dapm->set_bias_level(dapm, level);
632
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200633 if (ret == 0)
634 dapm->bias_level = level;
635
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200636 return ret;
637}
638EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
639
Mark Brown452c5ea2009-05-17 21:41:23 +0100640/**
641 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800642 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100643 * @level: level to configure
644 *
645 * Configure the bias (power) levels for the SoC audio device.
646 *
647 * Returns 0 for success else error.
648 */
Mark Browned5a4c42011-02-18 11:12:42 -0800649static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200650 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100651{
Mark Browned5a4c42011-02-18 11:12:42 -0800652 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100653 int ret = 0;
654
Mark Brown84e90932010-11-04 00:07:02 -0400655 trace_snd_soc_bias_level_start(card, level);
656
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000657 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100658 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100659 if (ret != 0)
660 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100661
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200662 if (!card || dapm != &card->dapm)
663 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100664
Mark Brown171ec6b2011-06-06 18:15:19 +0100665 if (ret != 0)
666 goto out;
667
668 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100669 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100670out:
Mark Brown84e90932010-11-04 00:07:02 -0400671 trace_snd_soc_bias_level_done(card, level);
672
Mark Brown452c5ea2009-05-17 21:41:23 +0100673 return ret;
674}
675
Mark Brown74b8f952009-06-06 11:26:15 +0100676/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200677static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200678 struct snd_soc_dapm_path *path, const char *control_name,
679 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200680{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200681 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200682 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100683 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200684 int i;
685
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100686 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200687 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100688 val = (val >> e->shift_l) & e->mask;
689 item = snd_soc_enum_val_to_item(e, val);
690 } else {
691 /* since a virtual mux has no backing registers to
692 * decide which path to connect, it will try to match
693 * with the first enumeration. This is to ensure
694 * that the default mux choice (the first) will be
695 * correctly powered up during initialization.
696 */
697 item = 0;
698 }
699
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100700 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200701 if (!(strcmp(control_name, e->texts[i]))) {
Rasmus Villemoes98ad73c2014-10-21 17:01:15 +0200702 path->name = e->texts[i];
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100703 if (i == item)
704 path->connect = 1;
705 else
706 path->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200707 return 0;
708 }
709 }
710
711 return -ENODEV;
712}
713
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100714/* set up initial codec paths */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200715static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100716{
717 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200718 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100719 unsigned int reg = mc->reg;
720 unsigned int shift = mc->shift;
721 unsigned int max = mc->max;
722 unsigned int mask = (1 << fls(max)) - 1;
723 unsigned int invert = mc->invert;
724 unsigned int val;
725
726 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200727 soc_dapm_read(p->sink->dapm, reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100728 val = (val >> shift) & mask;
729 if (invert)
730 val = max - val;
731 p->connect = !!val;
732 } else {
733 p->connect = 0;
734 }
735}
736
Mark Brown74b8f952009-06-06 11:26:15 +0100737/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200738static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200739 struct snd_soc_dapm_path *path, const char *control_name)
740{
741 int i;
742
743 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200744 for (i = 0; i < path->sink->num_kcontrols; i++) {
745 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
746 path->name = path->sink->kcontrol_news[i].name;
747 dapm_set_mixer_path_status(path, i);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200748 return 0;
749 }
750 }
751 return -ENODEV;
752}
753
Stephen Warrenaf468002011-04-28 17:38:01 -0600754static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600755 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600756 const struct snd_kcontrol_new *kcontrol_new,
757 struct snd_kcontrol **kcontrol)
758{
759 struct snd_soc_dapm_widget *w;
760 int i;
761
762 *kcontrol = NULL;
763
764 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600765 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
766 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600767 for (i = 0; i < w->num_kcontrols; i++) {
768 if (&w->kcontrol_news[i] == kcontrol_new) {
769 if (w->kcontrols)
770 *kcontrol = w->kcontrols[i];
771 return 1;
772 }
773 }
774 }
775
776 return 0;
777}
778
Stephen Warren85762e72013-03-29 15:40:10 -0600779/*
780 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
781 * create it. Either way, add the widget into the control's widget list
782 */
783static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100784 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200785{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200786 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000787 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000788 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600789 size_t prefix_len;
790 int shared;
791 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600792 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200793 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600794 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200795 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000796
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200797 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000798 if (prefix)
799 prefix_len = strlen(prefix) + 1;
800 else
801 prefix_len = 0;
802
Stephen Warren85762e72013-03-29 15:40:10 -0600803 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
804 &kcontrol);
805
Stephen Warren85762e72013-03-29 15:40:10 -0600806 if (!kcontrol) {
807 if (shared) {
808 wname_in_long_name = false;
809 kcname_in_long_name = true;
810 } else {
811 switch (w->id) {
812 case snd_soc_dapm_switch:
813 case snd_soc_dapm_mixer:
814 wname_in_long_name = true;
815 kcname_in_long_name = true;
816 break;
817 case snd_soc_dapm_mixer_named_ctl:
818 wname_in_long_name = false;
819 kcname_in_long_name = true;
820 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200821 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600822 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600823 wname_in_long_name = true;
824 kcname_in_long_name = false;
825 break;
826 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600827 return -EINVAL;
828 }
829 }
830
831 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600832 /*
833 * The control will get a prefix from the control
834 * creation process but we're also using the same
835 * prefix for widgets so cut the prefix off the
836 * front of the widget name.
837 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200838 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600839 w->name + prefix_len,
840 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200841 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200842 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600843
844 name = long_name;
845 } else if (wname_in_long_name) {
846 long_name = NULL;
847 name = w->name + prefix_len;
848 } else {
849 long_name = NULL;
850 name = w->kcontrol_news[kci].name;
851 }
852
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200853 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600854 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200855 if (!kcontrol) {
856 ret = -ENOMEM;
857 goto exit_free;
858 }
859
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200860 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200861
862 ret = dapm_kcontrol_data_alloc(w, kcontrol);
863 if (ret) {
864 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200865 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200866 }
867
Stephen Warren85762e72013-03-29 15:40:10 -0600868 ret = snd_ctl_add(card, kcontrol);
869 if (ret < 0) {
870 dev_err(dapm->dev,
871 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
872 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200873 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600874 }
Stephen Warren85762e72013-03-29 15:40:10 -0600875 }
876
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200877 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200878 if (ret == 0)
879 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200880
Daniel Macke5092c92014-10-07 13:41:24 +0200881exit_free:
882 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600883
Daniel Macke5092c92014-10-07 13:41:24 +0200884 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600885}
886
887/* create new dapm mixer control */
888static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
889{
890 int i, ret;
891 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100892 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600893
Richard Purdie2b97eab2006-10-06 18:32:18 +0200894 /* add kcontrol */
895 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200896 /* match name */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200897 snd_soc_dapm_widget_for_each_source_path(w, path) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200898 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600899 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200900 continue;
901
Charles Keepax561ed682015-05-01 12:37:26 +0100902 if (!w->kcontrols[i]) {
903 ret = dapm_create_or_share_mixmux_kcontrol(w, i);
904 if (ret < 0)
905 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200906 }
907
Mark Brown946d92a2013-08-12 23:28:42 +0100908 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100909
910 data = snd_kcontrol_chip(w->kcontrols[i]);
911 if (data->widget)
912 snd_soc_dapm_add_path(data->widget->dapm,
913 data->widget,
914 path->source,
915 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200916 }
917 }
Stephen Warren85762e72013-03-29 15:40:10 -0600918
919 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200920}
921
922/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200923static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200924{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200925 struct snd_soc_dapm_context *dapm = w->dapm;
Stephen Warren85762e72013-03-29 15:40:10 -0600926 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200927 struct list_head *paths;
928 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600929 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200930
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200931 switch (w->id) {
932 case snd_soc_dapm_mux:
933 paths = &w->sources;
934 type = "mux";
935 break;
936 case snd_soc_dapm_demux:
937 paths = &w->sinks;
938 type = "demux";
939 break;
940 default:
941 return -EINVAL;
942 }
943
Stephen Warrenaf468002011-04-28 17:38:01 -0600944 if (w->num_kcontrols != 1) {
945 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200946 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600947 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200948 return -EINVAL;
949 }
950
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200951 if (list_empty(paths)) {
952 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600953 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600954 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200955
Mark Brown946d92a2013-08-12 23:28:42 +0100956 ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600957 if (ret < 0)
958 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600959
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200960 if (w->id == snd_soc_dapm_mux) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200961 snd_soc_dapm_widget_for_each_source_path(w, path) {
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200962 if (path->name)
963 dapm_kcontrol_add_path(w->kcontrols[0], path);
964 }
965 } else {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200966 snd_soc_dapm_widget_for_each_sink_path(w, path) {
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200967 if (path->name)
968 dapm_kcontrol_add_path(w->kcontrols[0], path);
969 }
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +0200970 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200971
Stephen Warrenaf468002011-04-28 17:38:01 -0600972 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200973}
974
975/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200976static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200977{
Mark Browna6c65732010-03-03 17:45:21 +0000978 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200979 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000980 "ASoC: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200981
Mark Browna6c65732010-03-03 17:45:21 +0000982 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200983}
984
Nikesh Oswalc6615082015-02-02 17:06:44 +0000985/* create new dapm dai link control */
986static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
987{
988 int i, ret;
989 struct snd_kcontrol *kcontrol;
990 struct snd_soc_dapm_context *dapm = w->dapm;
991 struct snd_card *card = dapm->card->snd_card;
992
993 /* create control for links with > 1 config */
994 if (w->num_params <= 1)
995 return 0;
996
997 /* add kcontrol */
998 for (i = 0; i < w->num_kcontrols; i++) {
999 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
1000 w->name, NULL);
1001 ret = snd_ctl_add(card, kcontrol);
1002 if (ret < 0) {
1003 dev_err(dapm->dev,
1004 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1005 w->name, w->kcontrol_news[i].name, ret);
1006 return ret;
1007 }
1008 kcontrol->private_data = w;
1009 w->kcontrols[i] = kcontrol;
1010 }
1011
1012 return 0;
1013}
1014
Mark Brown99497882010-05-07 20:24:05 +01001015/* We implement power down on suspend by checking the power state of
1016 * the ALSA card - when we are suspending the ALSA state for the card
1017 * is set to D3.
1018 */
1019static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1020{
Mark Brown12ea2c72011-03-02 18:17:32 +00001021 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +01001022
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001023 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +01001024 case SNDRV_CTL_POWER_D3hot:
1025 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +01001026 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001027 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001028 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +01001029 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +01001030 default:
1031 return 1;
1032 }
1033}
1034
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001035static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1036 struct list_head *widgets)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001037{
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001038 struct snd_soc_dapm_widget *w;
1039 struct list_head *it;
1040 unsigned int size = 0;
1041 unsigned int i = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001042
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001043 list_for_each(it, widgets)
1044 size++;
1045
1046 *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001047 if (*list == NULL)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001048 return -ENOMEM;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001049
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001050 list_for_each_entry(w, widgets, work_list)
1051 (*list)->widgets[i++] = w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001052
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001053 (*list)->num_widgets = i;
1054
1055 return 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001056}
1057
Richard Purdie2b97eab2006-10-06 18:32:18 +02001058/*
1059 * Recursively check for a completed path to an active or physically connected
1060 * output widget. Returns number of complete paths.
1061 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001062static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001063 struct list_head *list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001064{
1065 struct snd_soc_dapm_path *path;
1066 int con = 0;
1067
Mark Brown024dc072011-10-09 11:52:05 +01001068 if (widget->outputs >= 0)
1069 return widget->outputs;
1070
Mark Brownde02d072011-09-20 21:43:24 +01001071 DAPM_UPDATE_STAT(widget, path_checks);
1072
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001073 /* do we need to add this widget to the list ? */
1074 if (list)
1075 list_add_tail(&widget->work_list, list);
1076
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001077 if (widget->is_sink && widget->connected) {
1078 widget->outputs = snd_soc_dapm_suspend_check(widget);
1079 return widget->outputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001080 }
1081
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001082 snd_soc_dapm_widget_for_each_sink_path(widget, path) {
Mark Browne56235e2011-09-21 18:19:14 +01001083 DAPM_UPDATE_STAT(widget, neighbour_checks);
1084
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001085 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001086 continue;
1087
Mark Brown8af294b2013-02-22 17:48:15 +00001088 if (path->walking)
1089 return 1;
1090
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001091 trace_snd_soc_dapm_output_path(widget, path);
1092
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001093 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001094 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001095 con += is_connected_output_ep(path->sink, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001096 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001097 }
1098 }
1099
Mark Brown024dc072011-10-09 11:52:05 +01001100 widget->outputs = con;
1101
Richard Purdie2b97eab2006-10-06 18:32:18 +02001102 return con;
1103}
1104
1105/*
1106 * Recursively check for a completed path to an active or physically connected
1107 * input widget. Returns number of complete paths.
1108 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001109static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001110 struct list_head *list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001111{
1112 struct snd_soc_dapm_path *path;
1113 int con = 0;
1114
Mark Brown024dc072011-10-09 11:52:05 +01001115 if (widget->inputs >= 0)
1116 return widget->inputs;
1117
Mark Brownde02d072011-09-20 21:43:24 +01001118 DAPM_UPDATE_STAT(widget, path_checks);
1119
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001120 /* do we need to add this widget to the list ? */
1121 if (list)
1122 list_add_tail(&widget->work_list, list);
1123
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001124 if (widget->is_source && widget->connected) {
1125 widget->inputs = snd_soc_dapm_suspend_check(widget);
1126 return widget->inputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001127 }
1128
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001129 snd_soc_dapm_widget_for_each_source_path(widget, path) {
Mark Browne56235e2011-09-21 18:19:14 +01001130 DAPM_UPDATE_STAT(widget, neighbour_checks);
1131
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001132 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001133 continue;
1134
Mark Brown8af294b2013-02-22 17:48:15 +00001135 if (path->walking)
1136 return 1;
1137
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001138 trace_snd_soc_dapm_input_path(widget, path);
1139
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001140 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001141 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001142 con += is_connected_input_ep(path->source, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001143 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001144 }
1145 }
1146
Mark Brown024dc072011-10-09 11:52:05 +01001147 widget->inputs = con;
1148
Richard Purdie2b97eab2006-10-06 18:32:18 +02001149 return con;
1150}
1151
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001152/**
1153 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1154 * @dai: the soc DAI.
1155 * @stream: stream direction.
1156 * @list: list of active widgets for this stream.
1157 *
1158 * Queries DAPM graph as to whether an valid audio stream path exists for
1159 * the initial stream specified by name. This takes into account
1160 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1161 *
1162 * Returns the number of valid paths or negative error.
1163 */
1164int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1165 struct snd_soc_dapm_widget_list **list)
1166{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001167 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001168 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001169 LIST_HEAD(widgets);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001170 int paths;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001171 int ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001172
1173 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001174
1175 /*
1176 * For is_connected_{output,input}_ep fully discover the graph we need
1177 * to reset the cached number of inputs and outputs.
1178 */
1179 list_for_each_entry(w, &card->widgets, list) {
1180 w->inputs = -1;
1181 w->outputs = -1;
1182 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001183
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001184 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001185 paths = is_connected_output_ep(dai->playback_widget, &widgets);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001186 else
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001187 paths = is_connected_input_ep(dai->capture_widget, &widgets);
1188
1189 /* Drop starting point */
1190 list_del(widgets.next);
1191
1192 ret = dapm_widget_list_create(list, &widgets);
1193 if (ret)
1194 return ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001195
1196 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001197 mutex_unlock(&card->dapm_mutex);
1198
1199 return paths;
1200}
1201
Richard Purdie2b97eab2006-10-06 18:32:18 +02001202/*
Mark Brown62ea8742012-01-21 21:14:48 +00001203 * Handler for regulator supply widget.
1204 */
1205int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1206 struct snd_kcontrol *kcontrol, int event)
1207{
Mark Brownc05b84d2012-09-07 12:57:11 +08001208 int ret;
1209
Mark Browneb270e92013-10-09 13:52:52 +01001210 soc_dapm_async_complete(w->dapm);
1211
Mark Brownc05b84d2012-09-07 12:57:11 +08001212 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001213 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001214 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001215 if (ret != 0)
1216 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001217 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001218 w->name, ret);
1219 }
1220
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001221 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001222 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001223 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001224 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001225 if (ret != 0)
1226 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001227 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001228 w->name, ret);
1229 }
1230
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001231 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001232 }
Mark Brown62ea8742012-01-21 21:14:48 +00001233}
1234EXPORT_SYMBOL_GPL(dapm_regulator_event);
1235
Ola Liljad7e7eb92012-05-24 15:26:25 +02001236/*
1237 * Handler for clock supply widget.
1238 */
1239int dapm_clock_event(struct snd_soc_dapm_widget *w,
1240 struct snd_kcontrol *kcontrol, int event)
1241{
1242 if (!w->clk)
1243 return -EIO;
1244
Mark Browneb270e92013-10-09 13:52:52 +01001245 soc_dapm_async_complete(w->dapm);
1246
Mark Brownec029952012-06-04 08:16:20 +01001247#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001248 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001249 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001250 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001251 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001252 return 0;
1253 }
Mark Brownec029952012-06-04 08:16:20 +01001254#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001255 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001256}
1257EXPORT_SYMBOL_GPL(dapm_clock_event);
1258
Mark Brownd8050022011-09-28 18:28:23 +01001259static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1260{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001261 if (w->power_checked)
1262 return w->new_power;
1263
Mark Brownd8050022011-09-28 18:28:23 +01001264 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001265 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001266 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001267 w->new_power = w->power_check(w);
1268
1269 w->power_checked = true;
1270
1271 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001272}
1273
Mark Browncd0f2d42009-04-20 16:56:59 +01001274/* Generic check to see if a widget should be powered.
1275 */
1276static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1277{
1278 int in, out;
1279
Mark Brownde02d072011-09-20 21:43:24 +01001280 DAPM_UPDATE_STAT(w, power_checks);
1281
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001282 in = is_connected_input_ep(w, NULL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001283 out = is_connected_output_ep(w, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001284 return out != 0 && in != 0;
1285}
1286
Mark Brown246d0a12009-04-22 18:24:55 +01001287/* Check to see if a power supply is needed */
1288static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1289{
1290 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001291
Mark Brownde02d072011-09-20 21:43:24 +01001292 DAPM_UPDATE_STAT(w, power_checks);
1293
Mark Brown246d0a12009-04-22 18:24:55 +01001294 /* Check if one of our outputs is connected */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001295 snd_soc_dapm_widget_for_each_sink_path(w, path) {
Mark Browna8fdac82011-09-28 18:20:26 +01001296 DAPM_UPDATE_STAT(w, neighbour_checks);
1297
Mark Brownbf3a9e12011-06-13 16:42:29 +01001298 if (path->weak)
1299 continue;
1300
Mark Brown215edda2009-09-08 18:59:05 +01001301 if (path->connected &&
1302 !path->connected(path->source, path->sink))
1303 continue;
1304
Mark Brownf68d7e12011-10-04 22:57:50 +01001305 if (dapm_widget_power_check(path->sink))
1306 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001307 }
1308
Mark Brownf68d7e12011-10-04 22:57:50 +01001309 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001310}
1311
Mark Brown35c64bc2011-09-28 18:23:53 +01001312static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1313{
1314 return 1;
1315}
1316
Mark Brown38357ab2009-06-06 19:03:23 +01001317static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1318 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001319 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001320{
Mark Brown828a8422011-01-15 13:14:30 +00001321 int *sort;
1322
1323 if (power_up)
1324 sort = dapm_up_seq;
1325 else
1326 sort = dapm_down_seq;
1327
Mark Brown38357ab2009-06-06 19:03:23 +01001328 if (sort[a->id] != sort[b->id])
1329 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001330 if (a->subseq != b->subseq) {
1331 if (power_up)
1332 return a->subseq - b->subseq;
1333 else
1334 return b->subseq - a->subseq;
1335 }
Mark Brownb22ead22009-06-07 12:51:26 +01001336 if (a->reg != b->reg)
1337 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001338 if (a->dapm != b->dapm)
1339 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001340
Mark Brown38357ab2009-06-06 19:03:23 +01001341 return 0;
1342}
Mark Brown42aa3412009-03-01 19:21:10 +00001343
Mark Brown38357ab2009-06-06 19:03:23 +01001344/* Insert a widget in order into a DAPM power sequence. */
1345static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1346 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001347 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001348{
1349 struct snd_soc_dapm_widget *w;
1350
1351 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001352 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001353 list_add_tail(&new_widget->power_list, &w->power_list);
1354 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001355 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001356
Mark Brown38357ab2009-06-06 19:03:23 +01001357 list_add_tail(&new_widget->power_list, list);
1358}
Mark Brown42aa3412009-03-01 19:21:10 +00001359
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001360static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001361 struct snd_soc_dapm_widget *w, int event)
1362{
Mark Brown68f89ad2010-11-03 23:51:49 -04001363 const char *ev_name;
1364 int power, ret;
1365
1366 switch (event) {
1367 case SND_SOC_DAPM_PRE_PMU:
1368 ev_name = "PRE_PMU";
1369 power = 1;
1370 break;
1371 case SND_SOC_DAPM_POST_PMU:
1372 ev_name = "POST_PMU";
1373 power = 1;
1374 break;
1375 case SND_SOC_DAPM_PRE_PMD:
1376 ev_name = "PRE_PMD";
1377 power = 0;
1378 break;
1379 case SND_SOC_DAPM_POST_PMD:
1380 ev_name = "POST_PMD";
1381 power = 0;
1382 break;
Mark Brown80114122013-02-25 15:14:19 +00001383 case SND_SOC_DAPM_WILL_PMU:
1384 ev_name = "WILL_PMU";
1385 power = 1;
1386 break;
1387 case SND_SOC_DAPM_WILL_PMD:
1388 ev_name = "WILL_PMD";
1389 power = 0;
1390 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001391 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001392 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001393 return;
1394 }
1395
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001396 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001397 return;
1398
1399 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001400 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001401 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001402 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001403 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001404 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001405 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001406 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001407 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001408 ev_name, w->name, ret);
1409 }
1410}
1411
Mark Brownb22ead22009-06-07 12:51:26 +01001412/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001413static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001414 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001415{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001416 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001417 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001418 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001419 unsigned int value = 0;
1420 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001421
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001422 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1423 reg = w->reg;
1424 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001425
1426 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001427 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001428 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001429
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001430 mask |= w->mask << w->shift;
1431 if (w->power)
1432 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001433 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001434 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001435
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001436 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001437 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1438 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001439
Mark Brown68f89ad2010-11-03 23:51:49 -04001440 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001441 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1442 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001443 }
1444
Mark Brown81628102009-06-07 13:21:24 +01001445 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001446 /* Any widget will do, they should all be updating the
1447 * same register.
1448 */
Mark Brown29376bc2011-06-19 13:49:28 +01001449
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001450 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001451 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001452 value, mask, reg, card->pop_time);
1453 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001454 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001455 }
1456
1457 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001458 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1459 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001460 }
Mark Brown42aa3412009-03-01 19:21:10 +00001461}
1462
Mark Brownb22ead22009-06-07 12:51:26 +01001463/* Apply a DAPM power sequence.
1464 *
1465 * We walk over a pre-sorted list of widgets to apply power to. In
1466 * order to minimise the number of writes to the device required
1467 * multiple widgets will be updated in a single write where possible.
1468 * Currently anything that requires more than a single write is not
1469 * handled.
1470 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001471static void dapm_seq_run(struct snd_soc_card *card,
1472 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001473{
1474 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001475 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001476 LIST_HEAD(pending);
1477 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001478 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001479 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001480 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001481 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001482 int *sort;
1483
1484 if (power_up)
1485 sort = dapm_up_seq;
1486 else
1487 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001488
Mark Brownb22ead22009-06-07 12:51:26 +01001489 list_for_each_entry_safe(w, n, list, power_list) {
1490 ret = 0;
1491
1492 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001493 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001494 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001495 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001496 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001497
Mark Brown474b62d2011-01-18 16:14:44 +00001498 if (cur_dapm && cur_dapm->seq_notifier) {
1499 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1500 if (sort[i] == cur_sort)
1501 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001502 i,
1503 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001504 }
1505
Mark Browneb270e92013-10-09 13:52:52 +01001506 if (cur_dapm && w->dapm != cur_dapm)
1507 soc_dapm_async_complete(cur_dapm);
1508
Mark Brownb22ead22009-06-07 12:51:26 +01001509 INIT_LIST_HEAD(&pending);
1510 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001511 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001512 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001513 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001514 }
1515
Mark Brown163cac02009-06-07 10:12:52 +01001516 switch (w->id) {
1517 case snd_soc_dapm_pre:
1518 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001519 list_for_each_entry_safe_continue(w, n, list,
1520 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001521
Mark Brownb22ead22009-06-07 12:51:26 +01001522 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001523 ret = w->event(w,
1524 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001525 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001526 ret = w->event(w,
1527 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001528 break;
1529
1530 case snd_soc_dapm_post:
1531 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001532 list_for_each_entry_safe_continue(w, n, list,
1533 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001534
Mark Brownb22ead22009-06-07 12:51:26 +01001535 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001536 ret = w->event(w,
1537 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001538 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001539 ret = w->event(w,
1540 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001541 break;
1542
Mark Brown163cac02009-06-07 10:12:52 +01001543 default:
Mark Brown81628102009-06-07 13:21:24 +01001544 /* Queue it up for application */
1545 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001546 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001547 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001548 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001549 list_move(&w->power_list, &pending);
1550 break;
Mark Brown163cac02009-06-07 10:12:52 +01001551 }
Mark Brownb22ead22009-06-07 12:51:26 +01001552
1553 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001554 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001555 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001556 }
Mark Brownb22ead22009-06-07 12:51:26 +01001557
1558 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001559 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001560
1561 if (cur_dapm && cur_dapm->seq_notifier) {
1562 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1563 if (sort[i] == cur_sort)
1564 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001565 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001566 }
Mark Browneb270e92013-10-09 13:52:52 +01001567
1568 list_for_each_entry(d, &card->dapm_list, list) {
1569 soc_dapm_async_complete(d);
1570 }
Mark Brown163cac02009-06-07 10:12:52 +01001571}
1572
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001573static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001574{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001575 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001576 struct snd_soc_dapm_widget_list *wlist;
1577 struct snd_soc_dapm_widget *w = NULL;
1578 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001579 int ret;
1580
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001581 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001582 return;
1583
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001584 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001585
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001586 for (wi = 0; wi < wlist->num_widgets; wi++) {
1587 w = wlist->widgets[wi];
1588
1589 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1590 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1591 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001592 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001593 w->name, ret);
1594 }
Mark Brown97404f22010-12-14 16:13:57 +00001595 }
1596
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001597 if (!w)
1598 return;
1599
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001600 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1601 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001602 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001603 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001604 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001605
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001606 for (wi = 0; wi < wlist->num_widgets; wi++) {
1607 w = wlist->widgets[wi];
1608
1609 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1610 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1611 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001612 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001613 w->name, ret);
1614 }
Mark Brown97404f22010-12-14 16:13:57 +00001615 }
1616}
1617
Mark Brown9d0624a2011-02-18 11:49:43 -08001618/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1619 * they're changing state.
1620 */
1621static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1622{
1623 struct snd_soc_dapm_context *d = data;
1624 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001625
Mark Brown56fba412011-06-04 11:25:10 +01001626 /* If we're off and we're not supposed to be go into STANDBY */
1627 if (d->bias_level == SND_SOC_BIAS_OFF &&
1628 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001629 if (d->dev)
1630 pm_runtime_get_sync(d->dev);
1631
Mark Brown9d0624a2011-02-18 11:49:43 -08001632 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1633 if (ret != 0)
1634 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001635 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001636 }
1637
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001638 /* Prepare for a transition to ON or away from ON */
1639 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1640 d->bias_level != SND_SOC_BIAS_ON) ||
1641 (d->target_bias_level != SND_SOC_BIAS_ON &&
1642 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001643 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1644 if (ret != 0)
1645 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001646 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001647 }
1648}
1649
1650/* Async callback run prior to DAPM sequences - brings to their final
1651 * state.
1652 */
1653static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1654{
1655 struct snd_soc_dapm_context *d = data;
1656 int ret;
1657
1658 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001659 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1660 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1661 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001662 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1663 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001664 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001665 ret);
1666 }
1667
1668 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001669 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1670 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001671 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1672 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001673 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1674 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001675
1676 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001677 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001678 }
1679
1680 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001681 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1682 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001683 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1684 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001685 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001686 ret);
1687 }
1688}
Mark Brown97404f22010-12-14 16:13:57 +00001689
Mark Brownfe4fda52011-10-03 22:36:57 +01001690static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1691 bool power, bool connect)
1692{
1693 /* If a connection is being made or broken then that update
1694 * will have marked the peer dirty, otherwise the widgets are
1695 * not connected and this update has no impact. */
1696 if (!connect)
1697 return;
1698
1699 /* If the peer is already in the state we're moving to then we
1700 * won't have an impact on it. */
1701 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001702 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001703}
1704
Mark Brown05623c42011-09-28 17:02:31 +01001705static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1706 struct list_head *up_list,
1707 struct list_head *down_list)
1708{
Mark Browndb432b42011-10-03 21:06:40 +01001709 struct snd_soc_dapm_path *path;
1710
Mark Brown05623c42011-09-28 17:02:31 +01001711 if (w->power == power)
1712 return;
1713
1714 trace_snd_soc_dapm_widget_power(w, power);
1715
Mark Browndb432b42011-10-03 21:06:40 +01001716 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001717 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001718 */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001719 snd_soc_dapm_widget_for_each_source_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001720 dapm_widget_set_peer_power(path->source, power, path->connect);
1721
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001722 /* Supplies can't affect their outputs, only their inputs */
1723 if (!w->is_supply) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001724 snd_soc_dapm_widget_for_each_sink_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001725 dapm_widget_set_peer_power(path->sink, power,
1726 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001727 }
1728
Mark Brown05623c42011-09-28 17:02:31 +01001729 if (power)
1730 dapm_seq_insert(w, up_list, true);
1731 else
1732 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001733}
1734
Mark Brown7c81beb2011-09-20 22:22:32 +01001735static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1736 struct list_head *up_list,
1737 struct list_head *down_list)
1738{
Mark Brown7c81beb2011-09-20 22:22:32 +01001739 int power;
1740
1741 switch (w->id) {
1742 case snd_soc_dapm_pre:
1743 dapm_seq_insert(w, down_list, false);
1744 break;
1745 case snd_soc_dapm_post:
1746 dapm_seq_insert(w, up_list, true);
1747 break;
1748
1749 default:
Mark Brownd8050022011-09-28 18:28:23 +01001750 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001751
Mark Brown05623c42011-09-28 17:02:31 +01001752 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001753 break;
1754 }
1755}
1756
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001757static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1758{
1759 if (dapm->idle_bias_off)
1760 return true;
1761
1762 switch (snd_power_get_state(dapm->card->snd_card)) {
1763 case SNDRV_CTL_POWER_D3hot:
1764 case SNDRV_CTL_POWER_D3cold:
1765 return dapm->suspend_bias_off;
1766 default:
1767 break;
1768 }
1769
1770 return false;
1771}
1772
Mark Brown42aa3412009-03-01 19:21:10 +00001773/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001774 * Scan each dapm widget for complete audio path.
1775 * A complete path is a route that has valid endpoints i.e.:-
1776 *
1777 * o DAC to output pin.
1778 * o Input Pin to ADC.
1779 * o Input pin to Output pin (bypass, sidetone)
1780 * o DAC to ADC (loopback).
1781 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001782static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001783{
1784 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001785 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001786 LIST_HEAD(up_list);
1787 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001788 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001789 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001790
Mark Brownf9fa2b12014-03-06 16:49:11 +08001791 lockdep_assert_held(&card->dapm_mutex);
1792
Mark Brown84e90932010-11-04 00:07:02 -04001793 trace_snd_soc_dapm_start(card);
1794
Mark Brown56fba412011-06-04 11:25:10 +01001795 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001796 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001797 d->target_bias_level = SND_SOC_BIAS_OFF;
1798 else
1799 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001800 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001801
Liam Girdwood6c120e12012-02-15 15:15:34 +00001802 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001803
Mark Brown6d3ddc82009-05-16 17:47:29 +01001804 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001805 * lists indicating if they should be powered up or down. We
1806 * only check widgets that have been flagged as dirty but note
1807 * that new widgets may be added to the dirty list while we
1808 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001809 */
Mark Browndb432b42011-10-03 21:06:40 +01001810 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001811 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001812 }
1813
Mark Brownf9de6d72011-09-28 17:19:47 +01001814 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001815 switch (w->id) {
1816 case snd_soc_dapm_pre:
1817 case snd_soc_dapm_post:
1818 /* These widgets always need to be powered */
1819 break;
1820 default:
1821 list_del_init(&w->dirty);
1822 break;
1823 }
Mark Browndb432b42011-10-03 21:06:40 +01001824
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001825 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001826 d = w->dapm;
1827
1828 /* Supplies and micbiases only bring the
1829 * context up to STANDBY as unless something
1830 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001831 * generally don't require full power. Signal
1832 * generators are virtual pins and have no
1833 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001834 */
1835 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001836 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001837 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001838 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001839 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001840 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001841 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001842 case snd_soc_dapm_micbias:
1843 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1844 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1845 break;
1846 default:
1847 d->target_bias_level = SND_SOC_BIAS_ON;
1848 break;
1849 }
1850 }
1851
1852 }
1853
Mark Brown85a843c2011-09-21 21:29:47 +01001854 /* Force all contexts in the card to the same bias state if
1855 * they're not ground referenced.
1856 */
Mark Brown56fba412011-06-04 11:25:10 +01001857 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001858 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001859 if (d->target_bias_level > bias)
1860 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001861 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001862 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001863 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001864
Mark Brownde02d072011-09-20 21:43:24 +01001865 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001866
Xiang Xiao17282ba2014-03-02 00:04:03 +08001867 /* Run card bias changes at first */
1868 dapm_pre_sequence_async(&card->dapm, 0);
1869 /* Run other bias changes in parallel */
1870 list_for_each_entry(d, &card->dapm_list, list) {
1871 if (d != &card->dapm)
1872 async_schedule_domain(dapm_pre_sequence_async, d,
1873 &async_domain);
1874 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001875 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001876
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001877 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001878 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001879 }
1880
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001881 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001882 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001883 }
1884
Mark Brown6d3ddc82009-05-16 17:47:29 +01001885 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001886 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001887
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001888 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001889
Mark Brown6d3ddc82009-05-16 17:47:29 +01001890 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001891 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001892
Mark Brown9d0624a2011-02-18 11:49:43 -08001893 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001894 list_for_each_entry(d, &card->dapm_list, list) {
1895 if (d != &card->dapm)
1896 async_schedule_domain(dapm_post_sequence_async, d,
1897 &async_domain);
1898 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001899 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001900 /* Run card bias changes at last */
1901 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001902
Liam Girdwood8078d872012-02-15 15:15:35 +00001903 /* do we need to notify any clients that DAPM event is complete */
1904 list_for_each_entry(d, &card->dapm_list, list) {
1905 if (d->stream_event)
1906 d->stream_event(d, event);
1907 }
1908
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001909 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001910 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001911 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001912
Mark Brown84e90932010-11-04 00:07:02 -04001913 trace_snd_soc_dapm_done(card);
1914
Mark Brown42aa3412009-03-01 19:21:10 +00001915 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001916}
1917
Mark Brown79fb9382009-08-21 16:38:13 +01001918#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001919static ssize_t dapm_widget_power_read_file(struct file *file,
1920 char __user *user_buf,
1921 size_t count, loff_t *ppos)
1922{
1923 struct snd_soc_dapm_widget *w = file->private_data;
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001924 struct snd_soc_card *card = w->dapm->card;
Mark Brown79fb9382009-08-21 16:38:13 +01001925 char *buf;
1926 int in, out;
1927 ssize_t ret;
1928 struct snd_soc_dapm_path *p = NULL;
1929
1930 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1931 if (!buf)
1932 return -ENOMEM;
1933
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001934 mutex_lock(&card->dapm_mutex);
1935
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001936 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
1937 if (w->is_supply) {
1938 in = 0;
1939 out = 0;
1940 } else {
1941 in = is_connected_input_ep(w, NULL);
1942 out = is_connected_output_ep(w, NULL);
1943 }
Mark Brown79fb9382009-08-21 16:38:13 +01001944
Mark Brownf13ebad2012-03-03 18:01:01 +00001945 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1946 w->name, w->power ? "On" : "Off",
1947 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001948
Mark Brownd033c362009-12-04 15:25:56 +00001949 if (w->reg >= 0)
1950 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001951 " - R%d(0x%x) mask 0x%x",
1952 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00001953
1954 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1955
Mark Brown3eef08b2009-09-14 16:49:00 +01001956 if (w->sname)
1957 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1958 w->sname,
1959 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001960
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001961 snd_soc_dapm_widget_for_each_source_path(w, p) {
Takashi Iwaiff186202013-10-28 14:21:49 +01001962 if (p->connected && !p->connected(w, p->source))
Mark Brown215edda2009-09-08 18:59:05 +01001963 continue;
1964
Mark Brown79fb9382009-08-21 16:38:13 +01001965 if (p->connect)
1966 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001967 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001968 p->name ? p->name : "static",
1969 p->source->name);
1970 }
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001971 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Mark Brown215edda2009-09-08 18:59:05 +01001972 if (p->connected && !p->connected(w, p->sink))
1973 continue;
1974
Mark Brown79fb9382009-08-21 16:38:13 +01001975 if (p->connect)
1976 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001977 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001978 p->name ? p->name : "static",
1979 p->sink->name);
1980 }
1981
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001982 mutex_unlock(&card->dapm_mutex);
1983
Mark Brown79fb9382009-08-21 16:38:13 +01001984 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1985
1986 kfree(buf);
1987 return ret;
1988}
1989
1990static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001991 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01001992 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001993 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001994};
1995
Mark Brownef49e4f2011-04-04 20:48:13 +09001996static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1997 size_t count, loff_t *ppos)
1998{
1999 struct snd_soc_dapm_context *dapm = file->private_data;
2000 char *level;
2001
2002 switch (dapm->bias_level) {
2003 case SND_SOC_BIAS_ON:
2004 level = "On\n";
2005 break;
2006 case SND_SOC_BIAS_PREPARE:
2007 level = "Prepare\n";
2008 break;
2009 case SND_SOC_BIAS_STANDBY:
2010 level = "Standby\n";
2011 break;
2012 case SND_SOC_BIAS_OFF:
2013 level = "Off\n";
2014 break;
2015 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002016 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002017 level = "Unknown\n";
2018 break;
2019 }
2020
2021 return simple_read_from_buffer(user_buf, count, ppos, level,
2022 strlen(level));
2023}
2024
2025static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002026 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002027 .read = dapm_bias_read_file,
2028 .llseek = default_llseek,
2029};
2030
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002031void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2032 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002033{
Mark Brown79fb9382009-08-21 16:38:13 +01002034 struct dentry *d;
2035
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002036 if (!parent)
2037 return;
2038
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002039 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2040
2041 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002042 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002043 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002044 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002045 }
Mark Brown79fb9382009-08-21 16:38:13 +01002046
Mark Brownef49e4f2011-04-04 20:48:13 +09002047 d = debugfs_create_file("bias_level", 0444,
2048 dapm->debugfs_dapm, dapm,
2049 &dapm_bias_fops);
2050 if (!d)
2051 dev_warn(dapm->dev,
2052 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002053}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002054
2055static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2056{
2057 struct snd_soc_dapm_context *dapm = w->dapm;
2058 struct dentry *d;
2059
2060 if (!dapm->debugfs_dapm || !w->name)
2061 return;
2062
2063 d = debugfs_create_file(w->name, 0444,
2064 dapm->debugfs_dapm, w,
2065 &dapm_widget_power_fops);
2066 if (!d)
2067 dev_warn(w->dapm->dev,
2068 "ASoC: Failed to create %s debugfs file\n",
2069 w->name);
2070}
2071
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002072static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2073{
2074 debugfs_remove_recursive(dapm->debugfs_dapm);
2075}
2076
Mark Brown79fb9382009-08-21 16:38:13 +01002077#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002078void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2079 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002080{
2081}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002082
2083static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2084{
2085}
2086
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002087static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2088{
2089}
2090
Mark Brown79fb9382009-08-21 16:38:13 +01002091#endif
2092
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002093/*
2094 * soc_dapm_connect_path() - Connects or disconnects a path
2095 * @path: The path to update
2096 * @connect: The new connect state of the path. True if the path is connected,
2097 * false if it is disconneted.
2098 * @reason: The reason why the path changed (for debugging only)
2099 */
2100static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2101 bool connect, const char *reason)
2102{
2103 if (path->connect == connect)
2104 return;
2105
2106 path->connect = connect;
2107 dapm_mark_dirty(path->source, reason);
2108 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002109 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002110}
2111
Richard Purdie2b97eab2006-10-06 18:32:18 +02002112/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002113static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002114 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002115{
2116 struct snd_soc_dapm_path *path;
2117 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002118 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002119
Mark Brownf9fa2b12014-03-06 16:49:11 +08002120 lockdep_assert_held(&card->dapm_mutex);
2121
Richard Purdie2b97eab2006-10-06 18:32:18 +02002122 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002123 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002124 found = 1;
2125 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002126 if (!(strcmp(path->name, e->texts[mux])))
2127 connect = true;
2128 else
2129 connect = false;
2130
2131 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002132 }
2133
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002134 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002135 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002136
Liam Girdwood618dae12012-04-25 12:12:51 +01002137 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002138}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002139
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002140int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002141 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2142 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002143{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002144 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002145 int ret;
2146
Liam Girdwood3cd04342012-03-09 12:02:08 +00002147 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002148 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002149 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002150 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002151 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002152 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002153 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002154 return ret;
2155}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002156EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002157
Milan plzik1b075e32008-01-10 14:39:46 +01002158/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002159static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Mark Brown283375c2009-12-07 18:09:03 +00002160 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002161{
2162 struct snd_soc_dapm_path *path;
2163 int found = 0;
2164
Mark Brownf9fa2b12014-03-06 16:49:11 +08002165 lockdep_assert_held(&card->dapm_mutex);
2166
Richard Purdie2b97eab2006-10-06 18:32:18 +02002167 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002168 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002169 found = 1;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002170 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002171 }
2172
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002173 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002174 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002175
Liam Girdwood618dae12012-04-25 12:12:51 +01002176 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002177}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002178
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002179int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002180 struct snd_kcontrol *kcontrol, int connect,
2181 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002182{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002183 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002184 int ret;
2185
Liam Girdwood3cd04342012-03-09 12:02:08 +00002186 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002187 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002188 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002189 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002190 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002191 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002192 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002193 return ret;
2194}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002195EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002196
Benoit Cousson44ba2642014-07-08 23:19:36 +02002197static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002198{
Richard Purdie2b97eab2006-10-06 18:32:18 +02002199 struct snd_soc_dapm_widget *w;
2200 int count = 0;
2201 char *state = "not set";
2202
Lars-Peter Clausen00200102014-07-17 22:01:07 +02002203 list_for_each_entry(w, &codec->component.card->widgets, list) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002204 if (w->dapm != &codec->dapm)
2205 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002206
2207 /* only display widgets that burnm power */
2208 switch (w->id) {
2209 case snd_soc_dapm_hp:
2210 case snd_soc_dapm_mic:
2211 case snd_soc_dapm_spk:
2212 case snd_soc_dapm_line:
2213 case snd_soc_dapm_micbias:
2214 case snd_soc_dapm_dac:
2215 case snd_soc_dapm_adc:
2216 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002217 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002218 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002219 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002220 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002221 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002222 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002223 if (w->name)
2224 count += sprintf(buf + count, "%s: %s\n",
2225 w->name, w->power ? "On":"Off");
2226 break;
2227 default:
2228 break;
2229 }
2230 }
2231
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002232 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02002233 case SND_SOC_BIAS_ON:
2234 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002235 break;
Mark Brown0be98982008-05-19 12:31:28 +02002236 case SND_SOC_BIAS_PREPARE:
2237 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002238 break;
Mark Brown0be98982008-05-19 12:31:28 +02002239 case SND_SOC_BIAS_STANDBY:
2240 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002241 break;
Mark Brown0be98982008-05-19 12:31:28 +02002242 case SND_SOC_BIAS_OFF:
2243 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002244 break;
2245 }
2246 count += sprintf(buf + count, "PM State: %s\n", state);
2247
2248 return count;
2249}
2250
Benoit Cousson44ba2642014-07-08 23:19:36 +02002251/* show dapm widget status in sys fs */
2252static ssize_t dapm_widget_show(struct device *dev,
2253 struct device_attribute *attr, char *buf)
2254{
2255 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2256 int i, count = 0;
2257
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002258 mutex_lock(&rtd->card->dapm_mutex);
2259
Benoit Cousson44ba2642014-07-08 23:19:36 +02002260 for (i = 0; i < rtd->num_codecs; i++) {
2261 struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
2262 count += dapm_widget_show_codec(codec, buf + count);
2263 }
2264
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002265 mutex_unlock(&rtd->card->dapm_mutex);
2266
Benoit Cousson44ba2642014-07-08 23:19:36 +02002267 return count;
2268}
2269
Richard Purdie2b97eab2006-10-06 18:32:18 +02002270static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2271
Takashi Iwaid29697d2015-01-30 20:16:37 +01002272struct attribute *soc_dapm_dev_attrs[] = {
2273 &dev_attr_dapm_widget.attr,
2274 NULL
2275};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002276
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002277static void dapm_free_path(struct snd_soc_dapm_path *path)
2278{
2279 list_del(&path->list_sink);
2280 list_del(&path->list_source);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002281 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002282 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002283 kfree(path);
2284}
2285
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002286void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2287{
2288 struct snd_soc_dapm_path *p, *next_p;
2289
2290 list_del(&w->list);
2291 /*
2292 * remove source and sink paths associated to this widget.
2293 * While removing the path, remove reference to it from both
2294 * source and sink widgets so that path is removed only once.
2295 */
2296 list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
2297 dapm_free_path(p);
2298
2299 list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
2300 dapm_free_path(p);
2301
2302 kfree(w->kcontrols);
Lars-Peter Clausen48068962015-07-21 18:11:08 +02002303 kfree_const(w->name);
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002304 kfree(w);
2305}
2306
Richard Purdie2b97eab2006-10-06 18:32:18 +02002307/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002308static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002309{
2310 struct snd_soc_dapm_widget *w, *next_w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002311
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002312 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2313 if (w->dapm != dapm)
2314 continue;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002315 snd_soc_dapm_free_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002316 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002317}
2318
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002319static struct snd_soc_dapm_widget *dapm_find_widget(
2320 struct snd_soc_dapm_context *dapm, const char *pin,
2321 bool search_other_contexts)
2322{
2323 struct snd_soc_dapm_widget *w;
2324 struct snd_soc_dapm_widget *fallback = NULL;
2325
2326 list_for_each_entry(w, &dapm->card->widgets, list) {
2327 if (!strcmp(w->name, pin)) {
2328 if (w->dapm == dapm)
2329 return w;
2330 else
2331 fallback = w;
2332 }
2333 }
2334
2335 if (search_other_contexts)
2336 return fallback;
2337
2338 return NULL;
2339}
2340
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002341static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002342 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002343{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002344 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002345
Mark Brownf9fa2b12014-03-06 16:49:11 +08002346 dapm_assert_locked(dapm);
2347
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002348 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002349 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002350 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002351 }
2352
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002353 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002354 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002355 dapm_widget_invalidate_input_paths(w);
2356 dapm_widget_invalidate_output_paths(w);
2357 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002358
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002359 w->connected = status;
2360 if (status == 0)
2361 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002362
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002363 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002364}
2365
Richard Purdie2b97eab2006-10-06 18:32:18 +02002366/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002367 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2368 * @dapm: DAPM context
2369 *
2370 * Walks all dapm audio paths and powers widgets according to their
2371 * stream or path usage.
2372 *
2373 * Requires external locking.
2374 *
2375 * Returns 0 for success.
2376 */
2377int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2378{
2379 /*
2380 * Suppress early reports (eg, jacks syncing their state) to avoid
2381 * silly DAPM runs during card startup.
2382 */
2383 if (!dapm->card || !dapm->card->instantiated)
2384 return 0;
2385
2386 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2387}
2388EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2389
2390/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002391 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002392 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002393 *
2394 * Walks all dapm audio paths and powers widgets according to their
2395 * stream or path usage.
2396 *
2397 * Returns 0 for success.
2398 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002399int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002400{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002401 int ret;
2402
Liam Girdwood3cd04342012-03-09 12:02:08 +00002403 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002404 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002405 mutex_unlock(&dapm->card->dapm_mutex);
2406 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002407}
Liam Girdwooda5302182008-07-07 13:35:17 +01002408EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002409
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002410/*
2411 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2412 * @w: The widget for which to update the flags
2413 *
2414 * Some widgets have a dynamic category which depends on which neighbors they
2415 * are connected to. This function update the category for these widgets.
2416 *
2417 * This function must be called whenever a path is added or removed to a widget.
2418 */
2419static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2420{
2421 struct snd_soc_dapm_path *p;
2422
2423 switch (w->id) {
2424 case snd_soc_dapm_input:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002425 /* On a fully routed card a input is never a source */
2426 if (w->dapm->card->fully_routed)
2427 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002428 w->is_source = 1;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002429 snd_soc_dapm_widget_for_each_source_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002430 if (p->source->id == snd_soc_dapm_micbias ||
2431 p->source->id == snd_soc_dapm_mic ||
2432 p->source->id == snd_soc_dapm_line ||
2433 p->source->id == snd_soc_dapm_output) {
2434 w->is_source = 0;
2435 break;
2436 }
2437 }
2438 break;
2439 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002440 /* On a fully routed card a output is never a sink */
2441 if (w->dapm->card->fully_routed)
2442 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002443 w->is_sink = 1;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002444 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002445 if (p->sink->id == snd_soc_dapm_spk ||
2446 p->sink->id == snd_soc_dapm_hp ||
2447 p->sink->id == snd_soc_dapm_line ||
2448 p->sink->id == snd_soc_dapm_input) {
2449 w->is_sink = 0;
2450 break;
2451 }
2452 }
2453 break;
2454 case snd_soc_dapm_line:
2455 w->is_sink = !list_empty(&w->sources);
2456 w->is_source = !list_empty(&w->sinks);
2457 break;
2458 default:
2459 break;
2460 }
2461}
2462
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002463static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2464 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2465 const char *control)
2466{
2467 bool dynamic_source = false;
2468 bool dynamic_sink = false;
2469
2470 if (!control)
2471 return 0;
2472
2473 switch (source->id) {
2474 case snd_soc_dapm_demux:
2475 dynamic_source = true;
2476 break;
2477 default:
2478 break;
2479 }
2480
2481 switch (sink->id) {
2482 case snd_soc_dapm_mux:
2483 case snd_soc_dapm_switch:
2484 case snd_soc_dapm_mixer:
2485 case snd_soc_dapm_mixer_named_ctl:
2486 dynamic_sink = true;
2487 break;
2488 default:
2489 break;
2490 }
2491
2492 if (dynamic_source && dynamic_sink) {
2493 dev_err(dapm->dev,
2494 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2495 source->name, control, sink->name);
2496 return -EINVAL;
2497 } else if (!dynamic_source && !dynamic_sink) {
2498 dev_err(dapm->dev,
2499 "Control not supported for path %s -> [%s] -> %s\n",
2500 source->name, control, sink->name);
2501 return -EINVAL;
2502 }
2503
2504 return 0;
2505}
2506
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002507static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2508 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2509 const char *control,
2510 int (*connected)(struct snd_soc_dapm_widget *source,
2511 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002512{
2513 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002514 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002515
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002516 if (wsink->is_supply && !wsource->is_supply) {
2517 dev_err(dapm->dev,
2518 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2519 wsource->name, wsink->name);
2520 return -EINVAL;
2521 }
2522
2523 if (connected && !wsource->is_supply) {
2524 dev_err(dapm->dev,
2525 "connected() callback only supported for supply widgets (%s -> %s)\n",
2526 wsource->name, wsink->name);
2527 return -EINVAL;
2528 }
2529
2530 if (wsource->is_supply && control) {
2531 dev_err(dapm->dev,
2532 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2533 wsource->name, control, wsink->name);
2534 return -EINVAL;
2535 }
2536
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002537 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2538 if (ret)
2539 return ret;
2540
Richard Purdie2b97eab2006-10-06 18:32:18 +02002541 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2542 if (!path)
2543 return -ENOMEM;
2544
2545 path->source = wsource;
2546 path->sink = wsink;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002547 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002548 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002549 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002550 INIT_LIST_HEAD(&path->list_source);
2551 INIT_LIST_HEAD(&path->list_sink);
2552
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002553 if (wsource->is_supply || wsink->is_supply)
2554 path->is_supply = 1;
2555
Richard Purdie2b97eab2006-10-06 18:32:18 +02002556 /* connect static paths */
2557 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002558 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002559 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002560 switch (wsource->id) {
2561 case snd_soc_dapm_demux:
2562 ret = dapm_connect_mux(dapm, path, control, wsource);
2563 if (ret)
2564 goto err;
2565 break;
2566 default:
2567 break;
2568 }
2569
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002570 switch (wsink->id) {
2571 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002572 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002573 if (ret != 0)
2574 goto err;
2575 break;
2576 case snd_soc_dapm_switch:
2577 case snd_soc_dapm_mixer:
2578 case snd_soc_dapm_mixer_named_ctl:
2579 ret = dapm_connect_mixer(dapm, path, control);
2580 if (ret != 0)
2581 goto err;
2582 break;
2583 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002584 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002585 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002586 }
2587
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002588 list_add(&path->list, &dapm->card->paths);
2589 list_add(&path->list_sink, &wsink->sources);
2590 list_add(&path->list_source, &wsource->sinks);
2591
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002592 dapm_update_widget_flags(wsource);
2593 dapm_update_widget_flags(wsink);
2594
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002595 dapm_mark_dirty(wsource, "Route added");
2596 dapm_mark_dirty(wsink, "Route added");
Mark Brownfabd0382012-07-05 17:20:06 +01002597
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002598 if (dapm->card->instantiated && path->connect)
2599 dapm_path_invalidate(path);
2600
Richard Purdie2b97eab2006-10-06 18:32:18 +02002601 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002602err:
2603 kfree(path);
2604 return ret;
2605}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002606
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002607static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002608 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002609{
2610 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2611 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2612 const char *sink;
2613 const char *source;
2614 char prefixed_sink[80];
2615 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002616 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002617 int ret;
2618
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002619 prefix = soc_dapm_prefix(dapm);
2620 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002621 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002622 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002623 sink = prefixed_sink;
2624 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002625 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002626 source = prefixed_source;
2627 } else {
2628 sink = route->sink;
2629 source = route->source;
2630 }
2631
Charles Keepax45a110a2015-05-11 13:50:30 +01002632 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2633 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2634
2635 if (wsink && wsource)
2636 goto skip_search;
2637
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002638 /*
2639 * find src and dest widgets over all widgets but favor a widget from
2640 * current DAPM context
2641 */
2642 list_for_each_entry(w, &dapm->card->widgets, list) {
2643 if (!wsink && !(strcmp(w->name, sink))) {
2644 wtsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002645 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002646 wsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002647 if (wsource)
2648 break;
2649 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002650 continue;
2651 }
2652 if (!wsource && !(strcmp(w->name, source))) {
2653 wtsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002654 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002655 wsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002656 if (wsink)
2657 break;
2658 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002659 }
2660 }
2661 /* use widget from another DAPM context if not found from this */
2662 if (!wsink)
2663 wsink = wtsink;
2664 if (!wsource)
2665 wsource = wtsource;
2666
2667 if (wsource == NULL) {
2668 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2669 route->source);
2670 return -ENODEV;
2671 }
2672 if (wsink == NULL) {
2673 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2674 route->sink);
2675 return -ENODEV;
2676 }
2677
Charles Keepax45a110a2015-05-11 13:50:30 +01002678skip_search:
2679 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2680 dapm_wcache_update(&dapm->path_source_cache, wsource);
2681
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002682 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2683 route->connected);
2684 if (ret)
2685 goto err;
2686
2687 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002688err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002689 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002690 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002691 return ret;
2692}
Mark Brown105f1c22008-05-13 14:52:19 +02002693
Mark Brownefcc3c62012-07-05 17:24:19 +01002694static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2695 const struct snd_soc_dapm_route *route)
2696{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002697 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002698 struct snd_soc_dapm_path *path, *p;
2699 const char *sink;
2700 const char *source;
2701 char prefixed_sink[80];
2702 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002703 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002704
2705 if (route->control) {
2706 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002707 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002708 return -EINVAL;
2709 }
2710
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002711 prefix = soc_dapm_prefix(dapm);
2712 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002713 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002714 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002715 sink = prefixed_sink;
2716 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002717 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002718 source = prefixed_source;
2719 } else {
2720 sink = route->sink;
2721 source = route->source;
2722 }
2723
2724 path = NULL;
2725 list_for_each_entry(p, &dapm->card->paths, list) {
2726 if (strcmp(p->source->name, source) != 0)
2727 continue;
2728 if (strcmp(p->sink->name, sink) != 0)
2729 continue;
2730 path = p;
2731 break;
2732 }
2733
2734 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002735 wsource = path->source;
2736 wsink = path->sink;
2737
2738 dapm_mark_dirty(wsource, "Route removed");
2739 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002740 if (path->connect)
2741 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002742
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002743 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002744
2745 /* Update any path related flags */
2746 dapm_update_widget_flags(wsource);
2747 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002748 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002749 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002750 source, sink);
2751 }
2752
2753 return 0;
2754}
2755
Mark Brown105f1c22008-05-13 14:52:19 +02002756/**
Mark Brown105f1c22008-05-13 14:52:19 +02002757 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002758 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002759 * @route: audio routes
2760 * @num: number of routes
2761 *
2762 * Connects 2 dapm widgets together via a named audio path. The sink is
2763 * the widget receiving the audio signal, whilst the source is the sender
2764 * of the audio signal.
2765 *
2766 * Returns 0 for success else error. On error all resources can be freed
2767 * with a call to snd_soc_card_free().
2768 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002769int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002770 const struct snd_soc_dapm_route *route, int num)
2771{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002772 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002773
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002774 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002775 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002776 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002777 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002778 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2779 route->source,
2780 route->control ? route->control : "direct",
2781 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002782 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002783 }
2784 route++;
2785 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002786 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002787
Dan Carpenter60884c22012-04-13 22:25:43 +03002788 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002789}
2790EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2791
Mark Brownefcc3c62012-07-05 17:24:19 +01002792/**
2793 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2794 * @dapm: DAPM context
2795 * @route: audio routes
2796 * @num: number of routes
2797 *
2798 * Removes routes from the DAPM context.
2799 */
2800int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2801 const struct snd_soc_dapm_route *route, int num)
2802{
2803 int i, ret = 0;
2804
2805 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2806 for (i = 0; i < num; i++) {
2807 snd_soc_dapm_del_route(dapm, route);
2808 route++;
2809 }
2810 mutex_unlock(&dapm->card->dapm_mutex);
2811
2812 return ret;
2813}
2814EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2815
Mark Brownbf3a9e12011-06-13 16:42:29 +01002816static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2817 const struct snd_soc_dapm_route *route)
2818{
2819 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2820 route->source,
2821 true);
2822 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2823 route->sink,
2824 true);
2825 struct snd_soc_dapm_path *path;
2826 int count = 0;
2827
2828 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002829 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002830 route->source);
2831 return -ENODEV;
2832 }
2833
2834 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002835 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002836 route->sink);
2837 return -ENODEV;
2838 }
2839
2840 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002841 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002842 route->source, route->sink);
2843
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002844 snd_soc_dapm_widget_for_each_sink_path(source, path) {
Mark Brownbf3a9e12011-06-13 16:42:29 +01002845 if (path->sink == sink) {
2846 path->weak = 1;
2847 count++;
2848 }
2849 }
2850
2851 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002852 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002853 route->source, route->sink);
2854 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002855 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002856 count, route->source, route->sink);
2857
2858 return 0;
2859}
2860
2861/**
2862 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2863 * @dapm: DAPM context
2864 * @route: audio routes
2865 * @num: number of routes
2866 *
2867 * Mark existing routes matching those specified in the passed array
2868 * as being weak, meaning that they are ignored for the purpose of
2869 * power decisions. The main intended use case is for sidetone paths
2870 * which couple audio between other independent paths if they are both
2871 * active in order to make the combination work better at the user
2872 * level but which aren't intended to be "used".
2873 *
2874 * Note that CODEC drivers should not use this as sidetone type paths
2875 * can frequently also be used as bypass paths.
2876 */
2877int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2878 const struct snd_soc_dapm_route *route, int num)
2879{
2880 int i, err;
2881 int ret = 0;
2882
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002883 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002884 for (i = 0; i < num; i++) {
2885 err = snd_soc_dapm_weak_route(dapm, route);
2886 if (err)
2887 ret = err;
2888 route++;
2889 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002890 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002891
2892 return ret;
2893}
2894EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2895
Mark Brown105f1c22008-05-13 14:52:19 +02002896/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002897 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002898 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002899 *
2900 * Checks the codec for any new dapm widgets and creates them if found.
2901 *
2902 * Returns 0 for success.
2903 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02002904int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002905{
2906 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002907 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002908
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002909 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002910
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002911 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002912 {
2913 if (w->new)
2914 continue;
2915
Stephen Warrenfad59882011-04-28 17:37:59 -06002916 if (w->num_kcontrols) {
2917 w->kcontrols = kzalloc(w->num_kcontrols *
2918 sizeof(struct snd_kcontrol *),
2919 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002920 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002921 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002922 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002923 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002924 }
2925
Richard Purdie2b97eab2006-10-06 18:32:18 +02002926 switch(w->id) {
2927 case snd_soc_dapm_switch:
2928 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002929 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002930 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002931 break;
2932 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002933 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002934 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002935 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002936 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002937 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002938 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002939 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00002940 case snd_soc_dapm_dai_link:
2941 dapm_new_dai_link(w);
2942 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002943 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002944 break;
2945 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002946
2947 /* Read the initial power state from the device */
2948 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002949 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08002950 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002951 val &= w->mask;
2952 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00002953 w->power = 1;
2954 }
2955
Richard Purdie2b97eab2006-10-06 18:32:18 +02002956 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002957
Mark Brown7508b122011-10-05 12:09:12 +01002958 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002959 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002960 }
2961
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002962 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2963 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002964 return 0;
2965}
2966EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2967
2968/**
2969 * snd_soc_dapm_get_volsw - dapm mixer get callback
2970 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002971 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002972 *
2973 * Callback to get the value of a dapm mixer control.
2974 *
2975 * Returns 0 for success.
2976 */
2977int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2978 struct snd_ctl_elem_value *ucontrol)
2979{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002980 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2981 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002982 struct soc_mixer_control *mc =
2983 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002984 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002985 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002986 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002987 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002988 unsigned int invert = mc->invert;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002989 unsigned int val;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002990 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002991
2992 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002993 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002994 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002995 kcontrol->id.name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002996
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002997 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002998 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
2999 ret = soc_dapm_read(dapm, reg, &val);
3000 val = (val >> shift) & mask;
3001 } else {
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003002 val = dapm_kcontrol_get_value(kcontrol);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003003 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003004 mutex_unlock(&card->dapm_mutex);
3005
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003006 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003007 ucontrol->value.integer.value[0] = max - val;
3008 else
3009 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003010
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003011 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003012}
3013EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3014
3015/**
3016 * snd_soc_dapm_put_volsw - dapm mixer set callback
3017 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003018 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003019 *
3020 * Callback to set the value of a dapm mixer control.
3021 *
3022 * Returns 0 for success.
3023 */
3024int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3025 struct snd_ctl_elem_value *ucontrol)
3026{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003027 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3028 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003029 struct soc_mixer_control *mc =
3030 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003031 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003032 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003033 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003034 unsigned int mask = (1 << fls(max)) - 1;
3035 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07003036 unsigned int val;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003037 int connect, change, reg_change = 0;
Mark Brown97404f22010-12-14 16:13:57 +00003038 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003039 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003040
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003041 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003042 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003043 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003044 kcontrol->id.name);
3045
Richard Purdie2b97eab2006-10-06 18:32:18 +02003046 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003047 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003048
3049 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003050 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003051
Liam Girdwood3cd04342012-03-09 12:02:08 +00003052 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003053
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003054 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown283375c2009-12-07 18:09:03 +00003055
Jarkko Nikula18626c72014-06-09 14:20:29 +03003056 if (reg != SND_SOC_NOPM) {
3057 mask = mask << shift;
3058 val = val << shift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003059
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003060 reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003061 }
3062
3063 if (change || reg_change) {
3064 if (reg_change) {
3065 update.kcontrol = kcontrol;
3066 update.reg = reg;
3067 update.mask = mask;
3068 update.val = val;
3069 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003070 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003071 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003072
Nenghua Cao52765972013-12-13 20:13:49 +08003073 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Mark Brown97404f22010-12-14 16:13:57 +00003074
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003075 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003076 }
3077
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003078 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003079
3080 if (ret > 0)
3081 soc_dpcm_runtime_update(card);
3082
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003083 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003084}
3085EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3086
3087/**
3088 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3089 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003090 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003091 *
3092 * Callback to get the value of a dapm enumerated double mixer control.
3093 *
3094 * Returns 0 for success.
3095 */
3096int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3097 struct snd_ctl_elem_value *ucontrol)
3098{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003099 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003100 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003101 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003102 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003103
Charles Keepax561ed682015-05-01 12:37:26 +01003104 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3105 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003106 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003107 if (ret) {
3108 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003109 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003110 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003111 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003112 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003113 }
Charles Keepax561ed682015-05-01 12:37:26 +01003114 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003115
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003116 val = (reg_val >> e->shift_l) & e->mask;
3117 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3118 if (e->shift_l != e->shift_r) {
3119 val = (reg_val >> e->shift_r) & e->mask;
3120 val = snd_soc_enum_val_to_item(e, val);
3121 ucontrol->value.enumerated.item[1] = val;
3122 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003123
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003124 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003125}
3126EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3127
3128/**
3129 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3130 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003131 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003132 *
3133 * Callback to set the value of a dapm enumerated double mixer control.
3134 *
3135 * Returns 0 for success.
3136 */
3137int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3138 struct snd_ctl_elem_value *ucontrol)
3139{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003140 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3141 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003142 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003143 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003144 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003145 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00003146 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003147 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003148
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003149 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003150 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003151
3152 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003153 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003154 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003155 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003156 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003157 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003158 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003159 }
3160
Liam Girdwood3cd04342012-03-09 12:02:08 +00003161 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003162
Charles Keepax561ed682015-05-01 12:37:26 +01003163 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003164
Charles Keepax561ed682015-05-01 12:37:26 +01003165 if (e->reg != SND_SOC_NOPM)
3166 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3167
3168 if (change || reg_change) {
3169 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003170 update.kcontrol = kcontrol;
3171 update.reg = e->reg;
3172 update.mask = mask;
3173 update.val = val;
3174 card->update = &update;
3175 }
Charles Keepax561ed682015-05-01 12:37:26 +01003176 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003177
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003178 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003179
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003180 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003181 }
3182
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003183 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003184
3185 if (ret > 0)
3186 soc_dpcm_runtime_update(card);
3187
Mark Brown97404f22010-12-14 16:13:57 +00003188 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003189}
3190EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3191
3192/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003193 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3194 *
3195 * @kcontrol: mixer control
3196 * @uinfo: control element information
3197 *
3198 * Callback to provide information about a pin switch control.
3199 */
3200int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3201 struct snd_ctl_elem_info *uinfo)
3202{
3203 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3204 uinfo->count = 1;
3205 uinfo->value.integer.min = 0;
3206 uinfo->value.integer.max = 1;
3207
3208 return 0;
3209}
3210EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3211
3212/**
3213 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3214 *
3215 * @kcontrol: mixer control
3216 * @ucontrol: Value
3217 */
3218int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3219 struct snd_ctl_elem_value *ucontrol)
3220{
Mark Brown48a8c392012-02-14 17:11:15 -08003221 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003222 const char *pin = (const char *)kcontrol->private_value;
3223
Liam Girdwood3cd04342012-03-09 12:02:08 +00003224 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003225
3226 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003227 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003228
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003229 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003230
3231 return 0;
3232}
3233EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3234
3235/**
3236 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3237 *
3238 * @kcontrol: mixer control
3239 * @ucontrol: Value
3240 */
3241int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3242 struct snd_ctl_elem_value *ucontrol)
3243{
Mark Brown48a8c392012-02-14 17:11:15 -08003244 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003245 const char *pin = (const char *)kcontrol->private_value;
3246
Mark Brown8b37dbd2009-02-28 21:14:20 +00003247 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003248 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003249 else
Mark Brown48a8c392012-02-14 17:11:15 -08003250 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003251
Mark Brown48a8c392012-02-14 17:11:15 -08003252 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003253 return 0;
3254}
3255EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3256
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +01003257struct snd_soc_dapm_widget *
Mark Brown5ba06fc2012-02-16 11:07:13 -08003258snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003259 const struct snd_soc_dapm_widget *widget)
3260{
3261 struct snd_soc_dapm_widget *w;
3262
3263 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3264 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3265 if (!w)
3266 dev_err(dapm->dev,
3267 "ASoC: Failed to create DAPM control %s\n",
3268 widget->name);
3269
3270 mutex_unlock(&dapm->card->dapm_mutex);
3271 return w;
3272}
3273
3274struct snd_soc_dapm_widget *
3275snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003276 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003277{
3278 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003279 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003280 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003281
3282 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003283 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003284
Mark Brown62ea8742012-01-21 21:14:48 +00003285 switch (w->id) {
3286 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003287 w->regulator = devm_regulator_get(dapm->dev, w->name);
3288 if (IS_ERR(w->regulator)) {
3289 ret = PTR_ERR(w->regulator);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003290 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003291 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003292 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003293 }
Mark Brown8784c772013-01-10 19:33:47 +00003294
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003295 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003296 ret = regulator_allow_bypass(w->regulator, true);
3297 if (ret != 0)
3298 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003299 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003300 w->name, ret);
3301 }
Mark Brown62ea8742012-01-21 21:14:48 +00003302 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003303 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003304#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003305 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003306 if (IS_ERR(w->clk)) {
3307 ret = PTR_ERR(w->clk);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003308 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003309 w->name, ret);
3310 return NULL;
3311 }
Mark Brownec029952012-06-04 08:16:20 +01003312#else
3313 return NULL;
3314#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003315 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003316 default:
3317 break;
3318 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003319
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003320 prefix = soc_dapm_prefix(dapm);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003321 if (prefix)
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003322 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003323 else
Lars-Peter Clausen48068962015-07-21 18:11:08 +02003324 w->name = kstrdup_const(widget->name, GFP_KERNEL);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003325 if (w->name == NULL) {
3326 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003327 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003328 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003329
Mark Brown7ca3a182011-10-08 14:04:50 +01003330 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003331 case snd_soc_dapm_mic:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003332 w->is_source = 1;
3333 w->power_check = dapm_generic_check_power;
3334 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003335 case snd_soc_dapm_input:
3336 if (!dapm->card->fully_routed)
3337 w->is_source = 1;
3338 w->power_check = dapm_generic_check_power;
3339 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003340 case snd_soc_dapm_spk:
3341 case snd_soc_dapm_hp:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003342 w->is_sink = 1;
3343 w->power_check = dapm_generic_check_power;
3344 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003345 case snd_soc_dapm_output:
3346 if (!dapm->card->fully_routed)
3347 w->is_sink = 1;
3348 w->power_check = dapm_generic_check_power;
3349 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003350 case snd_soc_dapm_vmid:
3351 case snd_soc_dapm_siggen:
3352 w->is_source = 1;
3353 w->power_check = dapm_always_on_check_power;
3354 break;
3355 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003356 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003357 case snd_soc_dapm_switch:
3358 case snd_soc_dapm_mixer:
3359 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003360 case snd_soc_dapm_adc:
3361 case snd_soc_dapm_aif_out:
3362 case snd_soc_dapm_dac:
3363 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003364 case snd_soc_dapm_pga:
3365 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003366 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003367 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003368 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003369 case snd_soc_dapm_dai_out:
3370 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003371 w->power_check = dapm_generic_check_power;
3372 break;
3373 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003374 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003375 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003376 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003377 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003378 w->power_check = dapm_supply_check_power;
3379 break;
3380 default:
3381 w->power_check = dapm_always_on_check_power;
3382 break;
3383 }
3384
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003385 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003386 INIT_LIST_HEAD(&w->sources);
3387 INIT_LIST_HEAD(&w->sinks);
3388 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003389 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003390 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003391
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003392 w->inputs = -1;
3393 w->outputs = -1;
3394
Richard Purdie2b97eab2006-10-06 18:32:18 +02003395 /* machine layer set ups unconnected pins and insertions */
3396 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003397 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003398}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003399
3400/**
Mark Brown4ba13272008-05-13 14:51:19 +02003401 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003402 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003403 * @widget: widget array
3404 * @num: number of widgets
3405 *
3406 * Creates new DAPM controls based upon the templates.
3407 *
3408 * Returns 0 for success else error.
3409 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003410int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003411 const struct snd_soc_dapm_widget *widget,
3412 int num)
3413{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003414 struct snd_soc_dapm_widget *w;
3415 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003416 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003417
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003418 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003419 for (i = 0; i < num; i++) {
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003420 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003421 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003422 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003423 "ASoC: Failed to create DAPM control %s\n",
3424 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003425 ret = -ENOMEM;
3426 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003427 }
Mark Brown4ba13272008-05-13 14:51:19 +02003428 widget++;
3429 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003430 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003431 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003432}
3433EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3434
Mark Brownc74184e2012-04-04 22:12:09 +01003435static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3436 struct snd_kcontrol *kcontrol, int event)
3437{
3438 struct snd_soc_dapm_path *source_p, *sink_p;
3439 struct snd_soc_dai *source, *sink;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003440 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003441 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003442 struct snd_pcm_hw_params *params = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003443 u64 fmt;
3444 int ret;
3445
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003446 if (WARN_ON(!config) ||
3447 WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
3448 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003449
3450 /* We only support a single source and sink, pick the first */
3451 source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
3452 list_sink);
3453 sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
3454 list_source);
3455
Mark Brownc74184e2012-04-04 22:12:09 +01003456 source = source_p->source->priv;
3457 sink = sink_p->sink->priv;
3458
3459 /* Be a little careful as we don't want to overflow the mask array */
3460 if (config->formats) {
3461 fmt = ffs(config->formats) - 1;
3462 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003463 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003464 config->formats);
3465 fmt = 0;
3466 }
3467
3468 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003469 params = kzalloc(sizeof(*params), GFP_KERNEL);
3470 if (!params) {
3471 ret = -ENOMEM;
3472 goto out;
3473 }
3474 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003475
Mark Brown9747cec2012-04-26 19:12:21 +01003476 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003477 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003478 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003479 config->rate_max;
3480
Mark Brown9747cec2012-04-26 19:12:21 +01003481 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003482 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003483 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003484 = config->channels_max;
3485
3486 memset(&substream, 0, sizeof(substream));
3487
3488 switch (event) {
3489 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003490 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3491 ret = soc_dai_hw_params(&substream, params, source);
3492 if (ret < 0)
3493 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003494
Benoit Cousson93e69582014-07-08 23:19:38 +02003495 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3496 ret = soc_dai_hw_params(&substream, params, sink);
3497 if (ret < 0)
3498 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003499 break;
3500
3501 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003502 ret = snd_soc_dai_digital_mute(sink, 0,
3503 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003504 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003505 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003506 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003507 break;
3508
3509 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003510 ret = snd_soc_dai_digital_mute(sink, 1,
3511 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003512 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003513 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003514 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003515 break;
3516
3517 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003518 WARN(1, "Unknown event %d\n", event);
Mark Brownc74184e2012-04-04 22:12:09 +01003519 return -EINVAL;
3520 }
3521
Mark Brown9747cec2012-04-26 19:12:21 +01003522out:
3523 kfree(params);
3524 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003525}
3526
Nikesh Oswalc6615082015-02-02 17:06:44 +00003527static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3528 struct snd_ctl_elem_value *ucontrol)
3529{
3530 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3531
3532 ucontrol->value.integer.value[0] = w->params_select;
3533
3534 return 0;
3535}
3536
3537static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3538 struct snd_ctl_elem_value *ucontrol)
3539{
3540 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3541
3542 /* Can't change the config when widget is already powered */
3543 if (w->power)
3544 return -EBUSY;
3545
3546 if (ucontrol->value.integer.value[0] == w->params_select)
3547 return 0;
3548
3549 if (ucontrol->value.integer.value[0] >= w->num_params)
3550 return -EINVAL;
3551
3552 w->params_select = ucontrol->value.integer.value[0];
3553
3554 return 0;
3555}
3556
Mark Brownc74184e2012-04-04 22:12:09 +01003557int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3558 const struct snd_soc_pcm_stream *params,
Nikesh Oswalc6615082015-02-02 17:06:44 +00003559 unsigned int num_params,
Mark Brownc74184e2012-04-04 22:12:09 +01003560 struct snd_soc_dapm_widget *source,
3561 struct snd_soc_dapm_widget *sink)
3562{
Mark Brownc74184e2012-04-04 22:12:09 +01003563 struct snd_soc_dapm_widget template;
3564 struct snd_soc_dapm_widget *w;
Mark Brownc74184e2012-04-04 22:12:09 +01003565 char *link_name;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003566 int ret, count;
3567 unsigned long private_value;
3568 const char **w_param_text;
3569 struct soc_enum w_param_enum[] = {
3570 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3571 };
3572 struct snd_kcontrol_new kcontrol_dai_link[] = {
3573 SOC_ENUM_EXT(NULL, w_param_enum[0],
3574 snd_soc_dapm_dai_link_get,
3575 snd_soc_dapm_dai_link_put),
3576 };
3577 const struct snd_soc_pcm_stream *config = params;
Mark Brownc74184e2012-04-04 22:12:09 +01003578
Nikesh Oswalc6615082015-02-02 17:06:44 +00003579 w_param_text = devm_kcalloc(card->dev, num_params,
3580 sizeof(char *), GFP_KERNEL);
3581 if (!w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003582 return -ENOMEM;
Mark Brownc74184e2012-04-04 22:12:09 +01003583
Charles Keepax46172b62015-03-25 11:22:35 +00003584 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3585 source->name, sink->name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003586 if (!link_name) {
3587 ret = -ENOMEM;
3588 goto outfree_w_param;
3589 }
Mark Brownc74184e2012-04-04 22:12:09 +01003590
Nikesh Oswalc6615082015-02-02 17:06:44 +00003591 for (count = 0 ; count < num_params; count++) {
3592 if (!config->stream_name) {
3593 dev_warn(card->dapm.dev,
3594 "ASoC: anonymous config %d for dai link %s\n",
3595 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003596 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003597 devm_kasprintf(card->dev, GFP_KERNEL,
3598 "Anonymous Configuration %d",
3599 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003600 if (!w_param_text[count]) {
3601 ret = -ENOMEM;
3602 goto outfree_link_name;
3603 }
Nikesh Oswalc6615082015-02-02 17:06:44 +00003604 } else {
3605 w_param_text[count] = devm_kmemdup(card->dev,
3606 config->stream_name,
3607 strlen(config->stream_name) + 1,
3608 GFP_KERNEL);
3609 if (!w_param_text[count]) {
3610 ret = -ENOMEM;
3611 goto outfree_link_name;
3612 }
3613 }
3614 config++;
3615 }
3616 w_param_enum[0].items = num_params;
3617 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003618
3619 memset(&template, 0, sizeof(template));
3620 template.reg = SND_SOC_NOPM;
3621 template.id = snd_soc_dapm_dai_link;
3622 template.name = link_name;
3623 template.event = snd_soc_dai_link_event;
3624 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3625 SND_SOC_DAPM_PRE_PMD;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003626 template.num_kcontrols = 1;
3627 /* duplicate w_param_enum on heap so that memory persists */
3628 private_value =
3629 (unsigned long) devm_kmemdup(card->dev,
3630 (void *)(kcontrol_dai_link[0].private_value),
3631 sizeof(struct soc_enum), GFP_KERNEL);
3632 if (!private_value) {
3633 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3634 link_name);
3635 ret = -ENOMEM;
3636 goto outfree_link_name;
3637 }
3638 kcontrol_dai_link[0].private_value = private_value;
3639 /* duplicate kcontrol_dai_link on heap so that memory persists */
3640 template.kcontrol_news =
3641 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3642 sizeof(struct snd_kcontrol_new),
3643 GFP_KERNEL);
3644 if (!template.kcontrol_news) {
3645 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3646 link_name);
3647 ret = -ENOMEM;
3648 goto outfree_private_value;
3649 }
Mark Brownc74184e2012-04-04 22:12:09 +01003650
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003651 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003652
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003653 w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
Mark Brownc74184e2012-04-04 22:12:09 +01003654 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003655 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003656 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003657 ret = -ENOMEM;
3658 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003659 }
3660
3661 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003662 w->num_params = num_params;
Mark Brownc74184e2012-04-04 22:12:09 +01003663
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003664 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3665 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003666 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003667 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003668
3669outfree_w:
3670 devm_kfree(card->dev, w);
3671outfree_kcontrol_news:
3672 devm_kfree(card->dev, (void *)template.kcontrol_news);
3673outfree_private_value:
3674 devm_kfree(card->dev, (void *)private_value);
3675outfree_link_name:
3676 devm_kfree(card->dev, link_name);
3677outfree_w_param:
3678 for (count = 0 ; count < num_params; count++)
3679 devm_kfree(card->dev, (void *)w_param_text[count]);
3680 devm_kfree(card->dev, w_param_text);
3681
3682 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003683}
3684
Mark Brown888df392012-02-16 19:37:51 -08003685int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3686 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003687{
Mark Brown888df392012-02-16 19:37:51 -08003688 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003689 struct snd_soc_dapm_widget *w;
3690
Mark Brown888df392012-02-16 19:37:51 -08003691 WARN_ON(dapm->dev != dai->dev);
3692
3693 memset(&template, 0, sizeof(template));
3694 template.reg = SND_SOC_NOPM;
3695
3696 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003697 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003698 template.name = dai->driver->playback.stream_name;
3699 template.sname = dai->driver->playback.stream_name;
3700
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003701 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003702 template.name);
3703
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003704 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Mark Brown888df392012-02-16 19:37:51 -08003705 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003706 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003707 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003708 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003709 }
3710
3711 w->priv = dai;
3712 dai->playback_widget = w;
3713 }
3714
3715 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003716 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003717 template.name = dai->driver->capture.stream_name;
3718 template.sname = dai->driver->capture.stream_name;
3719
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003720 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003721 template.name);
3722
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003723 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Mark Brown888df392012-02-16 19:37:51 -08003724 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003725 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003726 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003727 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003728 }
3729
3730 w->priv = dai;
3731 dai->capture_widget = w;
3732 }
3733
3734 return 0;
3735}
3736
3737int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3738{
3739 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003740 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08003741 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003742
3743 /* For each DAI widget... */
3744 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003745 switch (dai_w->id) {
3746 case snd_soc_dapm_dai_in:
3747 case snd_soc_dapm_dai_out:
3748 break;
3749 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003750 continue;
Mark Brown46162742013-06-05 19:36:11 +01003751 }
Mark Brown888df392012-02-16 19:37:51 -08003752
3753 dai = dai_w->priv;
3754
3755 /* ...find all widgets with the same stream and link them */
3756 list_for_each_entry(w, &card->widgets, list) {
3757 if (w->dapm != dai_w->dapm)
3758 continue;
3759
Mark Brown46162742013-06-05 19:36:11 +01003760 switch (w->id) {
3761 case snd_soc_dapm_dai_in:
3762 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08003763 continue;
Mark Brown46162742013-06-05 19:36:11 +01003764 default:
3765 break;
3766 }
Mark Brown888df392012-02-16 19:37:51 -08003767
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003768 if (!w->sname || !strstr(w->sname, dai_w->sname))
Mark Brown888df392012-02-16 19:37:51 -08003769 continue;
3770
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003771 if (dai_w->id == snd_soc_dapm_dai_in) {
3772 src = dai_w;
3773 sink = w;
3774 } else {
3775 src = w;
3776 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08003777 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003778 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
3779 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003780 }
3781 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003782
Mark Brown888df392012-02-16 19:37:51 -08003783 return 0;
3784}
Liam Girdwood64a648c2011-07-25 11:15:15 +01003785
Benoit Cousson44ba2642014-07-08 23:19:36 +02003786static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
3787 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003788{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003789 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003790 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003791 int i;
3792
Benoit Cousson44ba2642014-07-08 23:19:36 +02003793 for (i = 0; i < rtd->num_codecs; i++) {
3794 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003795
3796 /* there is no point in connecting BE DAI links with dummies */
3797 if (snd_soc_dai_is_dummy(codec_dai) ||
3798 snd_soc_dai_is_dummy(cpu_dai))
3799 continue;
3800
3801 /* connect BE DAI playback if widgets are valid */
3802 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003803 source = cpu_dai->playback_widget;
3804 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003805 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003806 cpu_dai->component->name, source->name,
3807 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003808
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003809 snd_soc_dapm_add_path(&card->dapm, source, sink,
3810 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003811 }
3812
3813 /* connect BE DAI capture if widgets are valid */
3814 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003815 source = codec_dai->capture_widget;
3816 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003817 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003818 codec_dai->component->name, source->name,
3819 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003820
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003821 snd_soc_dapm_add_path(&card->dapm, source, sink,
3822 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003823 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003824 }
3825}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003826
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003827static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3828 int event)
3829{
3830 struct snd_soc_dapm_widget *w;
3831
3832 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3833 w = dai->playback_widget;
3834 else
3835 w = dai->capture_widget;
3836
3837 if (w) {
3838 dapm_mark_dirty(w, "stream event");
3839
3840 switch (event) {
3841 case SND_SOC_DAPM_STREAM_START:
3842 w->active = 1;
3843 break;
3844 case SND_SOC_DAPM_STREAM_STOP:
3845 w->active = 0;
3846 break;
3847 case SND_SOC_DAPM_STREAM_SUSPEND:
3848 case SND_SOC_DAPM_STREAM_RESUME:
3849 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3850 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3851 break;
3852 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003853
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003854 if (w->id == snd_soc_dapm_dai_in) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003855 w->is_source = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003856 dapm_widget_invalidate_input_paths(w);
3857 } else {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003858 w->is_sink = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003859 dapm_widget_invalidate_output_paths(w);
3860 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003861 }
3862}
3863
Benoit Cousson44ba2642014-07-08 23:19:36 +02003864void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3865{
3866 struct snd_soc_pcm_runtime *rtd = card->rtd;
3867 int i;
3868
3869 /* for each BE DAI link... */
3870 for (i = 0; i < card->num_rtd; i++) {
3871 rtd = &card->rtd[i];
3872
3873 /*
3874 * dynamic FE links have no fixed DAI mapping.
3875 * CODEC<->CODEC links have no direct connection.
3876 */
3877 if (rtd->dai_link->dynamic || rtd->dai_link->params)
3878 continue;
3879
3880 dapm_connect_dai_link_widgets(card, rtd);
3881 }
3882}
3883
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003884static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3885 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003886{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003887 int i;
3888
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003889 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02003890 for (i = 0; i < rtd->num_codecs; i++)
3891 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003892
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003893 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003894}
3895
3896/**
3897 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3898 * @rtd: PCM runtime data
3899 * @stream: stream name
3900 * @event: stream event
3901 *
3902 * Sends a stream event to the dapm core. The core then makes any
3903 * necessary widget power changes.
3904 *
3905 * Returns 0 for success else error.
3906 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003907void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3908 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003909{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003910 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003911
Liam Girdwood3cd04342012-03-09 12:02:08 +00003912 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003913 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003914 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003915}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003916
3917/**
Charles Keepax11391102014-02-18 15:22:14 +00003918 * snd_soc_dapm_enable_pin_unlocked - enable pin.
3919 * @dapm: DAPM context
3920 * @pin: pin name
3921 *
3922 * Enables input/output pin and its parents or children widgets iff there is
3923 * a valid audio route and active audio stream.
3924 *
3925 * Requires external locking.
3926 *
3927 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3928 * do any widget power switching.
3929 */
3930int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3931 const char *pin)
3932{
3933 return snd_soc_dapm_set_pin(dapm, pin, 1);
3934}
3935EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
3936
3937/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003938 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003939 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003940 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02003941 *
Mark Brown74b8f952009-06-06 11:26:15 +01003942 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01003943 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00003944 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003945 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3946 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02003947 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003948int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003949{
Charles Keepax11391102014-02-18 15:22:14 +00003950 int ret;
3951
3952 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3953
3954 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
3955
3956 mutex_unlock(&dapm->card->dapm_mutex);
3957
3958 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003959}
Liam Girdwooda5302182008-07-07 13:35:17 +01003960EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003961
3962/**
Charles Keepax11391102014-02-18 15:22:14 +00003963 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
3964 * @dapm: DAPM context
3965 * @pin: pin name
3966 *
3967 * Enables input/output pin regardless of any other state. This is
3968 * intended for use with microphone bias supplies used in microphone
3969 * jack detection.
3970 *
3971 * Requires external locking.
3972 *
3973 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3974 * do any widget power switching.
3975 */
3976int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3977 const char *pin)
3978{
3979 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
3980
3981 if (!w) {
3982 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
3983 return -EINVAL;
3984 }
3985
3986 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003987 if (!w->connected) {
3988 /*
3989 * w->force does not affect the number of input or output paths,
3990 * so we only have to recheck if w->connected is changed
3991 */
3992 dapm_widget_invalidate_input_paths(w);
3993 dapm_widget_invalidate_output_paths(w);
3994 w->connected = 1;
3995 }
Charles Keepax11391102014-02-18 15:22:14 +00003996 w->force = 1;
3997 dapm_mark_dirty(w, "force enable");
3998
3999 return 0;
4000}
4001EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4002
4003/**
Mark Brownda341832010-03-15 19:23:37 +00004004 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004005 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00004006 * @pin: pin name
4007 *
4008 * Enables input/output pin regardless of any other state. This is
4009 * intended for use with microphone bias supplies used in microphone
4010 * jack detection.
4011 *
4012 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4013 * do any widget power switching.
4014 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004015int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4016 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00004017{
Charles Keepax11391102014-02-18 15:22:14 +00004018 int ret;
Mark Brownda341832010-03-15 19:23:37 +00004019
Charles Keepax11391102014-02-18 15:22:14 +00004020 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00004021
Charles Keepax11391102014-02-18 15:22:14 +00004022 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09004023
Charles Keepax11391102014-02-18 15:22:14 +00004024 mutex_unlock(&dapm->card->dapm_mutex);
4025
4026 return ret;
Mark Brownda341832010-03-15 19:23:37 +00004027}
4028EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4029
4030/**
Charles Keepax11391102014-02-18 15:22:14 +00004031 * snd_soc_dapm_disable_pin_unlocked - disable pin.
4032 * @dapm: DAPM context
4033 * @pin: pin name
4034 *
4035 * Disables input/output pin and its parents or children widgets.
4036 *
4037 * Requires external locking.
4038 *
4039 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4040 * do any widget power switching.
4041 */
4042int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4043 const char *pin)
4044{
4045 return snd_soc_dapm_set_pin(dapm, pin, 0);
4046}
4047EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4048
4049/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004050 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004051 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004052 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004053 *
Mark Brown74b8f952009-06-06 11:26:15 +01004054 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004055 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004056 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4057 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004058 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004059int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4060 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004061{
Charles Keepax11391102014-02-18 15:22:14 +00004062 int ret;
4063
4064 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4065
4066 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4067
4068 mutex_unlock(&dapm->card->dapm_mutex);
4069
4070 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004071}
4072EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4073
4074/**
Charles Keepax11391102014-02-18 15:22:14 +00004075 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4076 * @dapm: DAPM context
4077 * @pin: pin name
4078 *
4079 * Marks the specified pin as being not connected, disabling it along
4080 * any parent or child widgets. At present this is identical to
4081 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4082 * additional things such as disabling controls which only affect
4083 * paths through the pin.
4084 *
4085 * Requires external locking.
4086 *
4087 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4088 * do any widget power switching.
4089 */
4090int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4091 const char *pin)
4092{
4093 return snd_soc_dapm_set_pin(dapm, pin, 0);
4094}
4095EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4096
4097/**
Mark Brown5817b522008-09-24 11:23:11 +01004098 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004099 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004100 * @pin: pin name
4101 *
4102 * Marks the specified pin as being not connected, disabling it along
4103 * any parent or child widgets. At present this is identical to
4104 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4105 * additional things such as disabling controls which only affect
4106 * paths through the pin.
4107 *
4108 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4109 * do any widget power switching.
4110 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004111int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004112{
Charles Keepax11391102014-02-18 15:22:14 +00004113 int ret;
4114
4115 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4116
4117 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4118
4119 mutex_unlock(&dapm->card->dapm_mutex);
4120
4121 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004122}
4123EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4124
4125/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004126 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004127 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004128 * @pin: audio signal pin endpoint (or start point)
4129 *
4130 * Get audio pin status - connected or disconnected.
4131 *
4132 * Returns 1 for connected otherwise 0.
4133 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004134int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4135 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004136{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004137 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004138
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004139 if (w)
4140 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004141
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004142 return 0;
4143}
Liam Girdwooda5302182008-07-07 13:35:17 +01004144EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004145
4146/**
Mark Brown1547aba2010-05-07 21:11:40 +01004147 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004148 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004149 * @pin: audio signal pin endpoint (or start point)
4150 *
4151 * Mark the given endpoint or pin as ignoring suspend. When the
4152 * system is disabled a path between two endpoints flagged as ignoring
4153 * suspend will not be disabled. The path must already be enabled via
4154 * normal means at suspend time, it will not be turned on if it was not
4155 * already enabled.
4156 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004157int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4158 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004159{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004160 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004161
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004162 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004163 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004164 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004165 }
4166
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004167 w->ignore_suspend = 1;
4168
4169 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004170}
4171EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4172
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004173/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004174 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004175 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004176 *
4177 * Free all dapm widgets and resources.
4178 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004179void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004180{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004181 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004182 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004183 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004184}
4185EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4186
Xiang Xiao57996352014-03-02 00:04:02 +08004187static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004188{
Liam Girdwood01005a72012-07-06 16:57:05 +01004189 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004190 struct snd_soc_dapm_widget *w;
4191 LIST_HEAD(down_list);
4192 int powerdown = 0;
4193
Liam Girdwood01005a72012-07-06 16:57:05 +01004194 mutex_lock(&card->dapm_mutex);
4195
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004196 list_for_each_entry(w, &dapm->card->widgets, list) {
4197 if (w->dapm != dapm)
4198 continue;
Mark Brown51737472009-06-22 13:16:51 +01004199 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004200 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004201 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004202 powerdown = 1;
4203 }
4204 }
4205
4206 /* If there were no widgets to power down we're already in
4207 * standby.
4208 */
4209 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004210 if (dapm->bias_level == SND_SOC_BIAS_ON)
4211 snd_soc_dapm_set_bias_level(dapm,
4212 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004213 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004214 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4215 snd_soc_dapm_set_bias_level(dapm,
4216 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004217 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004218
4219 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004220}
Mark Brown51737472009-06-22 13:16:51 +01004221
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004222/*
4223 * snd_soc_dapm_shutdown - callback for system shutdown
4224 */
4225void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4226{
Xiang Xiao57996352014-03-02 00:04:02 +08004227 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004228
Xiang Xiao57996352014-03-02 00:04:02 +08004229 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004230 if (dapm != &card->dapm) {
4231 soc_dapm_shutdown_dapm(dapm);
4232 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4233 snd_soc_dapm_set_bias_level(dapm,
4234 SND_SOC_BIAS_OFF);
4235 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004236 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004237
4238 soc_dapm_shutdown_dapm(&card->dapm);
4239 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4240 snd_soc_dapm_set_bias_level(&card->dapm,
4241 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004242}
4243
Richard Purdie2b97eab2006-10-06 18:32:18 +02004244/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004245MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004246MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4247MODULE_LICENSE("GPL");