blob: d908ff8f97554cacdf6658288222744209287aee [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 Clausena3423b02015-08-11 21:38:00 +020050#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
51 SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
52
53#define snd_soc_dapm_for_each_direction(dir) \
54 for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
55 (dir)++)
56
Lars-Peter Clausen57295072013-08-05 11:27:31 +020057static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
58 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
59 const char *control,
60 int (*connected)(struct snd_soc_dapm_widget *source,
61 struct snd_soc_dapm_widget *sink));
Vladimir Zapolskiy5353f652015-06-02 00:57:53 +030062
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +010063struct snd_soc_dapm_widget *
Lars-Peter Clausen57295072013-08-05 11:27:31 +020064snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
65 const struct snd_soc_dapm_widget *widget);
66
Liam Girdwood02aa78a2015-05-25 18:21:17 +010067struct snd_soc_dapm_widget *
68snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +020069 const struct snd_soc_dapm_widget *widget);
70
Richard Purdie2b97eab2006-10-06 18:32:18 +020071/* dapm power sequences - make this per codec in the future */
72static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010073 [snd_soc_dapm_pre] = 0,
Mark Brown62ea8742012-01-21 21:14:48 +000074 [snd_soc_dapm_regulator_supply] = 1,
Ola Liljad7e7eb92012-05-24 15:26:25 +020075 [snd_soc_dapm_clock_supply] = 1,
Mark Brown1dd275b2013-10-09 13:56:37 +010076 [snd_soc_dapm_supply] = 2,
77 [snd_soc_dapm_micbias] = 3,
Mark Brownc74184e2012-04-04 22:12:09 +010078 [snd_soc_dapm_dai_link] = 2,
Mark Brown1dd275b2013-10-09 13:56:37 +010079 [snd_soc_dapm_dai_in] = 4,
80 [snd_soc_dapm_dai_out] = 4,
81 [snd_soc_dapm_aif_in] = 4,
82 [snd_soc_dapm_aif_out] = 4,
83 [snd_soc_dapm_mic] = 5,
84 [snd_soc_dapm_mux] = 6,
Lars-Peter Clausend714f972015-05-01 18:02:43 +020085 [snd_soc_dapm_demux] = 6,
Mark Brown1dd275b2013-10-09 13:56:37 +010086 [snd_soc_dapm_dac] = 7,
87 [snd_soc_dapm_switch] = 8,
88 [snd_soc_dapm_mixer] = 8,
89 [snd_soc_dapm_mixer_named_ctl] = 8,
90 [snd_soc_dapm_pga] = 9,
91 [snd_soc_dapm_adc] = 10,
92 [snd_soc_dapm_out_drv] = 11,
93 [snd_soc_dapm_hp] = 11,
94 [snd_soc_dapm_spk] = 11,
95 [snd_soc_dapm_line] = 11,
96 [snd_soc_dapm_kcontrol] = 12,
97 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020098};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000099
Richard Purdie2b97eab2006-10-06 18:32:18 +0200100static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +0100101 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200102 [snd_soc_dapm_kcontrol] = 1,
103 [snd_soc_dapm_adc] = 2,
104 [snd_soc_dapm_hp] = 3,
105 [snd_soc_dapm_spk] = 3,
106 [snd_soc_dapm_line] = 3,
107 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +0100108 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +0200109 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +0100110 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +0100111 [snd_soc_dapm_mixer] = 5,
112 [snd_soc_dapm_dac] = 6,
113 [snd_soc_dapm_mic] = 7,
114 [snd_soc_dapm_micbias] = 8,
115 [snd_soc_dapm_mux] = 9,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200116 [snd_soc_dapm_demux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100117 [snd_soc_dapm_aif_in] = 10,
118 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100119 [snd_soc_dapm_dai_in] = 10,
120 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100121 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100122 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100123 [snd_soc_dapm_clock_supply] = 13,
124 [snd_soc_dapm_regulator_supply] = 13,
125 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200126};
127
Mark Brownf9fa2b12014-03-06 16:49:11 +0800128static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
129{
130 if (dapm->card && dapm->card->instantiated)
131 lockdep_assert_held(&dapm->card->dapm_mutex);
132}
133
Troy Kisky12ef1932008-10-13 17:42:14 -0700134static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100135{
136 if (pop_time)
137 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
138}
139
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200140static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100141{
142 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200143 char *buf;
144
145 if (!pop_time)
146 return;
147
148 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
149 if (buf == NULL)
150 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100151
152 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200153 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100154 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100155 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200156
157 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100158}
159
Mark Browndb432b42011-10-03 21:06:40 +0100160static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
161{
162 return !list_empty(&w->dirty);
163}
164
Mark Brown492c0a12014-03-06 16:15:48 +0800165static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100166{
Mark Brownf9fa2b12014-03-06 16:49:11 +0800167 dapm_assert_locked(w->dapm);
168
Mark Brown75c1f892011-10-04 22:28:08 +0100169 if (!dapm_dirty_widget(w)) {
170 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
171 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100172 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100173 }
Mark Browndb432b42011-10-03 21:06:40 +0100174}
175
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200176/*
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200177 * Common implementation for dapm_widget_invalidate_input_paths() and
178 * dapm_widget_invalidate_output_paths(). The function is inlined since the
179 * combined size of the two specialized functions is only marginally larger then
180 * the size of the generic function and at the same time the fast path of the
181 * specialized functions is significantly smaller than the generic function.
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200182 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200183static __always_inline void dapm_widget_invalidate_paths(
184 struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200185{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200186 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
187 struct snd_soc_dapm_widget *node;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200188 struct snd_soc_dapm_path *p;
189 LIST_HEAD(list);
190
191 dapm_assert_locked(w->dapm);
192
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200193 if (w->endpoints[dir] == -1)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200194 return;
195
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200196 list_add_tail(&w->work_list, &list);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200197 w->endpoints[dir] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200198
199 list_for_each_entry(w, &list, work_list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200200 snd_soc_dapm_widget_for_each_path(w, dir, p) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200201 if (p->is_supply || p->weak || !p->connect)
202 continue;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200203 node = p->node[rdir];
204 if (node->endpoints[dir] != -1) {
205 node->endpoints[dir] = -1;
206 list_add_tail(&node->work_list, &list);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200207 }
208 }
209 }
210}
211
212/*
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200213 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of
214 * input paths
215 * @w: The widget for which to invalidate the cached number of input paths
216 *
217 * Resets the cached number of inputs for the specified widget and all widgets
218 * that can be reached via outcoming paths from the widget.
219 *
220 * This function must be called if the number of output paths for a widget might
221 * have changed. E.g. if the source state of a widget changes or a path is added
222 * or activated with the widget as the sink.
223 */
224static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
225{
226 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN);
227}
228
229/*
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200230 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
231 * output paths
232 * @w: The widget for which to invalidate the cached number of output paths
233 *
234 * Resets the cached number of outputs for the specified widget and all widgets
235 * that can be reached via incoming paths from the widget.
236 *
237 * This function must be called if the number of output paths for a widget might
238 * have changed. E.g. if the sink state of a widget changes or a path is added
239 * or activated with the widget as the source.
240 */
241static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
242{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200243 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200244}
245
246/*
247 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
248 * for the widgets connected to a path
249 * @p: The path to invalidate
250 *
251 * Resets the cached number of inputs for the sink of the path and the cached
252 * number of outputs for the source of the path.
253 *
254 * This function must be called when a path is added, removed or the connected
255 * state changes.
256 */
257static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
258{
259 /*
260 * Weak paths or supply paths do not influence the number of input or
261 * output paths of their neighbors.
262 */
263 if (p->weak || p->is_supply)
264 return;
265
266 /*
267 * The number of connected endpoints is the sum of the number of
268 * connected endpoints of all neighbors. If a node with 0 connected
269 * endpoints is either connected or disconnected that sum won't change,
270 * so there is no need to re-check the path.
271 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200272 if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200273 dapm_widget_invalidate_input_paths(p->sink);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200274 if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200275 dapm_widget_invalidate_output_paths(p->source);
276}
277
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200278void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
Mark Browne2d32ff2012-08-31 17:38:32 -0700279{
Mark Browne2d32ff2012-08-31 17:38:32 -0700280 struct snd_soc_dapm_widget *w;
281
282 mutex_lock(&card->dapm_mutex);
283
284 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200285 if (w->is_ep) {
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200286 dapm_mark_dirty(w, "Rechecking endpoints");
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200287 if (w->is_ep & SND_SOC_DAPM_EP_SINK)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200288 dapm_widget_invalidate_output_paths(w);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200289 if (w->is_ep & SND_SOC_DAPM_EP_SOURCE)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200290 dapm_widget_invalidate_input_paths(w);
291 }
Mark Browne2d32ff2012-08-31 17:38:32 -0700292 }
293
294 mutex_unlock(&card->dapm_mutex);
295}
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200296EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
Mark Browne2d32ff2012-08-31 17:38:32 -0700297
Richard Purdie2b97eab2006-10-06 18:32:18 +0200298/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100299static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200300 const struct snd_soc_dapm_widget *_widget)
301{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100302 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200303}
304
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200305struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200306 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200307 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200308 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200309 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200310};
311
312static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100313 struct snd_kcontrol *kcontrol, const char *ctrl_name)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200314{
315 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200316 struct soc_mixer_control *mc;
Charles Keepax561ed682015-05-01 12:37:26 +0100317 struct soc_enum *e;
Charles Keepax773da9b2015-05-01 12:37:25 +0100318 const char *name;
319 int ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200320
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200321 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100322 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200323 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200324
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200325 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200326
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200327 switch (widget->id) {
328 case snd_soc_dapm_switch:
329 case snd_soc_dapm_mixer:
330 case snd_soc_dapm_mixer_named_ctl:
331 mc = (struct soc_mixer_control *)kcontrol->private_value;
332
333 if (mc->autodisable) {
334 struct snd_soc_dapm_widget template;
335
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100336 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
Charles Keepax773da9b2015-05-01 12:37:25 +0100337 "Autodisable");
338 if (!name) {
339 ret = -ENOMEM;
340 goto err_data;
341 }
342
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200343 memset(&template, 0, sizeof(template));
344 template.reg = mc->reg;
345 template.mask = (1 << fls(mc->max)) - 1;
346 template.shift = mc->shift;
347 if (mc->invert)
348 template.off_val = mc->max;
349 else
350 template.off_val = 0;
351 template.on_val = template.off_val;
352 template.id = snd_soc_dapm_kcontrol;
Charles Keepax773da9b2015-05-01 12:37:25 +0100353 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200354
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200355 data->value = template.on_val;
356
Liam Girdwood02aa78a2015-05-25 18:21:17 +0100357 data->widget =
358 snd_soc_dapm_new_control_unlocked(widget->dapm,
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200359 &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200360 kfree(name);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200361 if (!data->widget) {
Charles Keepax773da9b2015-05-01 12:37:25 +0100362 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200363 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200364 }
365 }
366 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200367 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100368 case snd_soc_dapm_mux:
369 e = (struct soc_enum *)kcontrol->private_value;
370
371 if (e->autodisable) {
372 struct snd_soc_dapm_widget template;
373
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100374 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
Charles Keepax561ed682015-05-01 12:37:26 +0100375 "Autodisable");
376 if (!name) {
377 ret = -ENOMEM;
378 goto err_data;
379 }
380
381 memset(&template, 0, sizeof(template));
382 template.reg = e->reg;
383 template.mask = e->mask << e->shift_l;
384 template.shift = e->shift_l;
385 template.off_val = snd_soc_enum_item_to_val(e, 0);
386 template.on_val = template.off_val;
387 template.id = snd_soc_dapm_kcontrol;
388 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200389
390 data->value = template.on_val;
391
Charles Keepaxffacb482015-06-26 10:39:43 +0100392 data->widget = snd_soc_dapm_new_control_unlocked(
393 widget->dapm, &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200394 kfree(name);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200395 if (!data->widget) {
Charles Keepax561ed682015-05-01 12:37:26 +0100396 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200397 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200398 }
Charles Keepax561ed682015-05-01 12:37:26 +0100399
400 snd_soc_dapm_add_path(widget->dapm, data->widget,
401 widget, NULL, NULL);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200402 }
403 break;
404 default:
405 break;
406 }
407
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200408 kcontrol->private_data = data;
409
410 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100411
Charles Keepax773da9b2015-05-01 12:37:25 +0100412err_data:
413 kfree(data);
414 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200415}
416
417static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
418{
419 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200420 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200421 kfree(data);
422}
423
424static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
425 const struct snd_kcontrol *kcontrol)
426{
427 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
428
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200429 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200430}
431
432static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
433 struct snd_soc_dapm_widget *widget)
434{
435 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200436 struct snd_soc_dapm_widget_list *new_wlist;
437 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200438
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200439 if (data->wlist)
440 n = data->wlist->num_widgets + 1;
441 else
442 n = 1;
443
444 new_wlist = krealloc(data->wlist,
445 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
446 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200447 return -ENOMEM;
448
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200449 new_wlist->widgets[n - 1] = widget;
450 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200451
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200452 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200453
454 return 0;
455}
456
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200457static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
458 struct snd_soc_dapm_path *path)
459{
460 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
461
462 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200463}
464
465static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
466{
467 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
468
469 if (!data->widget)
470 return true;
471
472 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200473}
474
475static struct list_head *dapm_kcontrol_get_path_list(
476 const struct snd_kcontrol *kcontrol)
477{
478 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
479
480 return &data->paths;
481}
482
483#define dapm_kcontrol_for_each_path(path, kcontrol) \
484 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
485 list_kcontrol)
486
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530487unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200488{
489 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
490
491 return data->value;
492}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530493EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200494
495static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
496 unsigned int value)
497{
498 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
499
500 if (data->value == value)
501 return false;
502
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200503 if (data->widget)
504 data->widget->on_val = value;
505
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200506 data->value = value;
507
508 return true;
509}
510
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200511/**
Mythri P K93e39a12015-10-20 22:30:08 +0530512 * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
513 * kcontrol
514 * @kcontrol: The kcontrol
515 */
516struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
517 struct snd_kcontrol *kcontrol)
518{
519 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
520}
521EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
522
523/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200524 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
525 * kcontrol
526 * @kcontrol: The kcontrol
527 *
528 * Note: This function must only be used on kcontrols that are known to have
529 * been registered for a CODEC. Otherwise the behaviour is undefined.
530 */
531struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
532 struct snd_kcontrol *kcontrol)
533{
534 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
535}
536EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
537
Liam Girdwood6c120e12012-02-15 15:15:34 +0000538static void dapm_reset(struct snd_soc_card *card)
539{
540 struct snd_soc_dapm_widget *w;
541
Mark Brownf9fa2b12014-03-06 16:49:11 +0800542 lockdep_assert_held(&card->dapm_mutex);
543
Liam Girdwood6c120e12012-02-15 15:15:34 +0000544 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
545
546 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200547 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000548 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000549 }
550}
551
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200552static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
553{
554 if (!dapm->component)
555 return NULL;
556 return dapm->component->name_prefix;
557}
558
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200559static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800560 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100561{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200562 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200563 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200564 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100565}
566
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200567static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800568 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100569{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200570 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200571 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000572 return snd_soc_component_update_bits(dapm->component, reg,
573 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000574}
575
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200576static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
577 int reg, unsigned int mask, unsigned int value)
578{
579 if (!dapm->component)
580 return -EIO;
581 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
582}
583
Mark Browneb270e92013-10-09 13:52:52 +0100584static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
585{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200586 if (dapm->component)
587 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100588}
589
Charles Keepax45a110a2015-05-11 13:50:30 +0100590static struct snd_soc_dapm_widget *
591dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
592{
593 struct snd_soc_dapm_widget *w = wcache->widget;
594 struct list_head *wlist;
595 const int depth = 2;
596 int i = 0;
597
598 if (w) {
599 wlist = &w->dapm->card->widgets;
600
601 list_for_each_entry_from(w, wlist, list) {
602 if (!strcmp(name, w->name))
603 return w;
604
605 if (++i == depth)
606 break;
607 }
608 }
609
610 return NULL;
611}
612
613static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
614 struct snd_soc_dapm_widget *w)
615{
616 wcache->widget = w;
617}
618
Mark Brown452c5ea2009-05-17 21:41:23 +0100619/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200620 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
621 * @dapm: The DAPM context for which to set the level
622 * @level: The level to set
623 *
624 * Forces the DAPM bias level to a specific state. It will call the bias level
625 * callback of DAPM context with the specified level. This will even happen if
626 * the context is already at the same level. Furthermore it will not go through
627 * the normal bias level sequencing, meaning any intermediate states between the
628 * current and the target state will not be entered.
629 *
630 * Note that the change in bias level is only temporary and the next time
631 * snd_soc_dapm_sync() is called the state will be set to the level as
632 * determined by the DAPM core. The function is mainly intended to be used to
633 * used during probe or resume from suspend to power up the device so
634 * initialization can be done, before the DAPM core takes over.
635 */
636int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
637 enum snd_soc_bias_level level)
638{
639 int ret = 0;
640
641 if (dapm->set_bias_level)
642 ret = dapm->set_bias_level(dapm, level);
643
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200644 if (ret == 0)
645 dapm->bias_level = level;
646
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200647 return ret;
648}
649EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
650
Mark Brown452c5ea2009-05-17 21:41:23 +0100651/**
652 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800653 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100654 * @level: level to configure
655 *
656 * Configure the bias (power) levels for the SoC audio device.
657 *
658 * Returns 0 for success else error.
659 */
Mark Browned5a4c42011-02-18 11:12:42 -0800660static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200661 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100662{
Mark Browned5a4c42011-02-18 11:12:42 -0800663 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100664 int ret = 0;
665
Mark Brown84e90932010-11-04 00:07:02 -0400666 trace_snd_soc_bias_level_start(card, level);
667
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000668 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100669 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100670 if (ret != 0)
671 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100672
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200673 if (!card || dapm != &card->dapm)
674 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100675
Mark Brown171ec6b2011-06-06 18:15:19 +0100676 if (ret != 0)
677 goto out;
678
679 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100680 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100681out:
Mark Brown84e90932010-11-04 00:07:02 -0400682 trace_snd_soc_bias_level_done(card, level);
683
Mark Brown452c5ea2009-05-17 21:41:23 +0100684 return ret;
685}
686
Mark Brown74b8f952009-06-06 11:26:15 +0100687/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200688static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200689 struct snd_soc_dapm_path *path, const char *control_name,
690 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200691{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200692 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200693 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100694 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200695 int i;
696
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100697 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200698 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100699 val = (val >> e->shift_l) & e->mask;
700 item = snd_soc_enum_val_to_item(e, val);
701 } else {
702 /* since a virtual mux has no backing registers to
703 * decide which path to connect, it will try to match
704 * with the first enumeration. This is to ensure
705 * that the default mux choice (the first) will be
706 * correctly powered up during initialization.
707 */
708 item = 0;
709 }
710
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100711 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200712 if (!(strcmp(control_name, e->texts[i]))) {
Rasmus Villemoes98ad73c2014-10-21 17:01:15 +0200713 path->name = e->texts[i];
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100714 if (i == item)
715 path->connect = 1;
716 else
717 path->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200718 return 0;
719 }
720 }
721
722 return -ENODEV;
723}
724
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100725/* set up initial codec paths */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200726static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100727{
728 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200729 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100730 unsigned int reg = mc->reg;
731 unsigned int shift = mc->shift;
732 unsigned int max = mc->max;
733 unsigned int mask = (1 << fls(max)) - 1;
734 unsigned int invert = mc->invert;
735 unsigned int val;
736
737 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200738 soc_dapm_read(p->sink->dapm, reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100739 val = (val >> shift) & mask;
740 if (invert)
741 val = max - val;
742 p->connect = !!val;
743 } else {
744 p->connect = 0;
745 }
746}
747
Mark Brown74b8f952009-06-06 11:26:15 +0100748/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200749static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200750 struct snd_soc_dapm_path *path, const char *control_name)
751{
752 int i;
753
754 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200755 for (i = 0; i < path->sink->num_kcontrols; i++) {
756 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
757 path->name = path->sink->kcontrol_news[i].name;
758 dapm_set_mixer_path_status(path, i);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200759 return 0;
760 }
761 }
762 return -ENODEV;
763}
764
Stephen Warrenaf468002011-04-28 17:38:01 -0600765static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600766 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600767 const struct snd_kcontrol_new *kcontrol_new,
768 struct snd_kcontrol **kcontrol)
769{
770 struct snd_soc_dapm_widget *w;
771 int i;
772
773 *kcontrol = NULL;
774
775 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600776 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
777 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600778 for (i = 0; i < w->num_kcontrols; i++) {
779 if (&w->kcontrol_news[i] == kcontrol_new) {
780 if (w->kcontrols)
781 *kcontrol = w->kcontrols[i];
782 return 1;
783 }
784 }
785 }
786
787 return 0;
788}
789
Stephen Warren85762e72013-03-29 15:40:10 -0600790/*
791 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
792 * create it. Either way, add the widget into the control's widget list
793 */
Jeeja KP19a2557b2015-10-20 22:30:06 +0530794static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100795 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200796{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200797 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000798 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000799 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600800 size_t prefix_len;
801 int shared;
802 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600803 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200804 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600805 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200806 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000807
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200808 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000809 if (prefix)
810 prefix_len = strlen(prefix) + 1;
811 else
812 prefix_len = 0;
813
Stephen Warren85762e72013-03-29 15:40:10 -0600814 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
815 &kcontrol);
816
Stephen Warren85762e72013-03-29 15:40:10 -0600817 if (!kcontrol) {
818 if (shared) {
819 wname_in_long_name = false;
820 kcname_in_long_name = true;
821 } else {
822 switch (w->id) {
823 case snd_soc_dapm_switch:
824 case snd_soc_dapm_mixer:
Jeeja KP19a2557b2015-10-20 22:30:06 +0530825 case snd_soc_dapm_pga:
Stephen Warren85762e72013-03-29 15:40:10 -0600826 wname_in_long_name = true;
827 kcname_in_long_name = true;
828 break;
829 case snd_soc_dapm_mixer_named_ctl:
830 wname_in_long_name = false;
831 kcname_in_long_name = true;
832 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200833 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600834 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600835 wname_in_long_name = true;
836 kcname_in_long_name = false;
837 break;
838 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600839 return -EINVAL;
840 }
841 }
842
843 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600844 /*
845 * The control will get a prefix from the control
846 * creation process but we're also using the same
847 * prefix for widgets so cut the prefix off the
848 * front of the widget name.
849 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200850 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600851 w->name + prefix_len,
852 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200853 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200854 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600855
856 name = long_name;
857 } else if (wname_in_long_name) {
858 long_name = NULL;
859 name = w->name + prefix_len;
860 } else {
861 long_name = NULL;
862 name = w->kcontrol_news[kci].name;
863 }
864
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200865 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600866 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200867 if (!kcontrol) {
868 ret = -ENOMEM;
869 goto exit_free;
870 }
871
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200872 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200873
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100874 ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200875 if (ret) {
876 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200877 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200878 }
879
Stephen Warren85762e72013-03-29 15:40:10 -0600880 ret = snd_ctl_add(card, kcontrol);
881 if (ret < 0) {
882 dev_err(dapm->dev,
883 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
884 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200885 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600886 }
Stephen Warren85762e72013-03-29 15:40:10 -0600887 }
888
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200889 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200890 if (ret == 0)
891 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200892
Daniel Macke5092c92014-10-07 13:41:24 +0200893exit_free:
894 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600895
Daniel Macke5092c92014-10-07 13:41:24 +0200896 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600897}
898
899/* create new dapm mixer control */
900static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
901{
902 int i, ret;
903 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100904 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600905
Richard Purdie2b97eab2006-10-06 18:32:18 +0200906 /* add kcontrol */
907 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200908 /* match name */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200909 snd_soc_dapm_widget_for_each_source_path(w, path) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200910 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600911 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200912 continue;
913
Charles Keepax561ed682015-05-01 12:37:26 +0100914 if (!w->kcontrols[i]) {
Jeeja KP19a2557b2015-10-20 22:30:06 +0530915 ret = dapm_create_or_share_kcontrol(w, i);
Charles Keepax561ed682015-05-01 12:37:26 +0100916 if (ret < 0)
917 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200918 }
919
Mark Brown946d92a2013-08-12 23:28:42 +0100920 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100921
922 data = snd_kcontrol_chip(w->kcontrols[i]);
923 if (data->widget)
924 snd_soc_dapm_add_path(data->widget->dapm,
925 data->widget,
926 path->source,
927 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200928 }
929 }
Stephen Warren85762e72013-03-29 15:40:10 -0600930
931 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200932}
933
934/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200935static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200936{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200937 struct snd_soc_dapm_context *dapm = w->dapm;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200938 enum snd_soc_dapm_direction dir;
Stephen Warren85762e72013-03-29 15:40:10 -0600939 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200940 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600941 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200942
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200943 switch (w->id) {
944 case snd_soc_dapm_mux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200945 dir = SND_SOC_DAPM_DIR_OUT;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200946 type = "mux";
947 break;
948 case snd_soc_dapm_demux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200949 dir = SND_SOC_DAPM_DIR_IN;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200950 type = "demux";
951 break;
952 default:
953 return -EINVAL;
954 }
955
Stephen Warrenaf468002011-04-28 17:38:01 -0600956 if (w->num_kcontrols != 1) {
957 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200958 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600959 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200960 return -EINVAL;
961 }
962
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200963 if (list_empty(&w->edges[dir])) {
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200964 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600965 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600966 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200967
Jeeja KP19a2557b2015-10-20 22:30:06 +0530968 ret = dapm_create_or_share_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600969 if (ret < 0)
970 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600971
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200972 snd_soc_dapm_widget_for_each_path(w, dir, path) {
973 if (path->name)
974 dapm_kcontrol_add_path(w->kcontrols[0], path);
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +0200975 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200976
Stephen Warrenaf468002011-04-28 17:38:01 -0600977 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200978}
979
980/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200981static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200982{
Jeeja KP19a2557b2015-10-20 22:30:06 +0530983 int i, ret;
984
985 for (i = 0; i < w->num_kcontrols; i++) {
986 ret = dapm_create_or_share_kcontrol(w, i);
987 if (ret < 0)
988 return ret;
989 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200990
Mark Browna6c65732010-03-03 17:45:21 +0000991 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200992}
993
Nikesh Oswalc6615082015-02-02 17:06:44 +0000994/* create new dapm dai link control */
995static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
996{
997 int i, ret;
998 struct snd_kcontrol *kcontrol;
999 struct snd_soc_dapm_context *dapm = w->dapm;
1000 struct snd_card *card = dapm->card->snd_card;
1001
1002 /* create control for links with > 1 config */
1003 if (w->num_params <= 1)
1004 return 0;
1005
1006 /* add kcontrol */
1007 for (i = 0; i < w->num_kcontrols; i++) {
1008 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
1009 w->name, NULL);
1010 ret = snd_ctl_add(card, kcontrol);
1011 if (ret < 0) {
1012 dev_err(dapm->dev,
1013 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1014 w->name, w->kcontrol_news[i].name, ret);
1015 return ret;
1016 }
1017 kcontrol->private_data = w;
1018 w->kcontrols[i] = kcontrol;
1019 }
1020
1021 return 0;
1022}
1023
Mark Brown99497882010-05-07 20:24:05 +01001024/* We implement power down on suspend by checking the power state of
1025 * the ALSA card - when we are suspending the ALSA state for the card
1026 * is set to D3.
1027 */
1028static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1029{
Mark Brown12ea2c72011-03-02 18:17:32 +00001030 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +01001031
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001032 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +01001033 case SNDRV_CTL_POWER_D3hot:
1034 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +01001035 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001036 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001037 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +01001038 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +01001039 default:
1040 return 1;
1041 }
1042}
1043
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001044static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1045 struct list_head *widgets)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001046{
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001047 struct snd_soc_dapm_widget *w;
1048 struct list_head *it;
1049 unsigned int size = 0;
1050 unsigned int i = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001051
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001052 list_for_each(it, widgets)
1053 size++;
1054
1055 *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001056 if (*list == NULL)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001057 return -ENOMEM;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001058
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001059 list_for_each_entry(w, widgets, work_list)
1060 (*list)->widgets[i++] = w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001061
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001062 (*list)->num_widgets = i;
1063
1064 return 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001065}
1066
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001067/*
1068 * Common implementation for is_connected_output_ep() and
1069 * is_connected_input_ep(). The function is inlined since the combined size of
1070 * the two specialized functions is only marginally larger then the size of the
1071 * generic function and at the same time the fast path of the specialized
1072 * functions is significantly smaller than the generic function.
1073 */
1074static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
1075 struct list_head *list, enum snd_soc_dapm_direction dir,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001076 int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
1077 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1078 enum snd_soc_dapm_direction)),
1079 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1080 enum snd_soc_dapm_direction))
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001081{
1082 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001083 struct snd_soc_dapm_path *path;
1084 int con = 0;
1085
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001086 if (widget->endpoints[dir] >= 0)
1087 return widget->endpoints[dir];
Mark Brown024dc072011-10-09 11:52:05 +01001088
Mark Brownde02d072011-09-20 21:43:24 +01001089 DAPM_UPDATE_STAT(widget, path_checks);
1090
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001091 /* do we need to add this widget to the list ? */
1092 if (list)
1093 list_add_tail(&widget->work_list, list);
1094
Jeeja KP09464972016-06-15 11:16:55 +05301095 if (custom_stop_condition && custom_stop_condition(widget, dir)) {
1096 widget->endpoints[dir] = 1;
1097 return widget->endpoints[dir];
1098 }
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001099
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001100 if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
1101 widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
1102 return widget->endpoints[dir];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001103 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001104
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001105 snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
Mark Browne56235e02011-09-21 18:19:14 +01001106 DAPM_UPDATE_STAT(widget, neighbour_checks);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001107
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001108 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001109 continue;
1110
Mark Brown8af294b2013-02-22 17:48:15 +00001111 if (path->walking)
1112 return 1;
1113
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001114 trace_snd_soc_dapm_path(widget, dir, path);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001115
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001116 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001117 path->walking = 1;
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001118 con += fn(path->node[dir], list, custom_stop_condition);
Mark Brown8af294b2013-02-22 17:48:15 +00001119 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001120 }
1121 }
1122
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001123 widget->endpoints[dir] = con;
Mark Brown024dc072011-10-09 11:52:05 +01001124
Richard Purdie2b97eab2006-10-06 18:32:18 +02001125 return con;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001126}
1127
1128/*
1129 * Recursively check for a completed path to an active or physically connected
1130 * output widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001131 *
1132 * Optionally, can be supplied with a function acting as a stopping condition.
1133 * This function takes the dapm widget currently being examined and the walk
1134 * direction as an arguments, it should return true if the walk should be
1135 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001136 */
1137static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001138 struct list_head *list,
1139 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1140 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001141{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001142 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001143 is_connected_output_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001144}
1145
1146/*
1147 * Recursively check for a completed path to an active or physically connected
1148 * input widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001149 *
1150 * Optionally, can be supplied with a function acting as a stopping condition.
1151 * This function takes the dapm widget currently being examined and the walk
1152 * direction as an arguments, it should return true if the walk should be
1153 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001154 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001155static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001156 struct list_head *list,
1157 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1158 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001159{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001160 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001161 is_connected_input_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001162}
1163
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001164/**
1165 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1166 * @dai: the soc DAI.
1167 * @stream: stream direction.
1168 * @list: list of active widgets for this stream.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001169 * @custom_stop_condition: (optional) a function meant to stop the widget graph
1170 * walk based on custom logic.
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001171 *
1172 * Queries DAPM graph as to whether an valid audio stream path exists for
1173 * the initial stream specified by name. This takes into account
1174 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1175 *
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001176 * Optionally, can be supplied with a function acting as a stopping condition.
1177 * This function takes the dapm widget currently being examined and the walk
1178 * direction as an arguments, it should return true if the walk should be
1179 * stopped and false otherwise.
1180 *
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001181 * Returns the number of valid paths or negative error.
1182 */
1183int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001184 struct snd_soc_dapm_widget_list **list,
1185 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1186 enum snd_soc_dapm_direction))
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001187{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001188 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001189 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001190 LIST_HEAD(widgets);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001191 int paths;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001192 int ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001193
1194 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001195
1196 /*
1197 * For is_connected_{output,input}_ep fully discover the graph we need
1198 * to reset the cached number of inputs and outputs.
1199 */
1200 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001201 w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
1202 w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001203 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001204
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001205 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001206 paths = is_connected_output_ep(dai->playback_widget, &widgets,
1207 custom_stop_condition);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001208 else
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001209 paths = is_connected_input_ep(dai->capture_widget, &widgets,
1210 custom_stop_condition);
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001211
1212 /* Drop starting point */
1213 list_del(widgets.next);
1214
1215 ret = dapm_widget_list_create(list, &widgets);
1216 if (ret)
Lars-Peter Clausen30abbe72015-08-11 21:37:59 +02001217 paths = ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001218
1219 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001220 mutex_unlock(&card->dapm_mutex);
1221
1222 return paths;
1223}
1224
Richard Purdie2b97eab2006-10-06 18:32:18 +02001225/*
Mark Brown62ea8742012-01-21 21:14:48 +00001226 * Handler for regulator supply widget.
1227 */
1228int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1229 struct snd_kcontrol *kcontrol, int event)
1230{
Mark Brownc05b84d2012-09-07 12:57:11 +08001231 int ret;
1232
Mark Browneb270e92013-10-09 13:52:52 +01001233 soc_dapm_async_complete(w->dapm);
1234
Mark Brownc05b84d2012-09-07 12:57:11 +08001235 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001236 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001237 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001238 if (ret != 0)
1239 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001240 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001241 w->name, ret);
1242 }
1243
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001244 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001245 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001246 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001247 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001248 if (ret != 0)
1249 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001250 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001251 w->name, ret);
1252 }
1253
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001254 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001255 }
Mark Brown62ea8742012-01-21 21:14:48 +00001256}
1257EXPORT_SYMBOL_GPL(dapm_regulator_event);
1258
Ola Liljad7e7eb92012-05-24 15:26:25 +02001259/*
1260 * Handler for clock supply widget.
1261 */
1262int dapm_clock_event(struct snd_soc_dapm_widget *w,
1263 struct snd_kcontrol *kcontrol, int event)
1264{
1265 if (!w->clk)
1266 return -EIO;
1267
Mark Browneb270e92013-10-09 13:52:52 +01001268 soc_dapm_async_complete(w->dapm);
1269
Mark Brownec029952012-06-04 08:16:20 +01001270#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001271 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001272 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001273 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001274 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001275 return 0;
1276 }
Mark Brownec029952012-06-04 08:16:20 +01001277#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001278 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001279}
1280EXPORT_SYMBOL_GPL(dapm_clock_event);
1281
Mark Brownd8050022011-09-28 18:28:23 +01001282static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1283{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001284 if (w->power_checked)
1285 return w->new_power;
1286
Mark Brownd8050022011-09-28 18:28:23 +01001287 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001288 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001289 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001290 w->new_power = w->power_check(w);
1291
1292 w->power_checked = true;
1293
1294 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001295}
1296
Mark Browncd0f2d42009-04-20 16:56:59 +01001297/* Generic check to see if a widget should be powered.
1298 */
1299static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1300{
1301 int in, out;
1302
Mark Brownde02d072011-09-20 21:43:24 +01001303 DAPM_UPDATE_STAT(w, power_checks);
1304
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001305 in = is_connected_input_ep(w, NULL, NULL);
1306 out = is_connected_output_ep(w, NULL, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001307 return out != 0 && in != 0;
1308}
1309
Mark Brown246d0a12009-04-22 18:24:55 +01001310/* Check to see if a power supply is needed */
1311static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1312{
1313 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001314
Mark Brownde02d072011-09-20 21:43:24 +01001315 DAPM_UPDATE_STAT(w, power_checks);
1316
Mark Brown246d0a12009-04-22 18:24:55 +01001317 /* Check if one of our outputs is connected */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001318 snd_soc_dapm_widget_for_each_sink_path(w, path) {
Mark Browna8fdac82011-09-28 18:20:26 +01001319 DAPM_UPDATE_STAT(w, neighbour_checks);
1320
Mark Brownbf3a9e12011-06-13 16:42:29 +01001321 if (path->weak)
1322 continue;
1323
Mark Brown215edda2009-09-08 18:59:05 +01001324 if (path->connected &&
1325 !path->connected(path->source, path->sink))
1326 continue;
1327
Mark Brownf68d7e12011-10-04 22:57:50 +01001328 if (dapm_widget_power_check(path->sink))
1329 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001330 }
1331
Mark Brownf68d7e12011-10-04 22:57:50 +01001332 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001333}
1334
Mark Brown35c64bc2011-09-28 18:23:53 +01001335static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1336{
Charles Keepax20bb0182015-12-02 10:22:16 +00001337 return w->connected;
Mark Brown35c64bc2011-09-28 18:23:53 +01001338}
1339
Mark Brown38357ab2009-06-06 19:03:23 +01001340static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1341 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001342 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001343{
Mark Brown828a8422011-01-15 13:14:30 +00001344 int *sort;
1345
1346 if (power_up)
1347 sort = dapm_up_seq;
1348 else
1349 sort = dapm_down_seq;
1350
Mark Brown38357ab2009-06-06 19:03:23 +01001351 if (sort[a->id] != sort[b->id])
1352 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001353 if (a->subseq != b->subseq) {
1354 if (power_up)
1355 return a->subseq - b->subseq;
1356 else
1357 return b->subseq - a->subseq;
1358 }
Mark Brownb22ead22009-06-07 12:51:26 +01001359 if (a->reg != b->reg)
1360 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001361 if (a->dapm != b->dapm)
1362 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001363
Mark Brown38357ab2009-06-06 19:03:23 +01001364 return 0;
1365}
Mark Brown42aa3412009-03-01 19:21:10 +00001366
Mark Brown38357ab2009-06-06 19:03:23 +01001367/* Insert a widget in order into a DAPM power sequence. */
1368static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1369 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001370 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001371{
1372 struct snd_soc_dapm_widget *w;
1373
1374 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001375 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001376 list_add_tail(&new_widget->power_list, &w->power_list);
1377 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001378 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001379
Mark Brown38357ab2009-06-06 19:03:23 +01001380 list_add_tail(&new_widget->power_list, list);
1381}
Mark Brown42aa3412009-03-01 19:21:10 +00001382
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001383static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001384 struct snd_soc_dapm_widget *w, int event)
1385{
Mark Brown68f89ad2010-11-03 23:51:49 -04001386 const char *ev_name;
1387 int power, ret;
1388
1389 switch (event) {
1390 case SND_SOC_DAPM_PRE_PMU:
1391 ev_name = "PRE_PMU";
1392 power = 1;
1393 break;
1394 case SND_SOC_DAPM_POST_PMU:
1395 ev_name = "POST_PMU";
1396 power = 1;
1397 break;
1398 case SND_SOC_DAPM_PRE_PMD:
1399 ev_name = "PRE_PMD";
1400 power = 0;
1401 break;
1402 case SND_SOC_DAPM_POST_PMD:
1403 ev_name = "POST_PMD";
1404 power = 0;
1405 break;
Mark Brown80114122013-02-25 15:14:19 +00001406 case SND_SOC_DAPM_WILL_PMU:
1407 ev_name = "WILL_PMU";
1408 power = 1;
1409 break;
1410 case SND_SOC_DAPM_WILL_PMD:
1411 ev_name = "WILL_PMD";
1412 power = 0;
1413 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001414 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001415 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001416 return;
1417 }
1418
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001419 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001420 return;
1421
1422 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001423 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001424 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001425 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001426 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001427 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001428 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001429 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001430 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001431 ev_name, w->name, ret);
1432 }
1433}
1434
Mark Brownb22ead22009-06-07 12:51:26 +01001435/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001436static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001437 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001438{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001439 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001440 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001441 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001442 unsigned int value = 0;
1443 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001444
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001445 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1446 reg = w->reg;
1447 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001448
1449 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001450 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001451 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001452
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001453 mask |= w->mask << w->shift;
1454 if (w->power)
1455 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001456 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001457 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001458
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001459 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001460 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1461 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001462
Mark Brown68f89ad2010-11-03 23:51:49 -04001463 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001464 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1465 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001466 }
1467
Mark Brown81628102009-06-07 13:21:24 +01001468 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001469 /* Any widget will do, they should all be updating the
1470 * same register.
1471 */
Mark Brown29376bc2011-06-19 13:49:28 +01001472
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001473 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001474 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001475 value, mask, reg, card->pop_time);
1476 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001477 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001478 }
1479
1480 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001481 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1482 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001483 }
Mark Brown42aa3412009-03-01 19:21:10 +00001484}
1485
Mark Brownb22ead22009-06-07 12:51:26 +01001486/* Apply a DAPM power sequence.
1487 *
1488 * We walk over a pre-sorted list of widgets to apply power to. In
1489 * order to minimise the number of writes to the device required
1490 * multiple widgets will be updated in a single write where possible.
1491 * Currently anything that requires more than a single write is not
1492 * handled.
1493 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001494static void dapm_seq_run(struct snd_soc_card *card,
1495 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001496{
1497 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001498 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001499 LIST_HEAD(pending);
1500 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001501 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001502 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001503 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001504 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001505 int *sort;
1506
1507 if (power_up)
1508 sort = dapm_up_seq;
1509 else
1510 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001511
Mark Brownb22ead22009-06-07 12:51:26 +01001512 list_for_each_entry_safe(w, n, list, power_list) {
1513 ret = 0;
1514
1515 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001516 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001517 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001518 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001519 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001520
Mark Brown474b62d2011-01-18 16:14:44 +00001521 if (cur_dapm && cur_dapm->seq_notifier) {
1522 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1523 if (sort[i] == cur_sort)
1524 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001525 i,
1526 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001527 }
1528
Mark Browneb270e92013-10-09 13:52:52 +01001529 if (cur_dapm && w->dapm != cur_dapm)
1530 soc_dapm_async_complete(cur_dapm);
1531
Mark Brownb22ead22009-06-07 12:51:26 +01001532 INIT_LIST_HEAD(&pending);
1533 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001534 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001535 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001536 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001537 }
1538
Mark Brown163cac02009-06-07 10:12:52 +01001539 switch (w->id) {
1540 case snd_soc_dapm_pre:
1541 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001542 list_for_each_entry_safe_continue(w, n, list,
1543 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001544
Mark Brownb22ead22009-06-07 12:51:26 +01001545 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001546 ret = w->event(w,
1547 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001548 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001549 ret = w->event(w,
1550 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001551 break;
1552
1553 case snd_soc_dapm_post:
1554 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001555 list_for_each_entry_safe_continue(w, n, list,
1556 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001557
Mark Brownb22ead22009-06-07 12:51:26 +01001558 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001559 ret = w->event(w,
1560 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001561 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001562 ret = w->event(w,
1563 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001564 break;
1565
Mark Brown163cac02009-06-07 10:12:52 +01001566 default:
Mark Brown81628102009-06-07 13:21:24 +01001567 /* Queue it up for application */
1568 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001569 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001570 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001571 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001572 list_move(&w->power_list, &pending);
1573 break;
Mark Brown163cac02009-06-07 10:12:52 +01001574 }
Mark Brownb22ead22009-06-07 12:51:26 +01001575
1576 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001577 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001578 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001579 }
Mark Brownb22ead22009-06-07 12:51:26 +01001580
1581 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001582 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001583
1584 if (cur_dapm && cur_dapm->seq_notifier) {
1585 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1586 if (sort[i] == cur_sort)
1587 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001588 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001589 }
Mark Browneb270e92013-10-09 13:52:52 +01001590
1591 list_for_each_entry(d, &card->dapm_list, list) {
1592 soc_dapm_async_complete(d);
1593 }
Mark Brown163cac02009-06-07 10:12:52 +01001594}
1595
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001596static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001597{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001598 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001599 struct snd_soc_dapm_widget_list *wlist;
1600 struct snd_soc_dapm_widget *w = NULL;
1601 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001602 int ret;
1603
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001604 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001605 return;
1606
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001607 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001608
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001609 for (wi = 0; wi < wlist->num_widgets; wi++) {
1610 w = wlist->widgets[wi];
1611
1612 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1613 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1614 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001615 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001616 w->name, ret);
1617 }
Mark Brown97404f22010-12-14 16:13:57 +00001618 }
1619
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001620 if (!w)
1621 return;
1622
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001623 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1624 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001625 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001626 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001627 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001628
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001629 for (wi = 0; wi < wlist->num_widgets; wi++) {
1630 w = wlist->widgets[wi];
1631
1632 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1633 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1634 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001635 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001636 w->name, ret);
1637 }
Mark Brown97404f22010-12-14 16:13:57 +00001638 }
1639}
1640
Mark Brown9d0624a2011-02-18 11:49:43 -08001641/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1642 * they're changing state.
1643 */
1644static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1645{
1646 struct snd_soc_dapm_context *d = data;
1647 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001648
Mark Brown56fba412011-06-04 11:25:10 +01001649 /* If we're off and we're not supposed to be go into STANDBY */
1650 if (d->bias_level == SND_SOC_BIAS_OFF &&
1651 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001652 if (d->dev)
1653 pm_runtime_get_sync(d->dev);
1654
Mark Brown9d0624a2011-02-18 11:49:43 -08001655 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1656 if (ret != 0)
1657 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001658 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001659 }
1660
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001661 /* Prepare for a transition to ON or away from ON */
1662 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1663 d->bias_level != SND_SOC_BIAS_ON) ||
1664 (d->target_bias_level != SND_SOC_BIAS_ON &&
1665 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001666 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1667 if (ret != 0)
1668 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001669 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001670 }
1671}
1672
1673/* Async callback run prior to DAPM sequences - brings to their final
1674 * state.
1675 */
1676static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1677{
1678 struct snd_soc_dapm_context *d = data;
1679 int ret;
1680
1681 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001682 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1683 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1684 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001685 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1686 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001687 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001688 ret);
1689 }
1690
1691 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001692 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1693 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001694 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1695 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001696 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1697 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001698
1699 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001700 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001701 }
1702
1703 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001704 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1705 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001706 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1707 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001708 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001709 ret);
1710 }
1711}
Mark Brown97404f22010-12-14 16:13:57 +00001712
Mark Brownfe4fda52011-10-03 22:36:57 +01001713static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1714 bool power, bool connect)
1715{
1716 /* If a connection is being made or broken then that update
1717 * will have marked the peer dirty, otherwise the widgets are
1718 * not connected and this update has no impact. */
1719 if (!connect)
1720 return;
1721
1722 /* If the peer is already in the state we're moving to then we
1723 * won't have an impact on it. */
1724 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001725 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001726}
1727
Mark Brown05623c42011-09-28 17:02:31 +01001728static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1729 struct list_head *up_list,
1730 struct list_head *down_list)
1731{
Mark Browndb432b42011-10-03 21:06:40 +01001732 struct snd_soc_dapm_path *path;
1733
Mark Brown05623c42011-09-28 17:02:31 +01001734 if (w->power == power)
1735 return;
1736
1737 trace_snd_soc_dapm_widget_power(w, power);
1738
Mark Browndb432b42011-10-03 21:06:40 +01001739 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001740 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001741 */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001742 snd_soc_dapm_widget_for_each_source_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001743 dapm_widget_set_peer_power(path->source, power, path->connect);
1744
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001745 /* Supplies can't affect their outputs, only their inputs */
1746 if (!w->is_supply) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001747 snd_soc_dapm_widget_for_each_sink_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001748 dapm_widget_set_peer_power(path->sink, power,
1749 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001750 }
1751
Mark Brown05623c42011-09-28 17:02:31 +01001752 if (power)
1753 dapm_seq_insert(w, up_list, true);
1754 else
1755 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001756}
1757
Mark Brown7c81beb2011-09-20 22:22:32 +01001758static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1759 struct list_head *up_list,
1760 struct list_head *down_list)
1761{
Mark Brown7c81beb2011-09-20 22:22:32 +01001762 int power;
1763
1764 switch (w->id) {
1765 case snd_soc_dapm_pre:
1766 dapm_seq_insert(w, down_list, false);
1767 break;
1768 case snd_soc_dapm_post:
1769 dapm_seq_insert(w, up_list, true);
1770 break;
1771
1772 default:
Mark Brownd8050022011-09-28 18:28:23 +01001773 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001774
Mark Brown05623c42011-09-28 17:02:31 +01001775 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001776 break;
1777 }
1778}
1779
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001780static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1781{
1782 if (dapm->idle_bias_off)
1783 return true;
1784
1785 switch (snd_power_get_state(dapm->card->snd_card)) {
1786 case SNDRV_CTL_POWER_D3hot:
1787 case SNDRV_CTL_POWER_D3cold:
1788 return dapm->suspend_bias_off;
1789 default:
1790 break;
1791 }
1792
1793 return false;
1794}
1795
Mark Brown42aa3412009-03-01 19:21:10 +00001796/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001797 * Scan each dapm widget for complete audio path.
1798 * A complete path is a route that has valid endpoints i.e.:-
1799 *
1800 * o DAC to output pin.
1801 * o Input Pin to ADC.
1802 * o Input pin to Output pin (bypass, sidetone)
1803 * o DAC to ADC (loopback).
1804 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001805static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001806{
1807 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001808 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001809 LIST_HEAD(up_list);
1810 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001811 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001812 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001813
Mark Brownf9fa2b12014-03-06 16:49:11 +08001814 lockdep_assert_held(&card->dapm_mutex);
1815
Mark Brown84e90932010-11-04 00:07:02 -04001816 trace_snd_soc_dapm_start(card);
1817
Mark Brown56fba412011-06-04 11:25:10 +01001818 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001819 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001820 d->target_bias_level = SND_SOC_BIAS_OFF;
1821 else
1822 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001823 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001824
Liam Girdwood6c120e12012-02-15 15:15:34 +00001825 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001826
Mark Brown6d3ddc82009-05-16 17:47:29 +01001827 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001828 * lists indicating if they should be powered up or down. We
1829 * only check widgets that have been flagged as dirty but note
1830 * that new widgets may be added to the dirty list while we
1831 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001832 */
Mark Browndb432b42011-10-03 21:06:40 +01001833 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001834 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001835 }
1836
Mark Brownf9de6d72011-09-28 17:19:47 +01001837 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001838 switch (w->id) {
1839 case snd_soc_dapm_pre:
1840 case snd_soc_dapm_post:
1841 /* These widgets always need to be powered */
1842 break;
1843 default:
1844 list_del_init(&w->dirty);
1845 break;
1846 }
Mark Browndb432b42011-10-03 21:06:40 +01001847
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001848 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001849 d = w->dapm;
1850
1851 /* Supplies and micbiases only bring the
1852 * context up to STANDBY as unless something
1853 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001854 * generally don't require full power. Signal
1855 * generators are virtual pins and have no
1856 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001857 */
1858 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001859 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001860 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001861 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001862 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001863 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001864 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001865 case snd_soc_dapm_micbias:
1866 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1867 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1868 break;
1869 default:
1870 d->target_bias_level = SND_SOC_BIAS_ON;
1871 break;
1872 }
1873 }
1874
1875 }
1876
Mark Brown85a843c2011-09-21 21:29:47 +01001877 /* Force all contexts in the card to the same bias state if
1878 * they're not ground referenced.
1879 */
Mark Brown56fba412011-06-04 11:25:10 +01001880 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001881 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001882 if (d->target_bias_level > bias)
1883 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001884 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001885 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001886 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001887
Mark Brownde02d072011-09-20 21:43:24 +01001888 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001889
Xiang Xiao17282ba2014-03-02 00:04:03 +08001890 /* Run card bias changes at first */
1891 dapm_pre_sequence_async(&card->dapm, 0);
1892 /* Run other bias changes in parallel */
1893 list_for_each_entry(d, &card->dapm_list, list) {
1894 if (d != &card->dapm)
1895 async_schedule_domain(dapm_pre_sequence_async, d,
1896 &async_domain);
1897 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001898 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001899
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001900 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001901 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001902 }
1903
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001904 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001905 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001906 }
1907
Mark Brown6d3ddc82009-05-16 17:47:29 +01001908 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001909 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001910
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001911 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001912
Mark Brown6d3ddc82009-05-16 17:47:29 +01001913 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001914 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001915
Mark Brown9d0624a2011-02-18 11:49:43 -08001916 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001917 list_for_each_entry(d, &card->dapm_list, list) {
1918 if (d != &card->dapm)
1919 async_schedule_domain(dapm_post_sequence_async, d,
1920 &async_domain);
1921 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001922 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001923 /* Run card bias changes at last */
1924 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001925
Liam Girdwood8078d872012-02-15 15:15:35 +00001926 /* do we need to notify any clients that DAPM event is complete */
1927 list_for_each_entry(d, &card->dapm_list, list) {
1928 if (d->stream_event)
1929 d->stream_event(d, event);
1930 }
1931
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001932 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001933 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001934 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001935
Mark Brown84e90932010-11-04 00:07:02 -04001936 trace_snd_soc_dapm_done(card);
1937
Mark Brown42aa3412009-03-01 19:21:10 +00001938 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001939}
1940
Mark Brown79fb9382009-08-21 16:38:13 +01001941#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001942static ssize_t dapm_widget_power_read_file(struct file *file,
1943 char __user *user_buf,
1944 size_t count, loff_t *ppos)
1945{
1946 struct snd_soc_dapm_widget *w = file->private_data;
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001947 struct snd_soc_card *card = w->dapm->card;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001948 enum snd_soc_dapm_direction dir, rdir;
Mark Brown79fb9382009-08-21 16:38:13 +01001949 char *buf;
1950 int in, out;
1951 ssize_t ret;
1952 struct snd_soc_dapm_path *p = NULL;
1953
1954 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1955 if (!buf)
1956 return -ENOMEM;
1957
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001958 mutex_lock(&card->dapm_mutex);
1959
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001960 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
1961 if (w->is_supply) {
1962 in = 0;
1963 out = 0;
1964 } else {
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001965 in = is_connected_input_ep(w, NULL, NULL);
1966 out = is_connected_output_ep(w, NULL, NULL);
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001967 }
Mark Brown79fb9382009-08-21 16:38:13 +01001968
Mark Brownf13ebad2012-03-03 18:01:01 +00001969 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1970 w->name, w->power ? "On" : "Off",
1971 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001972
Mark Brownd033c362009-12-04 15:25:56 +00001973 if (w->reg >= 0)
1974 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001975 " - R%d(0x%x) mask 0x%x",
1976 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00001977
1978 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1979
Mark Brown3eef08b2009-09-14 16:49:00 +01001980 if (w->sname)
1981 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1982 w->sname,
1983 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001984
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001985 snd_soc_dapm_for_each_direction(dir) {
1986 rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
1987 snd_soc_dapm_widget_for_each_path(w, dir, p) {
1988 if (p->connected && !p->connected(w, p->node[rdir]))
1989 continue;
Mark Brown215edda2009-09-08 18:59:05 +01001990
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001991 if (!p->connect)
1992 continue;
Mark Brown215edda2009-09-08 18:59:05 +01001993
Mark Brown79fb9382009-08-21 16:38:13 +01001994 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001995 " %s \"%s\" \"%s\"\n",
1996 (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
Mark Brown79fb9382009-08-21 16:38:13 +01001997 p->name ? p->name : "static",
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001998 p->node[rdir]->name);
1999 }
Mark Brown79fb9382009-08-21 16:38:13 +01002000 }
2001
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002002 mutex_unlock(&card->dapm_mutex);
2003
Mark Brown79fb9382009-08-21 16:38:13 +01002004 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
2005
2006 kfree(buf);
2007 return ret;
2008}
2009
2010static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002011 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01002012 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002013 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01002014};
2015
Mark Brownef49e4f2011-04-04 20:48:13 +09002016static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
2017 size_t count, loff_t *ppos)
2018{
2019 struct snd_soc_dapm_context *dapm = file->private_data;
2020 char *level;
2021
2022 switch (dapm->bias_level) {
2023 case SND_SOC_BIAS_ON:
2024 level = "On\n";
2025 break;
2026 case SND_SOC_BIAS_PREPARE:
2027 level = "Prepare\n";
2028 break;
2029 case SND_SOC_BIAS_STANDBY:
2030 level = "Standby\n";
2031 break;
2032 case SND_SOC_BIAS_OFF:
2033 level = "Off\n";
2034 break;
2035 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002036 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002037 level = "Unknown\n";
2038 break;
2039 }
2040
2041 return simple_read_from_buffer(user_buf, count, ppos, level,
2042 strlen(level));
2043}
2044
2045static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002046 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002047 .read = dapm_bias_read_file,
2048 .llseek = default_llseek,
2049};
2050
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002051void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2052 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002053{
Mark Brown79fb9382009-08-21 16:38:13 +01002054 struct dentry *d;
2055
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002056 if (!parent)
2057 return;
2058
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002059 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2060
2061 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002062 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002063 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002064 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002065 }
Mark Brown79fb9382009-08-21 16:38:13 +01002066
Mark Brownef49e4f2011-04-04 20:48:13 +09002067 d = debugfs_create_file("bias_level", 0444,
2068 dapm->debugfs_dapm, dapm,
2069 &dapm_bias_fops);
2070 if (!d)
2071 dev_warn(dapm->dev,
2072 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002073}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002074
2075static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2076{
2077 struct snd_soc_dapm_context *dapm = w->dapm;
2078 struct dentry *d;
2079
2080 if (!dapm->debugfs_dapm || !w->name)
2081 return;
2082
2083 d = debugfs_create_file(w->name, 0444,
2084 dapm->debugfs_dapm, w,
2085 &dapm_widget_power_fops);
2086 if (!d)
2087 dev_warn(w->dapm->dev,
2088 "ASoC: Failed to create %s debugfs file\n",
2089 w->name);
2090}
2091
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002092static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2093{
2094 debugfs_remove_recursive(dapm->debugfs_dapm);
2095}
2096
Mark Brown79fb9382009-08-21 16:38:13 +01002097#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002098void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2099 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002100{
2101}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002102
2103static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2104{
2105}
2106
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002107static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2108{
2109}
2110
Mark Brown79fb9382009-08-21 16:38:13 +01002111#endif
2112
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002113/*
2114 * soc_dapm_connect_path() - Connects or disconnects a path
2115 * @path: The path to update
2116 * @connect: The new connect state of the path. True if the path is connected,
2117 * false if it is disconneted.
2118 * @reason: The reason why the path changed (for debugging only)
2119 */
2120static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2121 bool connect, const char *reason)
2122{
2123 if (path->connect == connect)
2124 return;
2125
2126 path->connect = connect;
2127 dapm_mark_dirty(path->source, reason);
2128 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002129 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002130}
2131
Richard Purdie2b97eab2006-10-06 18:32:18 +02002132/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002133static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002134 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002135{
2136 struct snd_soc_dapm_path *path;
2137 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002138 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002139
Mark Brownf9fa2b12014-03-06 16:49:11 +08002140 lockdep_assert_held(&card->dapm_mutex);
2141
Richard Purdie2b97eab2006-10-06 18:32:18 +02002142 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002143 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002144 found = 1;
2145 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002146 if (!(strcmp(path->name, e->texts[mux])))
2147 connect = true;
2148 else
2149 connect = false;
2150
2151 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002152 }
2153
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002154 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002155 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002156
Liam Girdwood618dae12012-04-25 12:12:51 +01002157 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002158}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002159
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002160int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002161 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2162 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002163{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002164 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002165 int ret;
2166
Liam Girdwood3cd04342012-03-09 12:02:08 +00002167 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002168 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002169 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002170 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002171 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002172 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002173 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002174 return ret;
2175}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002176EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002177
Milan plzik1b075e32008-01-10 14:39:46 +01002178/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002179static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Mark Brown283375c2009-12-07 18:09:03 +00002180 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002181{
2182 struct snd_soc_dapm_path *path;
2183 int found = 0;
2184
Mark Brownf9fa2b12014-03-06 16:49:11 +08002185 lockdep_assert_held(&card->dapm_mutex);
2186
Richard Purdie2b97eab2006-10-06 18:32:18 +02002187 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002188 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002189 found = 1;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002190 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002191 }
2192
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002193 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002194 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002195
Liam Girdwood618dae12012-04-25 12:12:51 +01002196 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002197}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002198
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002199int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002200 struct snd_kcontrol *kcontrol, int connect,
2201 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002202{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002203 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002204 int ret;
2205
Liam Girdwood3cd04342012-03-09 12:02:08 +00002206 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002207 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002208 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002209 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002210 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002211 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002212 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002213 return ret;
2214}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002215EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002216
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002217static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
2218 char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002219{
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002220 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002221 struct snd_soc_dapm_widget *w;
2222 int count = 0;
2223 char *state = "not set";
2224
Mark Brown47325072016-03-18 12:04:23 +00002225 /* card won't be set for the dummy component, as a spot fix
2226 * we're checking for that case specifically here but in future
2227 * we will ensure that the dummy component looks like others.
2228 */
2229 if (!cmpnt->card)
2230 return 0;
2231
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002232 list_for_each_entry(w, &cmpnt->card->widgets, list) {
2233 if (w->dapm != dapm)
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002234 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002235
2236 /* only display widgets that burnm power */
2237 switch (w->id) {
2238 case snd_soc_dapm_hp:
2239 case snd_soc_dapm_mic:
2240 case snd_soc_dapm_spk:
2241 case snd_soc_dapm_line:
2242 case snd_soc_dapm_micbias:
2243 case snd_soc_dapm_dac:
2244 case snd_soc_dapm_adc:
2245 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002246 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002247 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002248 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002249 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002250 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002251 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002252 if (w->name)
2253 count += sprintf(buf + count, "%s: %s\n",
2254 w->name, w->power ? "On":"Off");
2255 break;
2256 default:
2257 break;
2258 }
2259 }
2260
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002261 switch (snd_soc_dapm_get_bias_level(dapm)) {
Mark Brown0be98982008-05-19 12:31:28 +02002262 case SND_SOC_BIAS_ON:
2263 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002264 break;
Mark Brown0be98982008-05-19 12:31:28 +02002265 case SND_SOC_BIAS_PREPARE:
2266 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002267 break;
Mark Brown0be98982008-05-19 12:31:28 +02002268 case SND_SOC_BIAS_STANDBY:
2269 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002270 break;
Mark Brown0be98982008-05-19 12:31:28 +02002271 case SND_SOC_BIAS_OFF:
2272 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002273 break;
2274 }
2275 count += sprintf(buf + count, "PM State: %s\n", state);
2276
2277 return count;
2278}
2279
Benoit Cousson44ba2642014-07-08 23:19:36 +02002280/* show dapm widget status in sys fs */
2281static ssize_t dapm_widget_show(struct device *dev,
2282 struct device_attribute *attr, char *buf)
2283{
2284 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2285 int i, count = 0;
2286
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002287 mutex_lock(&rtd->card->dapm_mutex);
2288
Benoit Cousson44ba2642014-07-08 23:19:36 +02002289 for (i = 0; i < rtd->num_codecs; i++) {
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002290 struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component;
2291
2292 count += dapm_widget_show_component(cmpnt, buf + count);
Benoit Cousson44ba2642014-07-08 23:19:36 +02002293 }
2294
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002295 mutex_unlock(&rtd->card->dapm_mutex);
2296
Benoit Cousson44ba2642014-07-08 23:19:36 +02002297 return count;
2298}
2299
Richard Purdie2b97eab2006-10-06 18:32:18 +02002300static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2301
Takashi Iwaid29697d2015-01-30 20:16:37 +01002302struct attribute *soc_dapm_dev_attrs[] = {
2303 &dev_attr_dapm_widget.attr,
2304 NULL
2305};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002306
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002307static void dapm_free_path(struct snd_soc_dapm_path *path)
2308{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002309 list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
2310 list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002311 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002312 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002313 kfree(path);
2314}
2315
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002316void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2317{
2318 struct snd_soc_dapm_path *p, *next_p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002319 enum snd_soc_dapm_direction dir;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002320
2321 list_del(&w->list);
2322 /*
2323 * remove source and sink paths associated to this widget.
2324 * While removing the path, remove reference to it from both
2325 * source and sink widgets so that path is removed only once.
2326 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002327 snd_soc_dapm_for_each_direction(dir) {
2328 snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
2329 dapm_free_path(p);
2330 }
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002331
2332 kfree(w->kcontrols);
Lars-Peter Clausen48068962015-07-21 18:11:08 +02002333 kfree_const(w->name);
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002334 kfree(w);
2335}
2336
Jyri Sarhafd589a12015-11-10 18:12:42 +02002337void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
2338{
2339 dapm->path_sink_cache.widget = NULL;
2340 dapm->path_source_cache.widget = NULL;
2341}
2342
Richard Purdie2b97eab2006-10-06 18:32:18 +02002343/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002344static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002345{
2346 struct snd_soc_dapm_widget *w, *next_w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002347
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002348 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2349 if (w->dapm != dapm)
2350 continue;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002351 snd_soc_dapm_free_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002352 }
Jyri Sarhafd589a12015-11-10 18:12:42 +02002353 snd_soc_dapm_reset_cache(dapm);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002354}
2355
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002356static struct snd_soc_dapm_widget *dapm_find_widget(
2357 struct snd_soc_dapm_context *dapm, const char *pin,
2358 bool search_other_contexts)
2359{
2360 struct snd_soc_dapm_widget *w;
2361 struct snd_soc_dapm_widget *fallback = NULL;
2362
2363 list_for_each_entry(w, &dapm->card->widgets, list) {
2364 if (!strcmp(w->name, pin)) {
2365 if (w->dapm == dapm)
2366 return w;
2367 else
2368 fallback = w;
2369 }
2370 }
2371
2372 if (search_other_contexts)
2373 return fallback;
2374
2375 return NULL;
2376}
2377
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002378static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002379 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002380{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002381 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002382
Mark Brownf9fa2b12014-03-06 16:49:11 +08002383 dapm_assert_locked(dapm);
2384
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002385 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002386 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002387 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002388 }
2389
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002390 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002391 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002392 dapm_widget_invalidate_input_paths(w);
2393 dapm_widget_invalidate_output_paths(w);
2394 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002395
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002396 w->connected = status;
2397 if (status == 0)
2398 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002399
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002400 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002401}
2402
Richard Purdie2b97eab2006-10-06 18:32:18 +02002403/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002404 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2405 * @dapm: DAPM context
2406 *
2407 * Walks all dapm audio paths and powers widgets according to their
2408 * stream or path usage.
2409 *
2410 * Requires external locking.
2411 *
2412 * Returns 0 for success.
2413 */
2414int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2415{
2416 /*
2417 * Suppress early reports (eg, jacks syncing their state) to avoid
2418 * silly DAPM runs during card startup.
2419 */
2420 if (!dapm->card || !dapm->card->instantiated)
2421 return 0;
2422
2423 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2424}
2425EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2426
2427/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002428 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002429 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002430 *
2431 * Walks all dapm audio paths and powers widgets according to their
2432 * stream or path usage.
2433 *
2434 * Returns 0 for success.
2435 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002436int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002437{
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002438 int ret;
2439
Liam Girdwood3cd04342012-03-09 12:02:08 +00002440 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002441 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002442 mutex_unlock(&dapm->card->dapm_mutex);
2443 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002444}
Liam Girdwooda5302182008-07-07 13:35:17 +01002445EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002446
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002447/*
2448 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2449 * @w: The widget for which to update the flags
2450 *
2451 * Some widgets have a dynamic category which depends on which neighbors they
2452 * are connected to. This function update the category for these widgets.
2453 *
2454 * This function must be called whenever a path is added or removed to a widget.
2455 */
2456static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2457{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002458 enum snd_soc_dapm_direction dir;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002459 struct snd_soc_dapm_path *p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002460 unsigned int ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002461
2462 switch (w->id) {
2463 case snd_soc_dapm_input:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002464 /* On a fully routed card a input is never a source */
2465 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002466 return;
2467 ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002468 snd_soc_dapm_widget_for_each_source_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002469 if (p->source->id == snd_soc_dapm_micbias ||
2470 p->source->id == snd_soc_dapm_mic ||
2471 p->source->id == snd_soc_dapm_line ||
2472 p->source->id == snd_soc_dapm_output) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002473 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002474 break;
2475 }
2476 }
2477 break;
2478 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002479 /* On a fully routed card a output is never a sink */
2480 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002481 return;
2482 ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002483 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002484 if (p->sink->id == snd_soc_dapm_spk ||
2485 p->sink->id == snd_soc_dapm_hp ||
2486 p->sink->id == snd_soc_dapm_line ||
2487 p->sink->id == snd_soc_dapm_input) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002488 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002489 break;
2490 }
2491 }
2492 break;
2493 case snd_soc_dapm_line:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002494 ep = 0;
2495 snd_soc_dapm_for_each_direction(dir) {
2496 if (!list_empty(&w->edges[dir]))
2497 ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
2498 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002499 break;
2500 default:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002501 return;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002502 }
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002503
2504 w->is_ep = ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002505}
2506
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002507static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2508 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2509 const char *control)
2510{
2511 bool dynamic_source = false;
2512 bool dynamic_sink = false;
2513
2514 if (!control)
2515 return 0;
2516
2517 switch (source->id) {
2518 case snd_soc_dapm_demux:
2519 dynamic_source = true;
2520 break;
2521 default:
2522 break;
2523 }
2524
2525 switch (sink->id) {
2526 case snd_soc_dapm_mux:
2527 case snd_soc_dapm_switch:
2528 case snd_soc_dapm_mixer:
2529 case snd_soc_dapm_mixer_named_ctl:
2530 dynamic_sink = true;
2531 break;
2532 default:
2533 break;
2534 }
2535
2536 if (dynamic_source && dynamic_sink) {
2537 dev_err(dapm->dev,
2538 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2539 source->name, control, sink->name);
2540 return -EINVAL;
2541 } else if (!dynamic_source && !dynamic_sink) {
2542 dev_err(dapm->dev,
2543 "Control not supported for path %s -> [%s] -> %s\n",
2544 source->name, control, sink->name);
2545 return -EINVAL;
2546 }
2547
2548 return 0;
2549}
2550
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002551static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2552 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2553 const char *control,
2554 int (*connected)(struct snd_soc_dapm_widget *source,
2555 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002556{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002557 struct snd_soc_dapm_widget *widgets[2];
2558 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002559 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002560 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002561
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002562 if (wsink->is_supply && !wsource->is_supply) {
2563 dev_err(dapm->dev,
2564 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2565 wsource->name, wsink->name);
2566 return -EINVAL;
2567 }
2568
2569 if (connected && !wsource->is_supply) {
2570 dev_err(dapm->dev,
2571 "connected() callback only supported for supply widgets (%s -> %s)\n",
2572 wsource->name, wsink->name);
2573 return -EINVAL;
2574 }
2575
2576 if (wsource->is_supply && control) {
2577 dev_err(dapm->dev,
2578 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2579 wsource->name, control, wsink->name);
2580 return -EINVAL;
2581 }
2582
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002583 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2584 if (ret)
2585 return ret;
2586
Richard Purdie2b97eab2006-10-06 18:32:18 +02002587 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2588 if (!path)
2589 return -ENOMEM;
2590
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002591 path->node[SND_SOC_DAPM_DIR_IN] = wsource;
2592 path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
2593 widgets[SND_SOC_DAPM_DIR_IN] = wsource;
2594 widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
2595
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002596 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002597 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002598 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002599
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002600 if (wsource->is_supply || wsink->is_supply)
2601 path->is_supply = 1;
2602
Richard Purdie2b97eab2006-10-06 18:32:18 +02002603 /* connect static paths */
2604 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002605 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002606 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002607 switch (wsource->id) {
2608 case snd_soc_dapm_demux:
2609 ret = dapm_connect_mux(dapm, path, control, wsource);
2610 if (ret)
2611 goto err;
2612 break;
2613 default:
2614 break;
2615 }
2616
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002617 switch (wsink->id) {
2618 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002619 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002620 if (ret != 0)
2621 goto err;
2622 break;
2623 case snd_soc_dapm_switch:
2624 case snd_soc_dapm_mixer:
2625 case snd_soc_dapm_mixer_named_ctl:
2626 ret = dapm_connect_mixer(dapm, path, control);
2627 if (ret != 0)
2628 goto err;
2629 break;
2630 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002631 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002632 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002633 }
2634
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002635 list_add(&path->list, &dapm->card->paths);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002636 snd_soc_dapm_for_each_direction(dir)
2637 list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002638
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002639 snd_soc_dapm_for_each_direction(dir) {
2640 dapm_update_widget_flags(widgets[dir]);
2641 dapm_mark_dirty(widgets[dir], "Route added");
2642 }
Mark Brownfabd0382012-07-05 17:20:06 +01002643
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002644 if (dapm->card->instantiated && path->connect)
2645 dapm_path_invalidate(path);
2646
Richard Purdie2b97eab2006-10-06 18:32:18 +02002647 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002648err:
2649 kfree(path);
2650 return ret;
2651}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002652
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002653static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002654 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002655{
2656 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2657 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2658 const char *sink;
2659 const char *source;
2660 char prefixed_sink[80];
2661 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002662 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002663 int ret;
2664
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002665 prefix = soc_dapm_prefix(dapm);
2666 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002667 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002668 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002669 sink = prefixed_sink;
2670 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002671 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002672 source = prefixed_source;
2673 } else {
2674 sink = route->sink;
2675 source = route->source;
2676 }
2677
Charles Keepax45a110a2015-05-11 13:50:30 +01002678 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2679 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2680
2681 if (wsink && wsource)
2682 goto skip_search;
2683
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002684 /*
2685 * find src and dest widgets over all widgets but favor a widget from
2686 * current DAPM context
2687 */
2688 list_for_each_entry(w, &dapm->card->widgets, list) {
2689 if (!wsink && !(strcmp(w->name, sink))) {
2690 wtsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002691 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002692 wsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002693 if (wsource)
2694 break;
2695 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002696 continue;
2697 }
2698 if (!wsource && !(strcmp(w->name, source))) {
2699 wtsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002700 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002701 wsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002702 if (wsink)
2703 break;
2704 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002705 }
2706 }
2707 /* use widget from another DAPM context if not found from this */
2708 if (!wsink)
2709 wsink = wtsink;
2710 if (!wsource)
2711 wsource = wtsource;
2712
2713 if (wsource == NULL) {
2714 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2715 route->source);
2716 return -ENODEV;
2717 }
2718 if (wsink == NULL) {
2719 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2720 route->sink);
2721 return -ENODEV;
2722 }
2723
Charles Keepax45a110a2015-05-11 13:50:30 +01002724skip_search:
2725 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2726 dapm_wcache_update(&dapm->path_source_cache, wsource);
2727
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002728 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2729 route->connected);
2730 if (ret)
2731 goto err;
2732
2733 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002734err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002735 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002736 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002737 return ret;
2738}
Mark Brown105f1c22008-05-13 14:52:19 +02002739
Mark Brownefcc3c62012-07-05 17:24:19 +01002740static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2741 const struct snd_soc_dapm_route *route)
2742{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002743 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002744 struct snd_soc_dapm_path *path, *p;
2745 const char *sink;
2746 const char *source;
2747 char prefixed_sink[80];
2748 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002749 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002750
2751 if (route->control) {
2752 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002753 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002754 return -EINVAL;
2755 }
2756
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002757 prefix = soc_dapm_prefix(dapm);
2758 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002759 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002760 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002761 sink = prefixed_sink;
2762 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002763 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002764 source = prefixed_source;
2765 } else {
2766 sink = route->sink;
2767 source = route->source;
2768 }
2769
2770 path = NULL;
2771 list_for_each_entry(p, &dapm->card->paths, list) {
2772 if (strcmp(p->source->name, source) != 0)
2773 continue;
2774 if (strcmp(p->sink->name, sink) != 0)
2775 continue;
2776 path = p;
2777 break;
2778 }
2779
2780 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002781 wsource = path->source;
2782 wsink = path->sink;
2783
2784 dapm_mark_dirty(wsource, "Route removed");
2785 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002786 if (path->connect)
2787 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002788
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002789 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002790
2791 /* Update any path related flags */
2792 dapm_update_widget_flags(wsource);
2793 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002794 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002795 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002796 source, sink);
2797 }
2798
2799 return 0;
2800}
2801
Mark Brown105f1c22008-05-13 14:52:19 +02002802/**
Mark Brown105f1c22008-05-13 14:52:19 +02002803 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002804 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002805 * @route: audio routes
2806 * @num: number of routes
2807 *
2808 * Connects 2 dapm widgets together via a named audio path. The sink is
2809 * the widget receiving the audio signal, whilst the source is the sender
2810 * of the audio signal.
2811 *
2812 * Returns 0 for success else error. On error all resources can be freed
2813 * with a call to snd_soc_card_free().
2814 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002815int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002816 const struct snd_soc_dapm_route *route, int num)
2817{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002818 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002819
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002820 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002821 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002822 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002823 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002824 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2825 route->source,
2826 route->control ? route->control : "direct",
2827 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002828 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002829 }
2830 route++;
2831 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002832 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002833
Dan Carpenter60884c22012-04-13 22:25:43 +03002834 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002835}
2836EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2837
Mark Brownefcc3c62012-07-05 17:24:19 +01002838/**
2839 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2840 * @dapm: DAPM context
2841 * @route: audio routes
2842 * @num: number of routes
2843 *
2844 * Removes routes from the DAPM context.
2845 */
2846int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2847 const struct snd_soc_dapm_route *route, int num)
2848{
Rajan Vajae066ea22016-02-11 11:23:35 +05302849 int i;
Mark Brownefcc3c62012-07-05 17:24:19 +01002850
2851 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2852 for (i = 0; i < num; i++) {
2853 snd_soc_dapm_del_route(dapm, route);
2854 route++;
2855 }
2856 mutex_unlock(&dapm->card->dapm_mutex);
2857
Rajan Vajae066ea22016-02-11 11:23:35 +05302858 return 0;
Mark Brownefcc3c62012-07-05 17:24:19 +01002859}
2860EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2861
Mark Brownbf3a9e12011-06-13 16:42:29 +01002862static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2863 const struct snd_soc_dapm_route *route)
2864{
2865 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2866 route->source,
2867 true);
2868 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2869 route->sink,
2870 true);
2871 struct snd_soc_dapm_path *path;
2872 int count = 0;
2873
2874 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002875 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002876 route->source);
2877 return -ENODEV;
2878 }
2879
2880 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002881 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002882 route->sink);
2883 return -ENODEV;
2884 }
2885
2886 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002887 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002888 route->source, route->sink);
2889
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002890 snd_soc_dapm_widget_for_each_sink_path(source, path) {
Mark Brownbf3a9e12011-06-13 16:42:29 +01002891 if (path->sink == sink) {
2892 path->weak = 1;
2893 count++;
2894 }
2895 }
2896
2897 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002898 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002899 route->source, route->sink);
2900 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002901 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002902 count, route->source, route->sink);
2903
2904 return 0;
2905}
2906
2907/**
2908 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2909 * @dapm: DAPM context
2910 * @route: audio routes
2911 * @num: number of routes
2912 *
2913 * Mark existing routes matching those specified in the passed array
2914 * as being weak, meaning that they are ignored for the purpose of
2915 * power decisions. The main intended use case is for sidetone paths
2916 * which couple audio between other independent paths if they are both
2917 * active in order to make the combination work better at the user
2918 * level but which aren't intended to be "used".
2919 *
2920 * Note that CODEC drivers should not use this as sidetone type paths
2921 * can frequently also be used as bypass paths.
2922 */
2923int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2924 const struct snd_soc_dapm_route *route, int num)
2925{
2926 int i, err;
2927 int ret = 0;
2928
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002929 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002930 for (i = 0; i < num; i++) {
2931 err = snd_soc_dapm_weak_route(dapm, route);
2932 if (err)
2933 ret = err;
2934 route++;
2935 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002936 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002937
2938 return ret;
2939}
2940EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2941
Mark Brown105f1c22008-05-13 14:52:19 +02002942/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002943 * snd_soc_dapm_new_widgets - add new dapm widgets
Jonathan Corbet628536e2015-08-25 01:14:48 -06002944 * @card: card to be checked for new dapm widgets
Richard Purdie2b97eab2006-10-06 18:32:18 +02002945 *
2946 * Checks the codec for any new dapm widgets and creates them if found.
2947 *
2948 * Returns 0 for success.
2949 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02002950int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002951{
2952 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002953 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002954
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002955 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002956
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002957 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002958 {
2959 if (w->new)
2960 continue;
2961
Stephen Warrenfad59882011-04-28 17:37:59 -06002962 if (w->num_kcontrols) {
2963 w->kcontrols = kzalloc(w->num_kcontrols *
2964 sizeof(struct snd_kcontrol *),
2965 GFP_KERNEL);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002966 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002967 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002968 return -ENOMEM;
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002969 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002970 }
2971
Richard Purdie2b97eab2006-10-06 18:32:18 +02002972 switch(w->id) {
2973 case snd_soc_dapm_switch:
2974 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002975 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002976 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002977 break;
2978 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002979 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002980 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002981 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002982 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002983 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002984 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002985 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00002986 case snd_soc_dapm_dai_link:
2987 dapm_new_dai_link(w);
2988 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002989 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002990 break;
2991 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002992
2993 /* Read the initial power state from the device */
2994 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002995 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08002996 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002997 val &= w->mask;
2998 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00002999 w->power = 1;
3000 }
3001
Richard Purdie2b97eab2006-10-06 18:32:18 +02003002 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003003
Mark Brown7508b122011-10-05 12:09:12 +01003004 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003005 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003006 }
3007
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003008 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
3009 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003010 return 0;
3011}
3012EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
3013
3014/**
3015 * snd_soc_dapm_get_volsw - dapm mixer get callback
3016 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003017 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003018 *
3019 * Callback to get the value of a dapm mixer control.
3020 *
3021 * Returns 0 for success.
3022 */
3023int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
3024 struct snd_ctl_elem_value *ucontrol)
3025{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003026 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3027 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003028 struct soc_mixer_control *mc =
3029 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003030 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003031 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003032 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003033 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003034 unsigned int invert = mc->invert;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003035 unsigned int val;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003036 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003037
3038 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003039 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003040 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003041 kcontrol->id.name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003042
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003043 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003044 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
3045 ret = soc_dapm_read(dapm, reg, &val);
3046 val = (val >> shift) & mask;
3047 } else {
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003048 val = dapm_kcontrol_get_value(kcontrol);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003049 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003050 mutex_unlock(&card->dapm_mutex);
3051
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003052 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003053 ucontrol->value.integer.value[0] = max - val;
3054 else
3055 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003056
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003057 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003058}
3059EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3060
3061/**
3062 * snd_soc_dapm_put_volsw - dapm mixer set callback
3063 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003064 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003065 *
3066 * Callback to set the value of a dapm mixer control.
3067 *
3068 * Returns 0 for success.
3069 */
3070int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3071 struct snd_ctl_elem_value *ucontrol)
3072{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003073 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3074 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003075 struct soc_mixer_control *mc =
3076 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003077 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003078 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003079 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003080 unsigned int mask = (1 << fls(max)) - 1;
3081 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07003082 unsigned int val;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003083 int connect, change, reg_change = 0;
Mark Brown97404f22010-12-14 16:13:57 +00003084 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003085 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003086
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003087 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003088 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003089 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003090 kcontrol->id.name);
3091
Richard Purdie2b97eab2006-10-06 18:32:18 +02003092 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003093 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003094
3095 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003096 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003097
Liam Girdwood3cd04342012-03-09 12:02:08 +00003098 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003099
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003100 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown283375c2009-12-07 18:09:03 +00003101
Jarkko Nikula18626c72014-06-09 14:20:29 +03003102 if (reg != SND_SOC_NOPM) {
3103 mask = mask << shift;
3104 val = val << shift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003105
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003106 reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003107 }
3108
3109 if (change || reg_change) {
3110 if (reg_change) {
3111 update.kcontrol = kcontrol;
3112 update.reg = reg;
3113 update.mask = mask;
3114 update.val = val;
3115 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003116 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003117 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003118
Nenghua Cao52765972013-12-13 20:13:49 +08003119 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Mark Brown97404f22010-12-14 16:13:57 +00003120
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003121 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003122 }
3123
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003124 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003125
3126 if (ret > 0)
3127 soc_dpcm_runtime_update(card);
3128
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003129 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003130}
3131EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3132
3133/**
3134 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3135 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003136 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003137 *
3138 * Callback to get the value of a dapm enumerated double mixer control.
3139 *
3140 * Returns 0 for success.
3141 */
3142int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3143 struct snd_ctl_elem_value *ucontrol)
3144{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003145 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003146 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003147 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003148 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003149
Charles Keepax561ed682015-05-01 12:37:26 +01003150 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3151 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003152 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003153 if (ret) {
3154 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003155 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003156 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003157 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003158 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003159 }
Charles Keepax561ed682015-05-01 12:37:26 +01003160 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003161
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003162 val = (reg_val >> e->shift_l) & e->mask;
3163 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3164 if (e->shift_l != e->shift_r) {
3165 val = (reg_val >> e->shift_r) & e->mask;
3166 val = snd_soc_enum_val_to_item(e, val);
3167 ucontrol->value.enumerated.item[1] = val;
3168 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003169
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003170 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003171}
3172EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3173
3174/**
3175 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3176 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003177 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003178 *
3179 * Callback to set the value of a dapm enumerated double mixer control.
3180 *
3181 * Returns 0 for success.
3182 */
3183int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3184 struct snd_ctl_elem_value *ucontrol)
3185{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003186 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3187 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003188 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003189 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003190 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003191 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00003192 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003193 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003194
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003195 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003196 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003197
3198 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003199 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003200 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003201 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003202 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003203 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003204 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003205 }
3206
Liam Girdwood3cd04342012-03-09 12:02:08 +00003207 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003208
Charles Keepax561ed682015-05-01 12:37:26 +01003209 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003210
Charles Keepax561ed682015-05-01 12:37:26 +01003211 if (e->reg != SND_SOC_NOPM)
3212 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3213
3214 if (change || reg_change) {
3215 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003216 update.kcontrol = kcontrol;
3217 update.reg = e->reg;
3218 update.mask = mask;
3219 update.val = val;
3220 card->update = &update;
3221 }
Charles Keepax561ed682015-05-01 12:37:26 +01003222 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003223
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003224 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003225
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003226 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003227 }
3228
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003229 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003230
3231 if (ret > 0)
3232 soc_dpcm_runtime_update(card);
3233
Mark Brown97404f22010-12-14 16:13:57 +00003234 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003235}
3236EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3237
3238/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003239 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3240 *
3241 * @kcontrol: mixer control
3242 * @uinfo: control element information
3243 *
3244 * Callback to provide information about a pin switch control.
3245 */
3246int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3247 struct snd_ctl_elem_info *uinfo)
3248{
3249 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3250 uinfo->count = 1;
3251 uinfo->value.integer.min = 0;
3252 uinfo->value.integer.max = 1;
3253
3254 return 0;
3255}
3256EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3257
3258/**
3259 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3260 *
3261 * @kcontrol: mixer control
3262 * @ucontrol: Value
3263 */
3264int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3265 struct snd_ctl_elem_value *ucontrol)
3266{
Mark Brown48a8c392012-02-14 17:11:15 -08003267 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003268 const char *pin = (const char *)kcontrol->private_value;
3269
Liam Girdwood3cd04342012-03-09 12:02:08 +00003270 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003271
3272 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003273 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003274
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003275 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003276
3277 return 0;
3278}
3279EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3280
3281/**
3282 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3283 *
3284 * @kcontrol: mixer control
3285 * @ucontrol: Value
3286 */
3287int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3288 struct snd_ctl_elem_value *ucontrol)
3289{
Mark Brown48a8c392012-02-14 17:11:15 -08003290 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003291 const char *pin = (const char *)kcontrol->private_value;
3292
Mark Brown8b37dbd2009-02-28 21:14:20 +00003293 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003294 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003295 else
Mark Brown48a8c392012-02-14 17:11:15 -08003296 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003297
Mark Brown48a8c392012-02-14 17:11:15 -08003298 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003299 return 0;
3300}
3301EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3302
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +01003303struct snd_soc_dapm_widget *
Mark Brown5ba06fc2012-02-16 11:07:13 -08003304snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003305 const struct snd_soc_dapm_widget *widget)
3306{
3307 struct snd_soc_dapm_widget *w;
3308
3309 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3310 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3311 if (!w)
3312 dev_err(dapm->dev,
3313 "ASoC: Failed to create DAPM control %s\n",
3314 widget->name);
3315
3316 mutex_unlock(&dapm->card->dapm_mutex);
3317 return w;
3318}
Subhransu S. Prustya5d56392016-06-27 09:18:03 +05303319EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003320
3321struct snd_soc_dapm_widget *
3322snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003323 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003324{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003325 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003326 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003327 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003328 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003329
3330 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003331 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003332
Mark Brown62ea8742012-01-21 21:14:48 +00003333 switch (w->id) {
3334 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003335 w->regulator = devm_regulator_get(dapm->dev, w->name);
3336 if (IS_ERR(w->regulator)) {
3337 ret = PTR_ERR(w->regulator);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003338 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003339 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003340 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003341 }
Mark Brown8784c772013-01-10 19:33:47 +00003342
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003343 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003344 ret = regulator_allow_bypass(w->regulator, true);
3345 if (ret != 0)
3346 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003347 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003348 w->name, ret);
3349 }
Mark Brown62ea8742012-01-21 21:14:48 +00003350 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003351 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003352#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003353 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003354 if (IS_ERR(w->clk)) {
3355 ret = PTR_ERR(w->clk);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003356 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003357 w->name, ret);
3358 return NULL;
3359 }
Mark Brownec029952012-06-04 08:16:20 +01003360#else
3361 return NULL;
3362#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003363 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003364 default:
3365 break;
3366 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003367
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003368 prefix = soc_dapm_prefix(dapm);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003369 if (prefix)
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003370 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003371 else
Lars-Peter Clausen48068962015-07-21 18:11:08 +02003372 w->name = kstrdup_const(widget->name, GFP_KERNEL);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003373 if (w->name == NULL) {
3374 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003375 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003376 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003377
Mark Brown7ca3a182011-10-08 14:04:50 +01003378 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003379 case snd_soc_dapm_mic:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003380 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003381 w->power_check = dapm_generic_check_power;
3382 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003383 case snd_soc_dapm_input:
3384 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003385 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003386 w->power_check = dapm_generic_check_power;
3387 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003388 case snd_soc_dapm_spk:
3389 case snd_soc_dapm_hp:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003390 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003391 w->power_check = dapm_generic_check_power;
3392 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003393 case snd_soc_dapm_output:
3394 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003395 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003396 w->power_check = dapm_generic_check_power;
3397 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003398 case snd_soc_dapm_vmid:
3399 case snd_soc_dapm_siggen:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003400 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003401 w->power_check = dapm_always_on_check_power;
3402 break;
Vinod Koul56b44372015-11-23 21:22:30 +05303403 case snd_soc_dapm_sink:
3404 w->is_ep = SND_SOC_DAPM_EP_SINK;
3405 w->power_check = dapm_always_on_check_power;
3406 break;
3407
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003408 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003409 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003410 case snd_soc_dapm_switch:
3411 case snd_soc_dapm_mixer:
3412 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003413 case snd_soc_dapm_adc:
3414 case snd_soc_dapm_aif_out:
3415 case snd_soc_dapm_dac:
3416 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003417 case snd_soc_dapm_pga:
3418 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003419 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003420 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003421 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003422 case snd_soc_dapm_dai_out:
3423 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003424 w->power_check = dapm_generic_check_power;
3425 break;
3426 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003427 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003428 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003429 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003430 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003431 w->power_check = dapm_supply_check_power;
3432 break;
3433 default:
3434 w->power_check = dapm_always_on_check_power;
3435 break;
3436 }
3437
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003438 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003439 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003440 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003441 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003442
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003443 snd_soc_dapm_for_each_direction(dir) {
3444 INIT_LIST_HEAD(&w->edges[dir]);
3445 w->endpoints[dir] = -1;
3446 }
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003447
Richard Purdie2b97eab2006-10-06 18:32:18 +02003448 /* machine layer set ups unconnected pins and insertions */
3449 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003450 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003451}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003452
3453/**
Mark Brown4ba13272008-05-13 14:51:19 +02003454 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003455 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003456 * @widget: widget array
3457 * @num: number of widgets
3458 *
3459 * Creates new DAPM controls based upon the templates.
3460 *
3461 * Returns 0 for success else error.
3462 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003463int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003464 const struct snd_soc_dapm_widget *widget,
3465 int num)
3466{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003467 struct snd_soc_dapm_widget *w;
3468 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003469 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003470
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003471 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003472 for (i = 0; i < num; i++) {
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003473 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003474 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003475 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003476 "ASoC: Failed to create DAPM control %s\n",
3477 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003478 ret = -ENOMEM;
3479 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003480 }
Mark Brown4ba13272008-05-13 14:51:19 +02003481 widget++;
3482 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003483 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003484 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003485}
3486EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3487
Mark Brownc74184e2012-04-04 22:12:09 +01003488static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3489 struct snd_kcontrol *kcontrol, int event)
3490{
3491 struct snd_soc_dapm_path *source_p, *sink_p;
3492 struct snd_soc_dai *source, *sink;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003493 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003494 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003495 struct snd_pcm_hw_params *params = NULL;
Nicolin Chen8053f212016-07-26 14:55:51 -07003496 struct snd_pcm_runtime *runtime = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003497 u64 fmt;
3498 int ret;
3499
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003500 if (WARN_ON(!config) ||
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003501 WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3502 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003503 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003504
3505 /* We only support a single source and sink, pick the first */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003506 source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
3507 struct snd_soc_dapm_path,
3508 list_node[SND_SOC_DAPM_DIR_OUT]);
3509 sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
3510 struct snd_soc_dapm_path,
3511 list_node[SND_SOC_DAPM_DIR_IN]);
Mark Brownc74184e2012-04-04 22:12:09 +01003512
3513 source = source_p->source->priv;
3514 sink = sink_p->sink->priv;
3515
3516 /* Be a little careful as we don't want to overflow the mask array */
3517 if (config->formats) {
3518 fmt = ffs(config->formats) - 1;
3519 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003520 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003521 config->formats);
3522 fmt = 0;
3523 }
3524
3525 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003526 params = kzalloc(sizeof(*params), GFP_KERNEL);
3527 if (!params) {
3528 ret = -ENOMEM;
3529 goto out;
3530 }
3531 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003532
Mark Brown9747cec2012-04-26 19:12:21 +01003533 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003534 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003535 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003536 config->rate_max;
3537
Mark Brown9747cec2012-04-26 19:12:21 +01003538 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003539 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003540 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003541 = config->channels_max;
3542
3543 memset(&substream, 0, sizeof(substream));
3544
Nicolin Chen8053f212016-07-26 14:55:51 -07003545 /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */
3546 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
3547 if (!runtime) {
3548 ret = -ENOMEM;
3549 goto out;
3550 }
3551 substream.runtime = runtime;
3552
Mark Brownc74184e2012-04-04 22:12:09 +01003553 switch (event) {
3554 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003555 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303556 if (source->driver->ops && source->driver->ops->startup) {
3557 ret = source->driver->ops->startup(&substream, source);
3558 if (ret < 0) {
3559 dev_err(source->dev,
3560 "ASoC: startup() failed: %d\n", ret);
3561 goto out;
3562 }
3563 source->active++;
3564 }
Benoit Cousson93e69582014-07-08 23:19:38 +02003565 ret = soc_dai_hw_params(&substream, params, source);
3566 if (ret < 0)
3567 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003568
Benoit Cousson93e69582014-07-08 23:19:38 +02003569 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303570 if (sink->driver->ops && sink->driver->ops->startup) {
3571 ret = sink->driver->ops->startup(&substream, sink);
3572 if (ret < 0) {
3573 dev_err(sink->dev,
3574 "ASoC: startup() failed: %d\n", ret);
3575 goto out;
3576 }
3577 sink->active++;
3578 }
Benoit Cousson93e69582014-07-08 23:19:38 +02003579 ret = soc_dai_hw_params(&substream, params, sink);
3580 if (ret < 0)
3581 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003582 break;
3583
3584 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003585 ret = snd_soc_dai_digital_mute(sink, 0,
3586 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003587 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003588 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003589 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003590 break;
3591
3592 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003593 ret = snd_soc_dai_digital_mute(sink, 1,
3594 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003595 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003596 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003597 ret = 0;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303598
3599 source->active--;
3600 if (source->driver->ops && source->driver->ops->shutdown) {
3601 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3602 source->driver->ops->shutdown(&substream, source);
3603 }
3604
3605 sink->active--;
3606 if (sink->driver->ops && sink->driver->ops->shutdown) {
3607 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3608 sink->driver->ops->shutdown(&substream, sink);
3609 }
Mark Brownc74184e2012-04-04 22:12:09 +01003610 break;
3611
3612 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003613 WARN(1, "Unknown event %d\n", event);
Sudip Mukherjee75881df2015-09-10 18:01:44 +05303614 ret = -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003615 }
3616
Mark Brown9747cec2012-04-26 19:12:21 +01003617out:
Nicolin Chen8053f212016-07-26 14:55:51 -07003618 kfree(runtime);
Mark Brown9747cec2012-04-26 19:12:21 +01003619 kfree(params);
3620 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003621}
3622
Nikesh Oswalc6615082015-02-02 17:06:44 +00003623static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3624 struct snd_ctl_elem_value *ucontrol)
3625{
3626 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3627
Takashi Iwai741338f2016-02-29 17:20:48 +01003628 ucontrol->value.enumerated.item[0] = w->params_select;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003629
3630 return 0;
3631}
3632
3633static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3634 struct snd_ctl_elem_value *ucontrol)
3635{
3636 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3637
3638 /* Can't change the config when widget is already powered */
3639 if (w->power)
3640 return -EBUSY;
3641
Takashi Iwai741338f2016-02-29 17:20:48 +01003642 if (ucontrol->value.enumerated.item[0] == w->params_select)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003643 return 0;
3644
Takashi Iwai741338f2016-02-29 17:20:48 +01003645 if (ucontrol->value.enumerated.item[0] >= w->num_params)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003646 return -EINVAL;
3647
Takashi Iwai741338f2016-02-29 17:20:48 +01003648 w->params_select = ucontrol->value.enumerated.item[0];
Nikesh Oswalc6615082015-02-02 17:06:44 +00003649
3650 return 0;
3651}
3652
Mark Brownc74184e2012-04-04 22:12:09 +01003653int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3654 const struct snd_soc_pcm_stream *params,
Nikesh Oswalc6615082015-02-02 17:06:44 +00003655 unsigned int num_params,
Mark Brownc74184e2012-04-04 22:12:09 +01003656 struct snd_soc_dapm_widget *source,
3657 struct snd_soc_dapm_widget *sink)
3658{
Mark Brownc74184e2012-04-04 22:12:09 +01003659 struct snd_soc_dapm_widget template;
3660 struct snd_soc_dapm_widget *w;
Mark Brownc74184e2012-04-04 22:12:09 +01003661 char *link_name;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003662 int ret, count;
3663 unsigned long private_value;
3664 const char **w_param_text;
3665 struct soc_enum w_param_enum[] = {
3666 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3667 };
3668 struct snd_kcontrol_new kcontrol_dai_link[] = {
3669 SOC_ENUM_EXT(NULL, w_param_enum[0],
3670 snd_soc_dapm_dai_link_get,
3671 snd_soc_dapm_dai_link_put),
3672 };
3673 const struct snd_soc_pcm_stream *config = params;
Mark Brownc74184e2012-04-04 22:12:09 +01003674
Nikesh Oswalc6615082015-02-02 17:06:44 +00003675 w_param_text = devm_kcalloc(card->dev, num_params,
3676 sizeof(char *), GFP_KERNEL);
3677 if (!w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003678 return -ENOMEM;
Mark Brownc74184e2012-04-04 22:12:09 +01003679
Charles Keepax46172b62015-03-25 11:22:35 +00003680 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3681 source->name, sink->name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003682 if (!link_name) {
3683 ret = -ENOMEM;
3684 goto outfree_w_param;
3685 }
Mark Brownc74184e2012-04-04 22:12:09 +01003686
Nikesh Oswalc6615082015-02-02 17:06:44 +00003687 for (count = 0 ; count < num_params; count++) {
3688 if (!config->stream_name) {
3689 dev_warn(card->dapm.dev,
3690 "ASoC: anonymous config %d for dai link %s\n",
3691 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003692 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003693 devm_kasprintf(card->dev, GFP_KERNEL,
3694 "Anonymous Configuration %d",
3695 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003696 if (!w_param_text[count]) {
3697 ret = -ENOMEM;
3698 goto outfree_link_name;
3699 }
Nikesh Oswalc6615082015-02-02 17:06:44 +00003700 } else {
3701 w_param_text[count] = devm_kmemdup(card->dev,
3702 config->stream_name,
3703 strlen(config->stream_name) + 1,
3704 GFP_KERNEL);
3705 if (!w_param_text[count]) {
3706 ret = -ENOMEM;
3707 goto outfree_link_name;
3708 }
3709 }
3710 config++;
3711 }
3712 w_param_enum[0].items = num_params;
3713 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003714
3715 memset(&template, 0, sizeof(template));
3716 template.reg = SND_SOC_NOPM;
3717 template.id = snd_soc_dapm_dai_link;
3718 template.name = link_name;
3719 template.event = snd_soc_dai_link_event;
3720 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3721 SND_SOC_DAPM_PRE_PMD;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003722 template.num_kcontrols = 1;
3723 /* duplicate w_param_enum on heap so that memory persists */
3724 private_value =
3725 (unsigned long) devm_kmemdup(card->dev,
3726 (void *)(kcontrol_dai_link[0].private_value),
3727 sizeof(struct soc_enum), GFP_KERNEL);
3728 if (!private_value) {
3729 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3730 link_name);
3731 ret = -ENOMEM;
3732 goto outfree_link_name;
3733 }
3734 kcontrol_dai_link[0].private_value = private_value;
3735 /* duplicate kcontrol_dai_link on heap so that memory persists */
3736 template.kcontrol_news =
3737 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3738 sizeof(struct snd_kcontrol_new),
3739 GFP_KERNEL);
3740 if (!template.kcontrol_news) {
3741 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3742 link_name);
3743 ret = -ENOMEM;
3744 goto outfree_private_value;
3745 }
Mark Brownc74184e2012-04-04 22:12:09 +01003746
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003747 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003748
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003749 w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
Mark Brownc74184e2012-04-04 22:12:09 +01003750 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003751 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003752 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003753 ret = -ENOMEM;
3754 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003755 }
3756
3757 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003758 w->num_params = num_params;
Mark Brownc74184e2012-04-04 22:12:09 +01003759
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003760 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3761 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003762 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003763 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003764
3765outfree_w:
3766 devm_kfree(card->dev, w);
3767outfree_kcontrol_news:
3768 devm_kfree(card->dev, (void *)template.kcontrol_news);
3769outfree_private_value:
3770 devm_kfree(card->dev, (void *)private_value);
3771outfree_link_name:
3772 devm_kfree(card->dev, link_name);
3773outfree_w_param:
3774 for (count = 0 ; count < num_params; count++)
3775 devm_kfree(card->dev, (void *)w_param_text[count]);
3776 devm_kfree(card->dev, w_param_text);
3777
3778 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003779}
3780
Mark Brown888df392012-02-16 19:37:51 -08003781int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3782 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003783{
Mark Brown888df392012-02-16 19:37:51 -08003784 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003785 struct snd_soc_dapm_widget *w;
3786
Mark Brown888df392012-02-16 19:37:51 -08003787 WARN_ON(dapm->dev != dai->dev);
3788
3789 memset(&template, 0, sizeof(template));
3790 template.reg = SND_SOC_NOPM;
3791
3792 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003793 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003794 template.name = dai->driver->playback.stream_name;
3795 template.sname = dai->driver->playback.stream_name;
3796
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003797 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003798 template.name);
3799
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003800 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Mark Brown888df392012-02-16 19:37:51 -08003801 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003802 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003803 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003804 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003805 }
3806
3807 w->priv = dai;
3808 dai->playback_widget = w;
3809 }
3810
3811 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003812 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003813 template.name = dai->driver->capture.stream_name;
3814 template.sname = dai->driver->capture.stream_name;
3815
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003816 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003817 template.name);
3818
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003819 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Mark Brown888df392012-02-16 19:37:51 -08003820 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003821 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003822 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003823 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003824 }
3825
3826 w->priv = dai;
3827 dai->capture_widget = w;
3828 }
3829
3830 return 0;
3831}
3832
3833int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3834{
3835 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003836 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08003837 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003838
3839 /* For each DAI widget... */
3840 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003841 switch (dai_w->id) {
3842 case snd_soc_dapm_dai_in:
3843 case snd_soc_dapm_dai_out:
3844 break;
3845 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003846 continue;
Mark Brown46162742013-06-05 19:36:11 +01003847 }
Mark Brown888df392012-02-16 19:37:51 -08003848
3849 dai = dai_w->priv;
3850
3851 /* ...find all widgets with the same stream and link them */
3852 list_for_each_entry(w, &card->widgets, list) {
3853 if (w->dapm != dai_w->dapm)
3854 continue;
3855
Mark Brown46162742013-06-05 19:36:11 +01003856 switch (w->id) {
3857 case snd_soc_dapm_dai_in:
3858 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08003859 continue;
Mark Brown46162742013-06-05 19:36:11 +01003860 default:
3861 break;
3862 }
Mark Brown888df392012-02-16 19:37:51 -08003863
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003864 if (!w->sname || !strstr(w->sname, dai_w->sname))
Mark Brown888df392012-02-16 19:37:51 -08003865 continue;
3866
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003867 if (dai_w->id == snd_soc_dapm_dai_in) {
3868 src = dai_w;
3869 sink = w;
3870 } else {
3871 src = w;
3872 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08003873 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003874 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
3875 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003876 }
3877 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003878
Mark Brown888df392012-02-16 19:37:51 -08003879 return 0;
3880}
Liam Girdwood64a648c2011-07-25 11:15:15 +01003881
Benoit Cousson44ba2642014-07-08 23:19:36 +02003882static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
3883 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003884{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003885 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003886 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003887 int i;
3888
Benoit Cousson44ba2642014-07-08 23:19:36 +02003889 for (i = 0; i < rtd->num_codecs; i++) {
3890 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003891
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003892 /* connect BE DAI playback if widgets are valid */
3893 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003894 source = cpu_dai->playback_widget;
3895 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003896 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003897 cpu_dai->component->name, source->name,
3898 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003899
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003900 snd_soc_dapm_add_path(&card->dapm, source, sink,
3901 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003902 }
3903
3904 /* connect BE DAI capture if widgets are valid */
3905 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003906 source = codec_dai->capture_widget;
3907 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003908 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003909 codec_dai->component->name, source->name,
3910 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003911
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003912 snd_soc_dapm_add_path(&card->dapm, source, sink,
3913 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003914 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003915 }
3916}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003917
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003918static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3919 int event)
3920{
3921 struct snd_soc_dapm_widget *w;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003922 unsigned int ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003923
3924 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3925 w = dai->playback_widget;
3926 else
3927 w = dai->capture_widget;
3928
3929 if (w) {
3930 dapm_mark_dirty(w, "stream event");
3931
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003932 if (w->id == snd_soc_dapm_dai_in) {
3933 ep = SND_SOC_DAPM_EP_SOURCE;
3934 dapm_widget_invalidate_input_paths(w);
3935 } else {
3936 ep = SND_SOC_DAPM_EP_SINK;
3937 dapm_widget_invalidate_output_paths(w);
3938 }
3939
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003940 switch (event) {
3941 case SND_SOC_DAPM_STREAM_START:
3942 w->active = 1;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003943 w->is_ep = ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003944 break;
3945 case SND_SOC_DAPM_STREAM_STOP:
3946 w->active = 0;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003947 w->is_ep = 0;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003948 break;
3949 case SND_SOC_DAPM_STREAM_SUSPEND:
3950 case SND_SOC_DAPM_STREAM_RESUME:
3951 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3952 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3953 break;
3954 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003955 }
3956}
3957
Benoit Cousson44ba2642014-07-08 23:19:36 +02003958void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3959{
Mengdong Lin1a497982015-11-18 02:34:11 -05003960 struct snd_soc_pcm_runtime *rtd;
Benoit Cousson44ba2642014-07-08 23:19:36 +02003961
3962 /* for each BE DAI link... */
Mengdong Lin1a497982015-11-18 02:34:11 -05003963 list_for_each_entry(rtd, &card->rtd_list, list) {
Benoit Cousson44ba2642014-07-08 23:19:36 +02003964 /*
3965 * dynamic FE links have no fixed DAI mapping.
3966 * CODEC<->CODEC links have no direct connection.
3967 */
3968 if (rtd->dai_link->dynamic || rtd->dai_link->params)
3969 continue;
3970
3971 dapm_connect_dai_link_widgets(card, rtd);
3972 }
3973}
3974
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003975static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3976 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003977{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003978 int i;
3979
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003980 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02003981 for (i = 0; i < rtd->num_codecs; i++)
3982 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003983
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003984 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003985}
3986
3987/**
3988 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3989 * @rtd: PCM runtime data
3990 * @stream: stream name
3991 * @event: stream event
3992 *
3993 * Sends a stream event to the dapm core. The core then makes any
3994 * necessary widget power changes.
3995 *
3996 * Returns 0 for success else error.
3997 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003998void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3999 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004000{
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00004001 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004002
Liam Girdwood3cd04342012-03-09 12:02:08 +00004003 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004004 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00004005 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004006}
Richard Purdie2b97eab2006-10-06 18:32:18 +02004007
4008/**
Charles Keepax11391102014-02-18 15:22:14 +00004009 * snd_soc_dapm_enable_pin_unlocked - enable pin.
4010 * @dapm: DAPM context
4011 * @pin: pin name
4012 *
4013 * Enables input/output pin and its parents or children widgets iff there is
4014 * a valid audio route and active audio stream.
4015 *
4016 * Requires external locking.
4017 *
4018 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4019 * do any widget power switching.
4020 */
4021int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4022 const char *pin)
4023{
4024 return snd_soc_dapm_set_pin(dapm, pin, 1);
4025}
4026EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
4027
4028/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004029 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004030 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004031 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02004032 *
Mark Brown74b8f952009-06-06 11:26:15 +01004033 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01004034 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00004035 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004036 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4037 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02004038 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004039int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004040{
Charles Keepax11391102014-02-18 15:22:14 +00004041 int ret;
4042
4043 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4044
4045 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
4046
4047 mutex_unlock(&dapm->card->dapm_mutex);
4048
4049 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02004050}
Liam Girdwooda5302182008-07-07 13:35:17 +01004051EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004052
4053/**
Charles Keepax11391102014-02-18 15:22:14 +00004054 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
4055 * @dapm: DAPM context
4056 * @pin: pin name
4057 *
4058 * Enables input/output pin regardless of any other state. This is
4059 * intended for use with microphone bias supplies used in microphone
4060 * jack detection.
4061 *
4062 * Requires external locking.
4063 *
4064 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4065 * do any widget power switching.
4066 */
4067int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4068 const char *pin)
4069{
4070 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4071
4072 if (!w) {
4073 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4074 return -EINVAL;
4075 }
4076
4077 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02004078 if (!w->connected) {
4079 /*
4080 * w->force does not affect the number of input or output paths,
4081 * so we only have to recheck if w->connected is changed
4082 */
4083 dapm_widget_invalidate_input_paths(w);
4084 dapm_widget_invalidate_output_paths(w);
4085 w->connected = 1;
4086 }
Charles Keepax11391102014-02-18 15:22:14 +00004087 w->force = 1;
4088 dapm_mark_dirty(w, "force enable");
4089
4090 return 0;
4091}
4092EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4093
4094/**
Mark Brownda341832010-03-15 19:23:37 +00004095 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004096 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00004097 * @pin: pin name
4098 *
4099 * Enables input/output pin regardless of any other state. This is
4100 * intended for use with microphone bias supplies used in microphone
4101 * jack detection.
4102 *
4103 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4104 * do any widget power switching.
4105 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004106int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4107 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00004108{
Charles Keepax11391102014-02-18 15:22:14 +00004109 int ret;
Mark Brownda341832010-03-15 19:23:37 +00004110
Charles Keepax11391102014-02-18 15:22:14 +00004111 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00004112
Charles Keepax11391102014-02-18 15:22:14 +00004113 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09004114
Charles Keepax11391102014-02-18 15:22:14 +00004115 mutex_unlock(&dapm->card->dapm_mutex);
4116
4117 return ret;
Mark Brownda341832010-03-15 19:23:37 +00004118}
4119EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4120
4121/**
Charles Keepax11391102014-02-18 15:22:14 +00004122 * snd_soc_dapm_disable_pin_unlocked - disable pin.
4123 * @dapm: DAPM context
4124 * @pin: pin name
4125 *
4126 * Disables input/output pin and its parents or children widgets.
4127 *
4128 * Requires external locking.
4129 *
4130 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4131 * do any widget power switching.
4132 */
4133int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4134 const char *pin)
4135{
4136 return snd_soc_dapm_set_pin(dapm, pin, 0);
4137}
4138EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4139
4140/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004141 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004142 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004143 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004144 *
Mark Brown74b8f952009-06-06 11:26:15 +01004145 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004146 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004147 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4148 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004149 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004150int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4151 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004152{
Charles Keepax11391102014-02-18 15:22:14 +00004153 int ret;
4154
4155 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4156
4157 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4158
4159 mutex_unlock(&dapm->card->dapm_mutex);
4160
4161 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004162}
4163EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4164
4165/**
Charles Keepax11391102014-02-18 15:22:14 +00004166 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4167 * @dapm: DAPM context
4168 * @pin: pin name
4169 *
4170 * Marks the specified pin as being not connected, disabling it along
4171 * any parent or child widgets. At present this is identical to
4172 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4173 * additional things such as disabling controls which only affect
4174 * paths through the pin.
4175 *
4176 * Requires external locking.
4177 *
4178 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4179 * do any widget power switching.
4180 */
4181int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4182 const char *pin)
4183{
4184 return snd_soc_dapm_set_pin(dapm, pin, 0);
4185}
4186EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4187
4188/**
Mark Brown5817b522008-09-24 11:23:11 +01004189 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004190 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004191 * @pin: pin name
4192 *
4193 * Marks the specified pin as being not connected, disabling it along
4194 * any parent or child widgets. At present this is identical to
4195 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4196 * additional things such as disabling controls which only affect
4197 * paths through the pin.
4198 *
4199 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4200 * do any widget power switching.
4201 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004202int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004203{
Charles Keepax11391102014-02-18 15:22:14 +00004204 int ret;
4205
4206 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4207
4208 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4209
4210 mutex_unlock(&dapm->card->dapm_mutex);
4211
4212 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004213}
4214EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4215
4216/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004217 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004218 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004219 * @pin: audio signal pin endpoint (or start point)
4220 *
4221 * Get audio pin status - connected or disconnected.
4222 *
4223 * Returns 1 for connected otherwise 0.
4224 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004225int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4226 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004227{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004228 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004229
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004230 if (w)
4231 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004232
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004233 return 0;
4234}
Liam Girdwooda5302182008-07-07 13:35:17 +01004235EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004236
4237/**
Mark Brown1547aba2010-05-07 21:11:40 +01004238 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004239 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004240 * @pin: audio signal pin endpoint (or start point)
4241 *
4242 * Mark the given endpoint or pin as ignoring suspend. When the
4243 * system is disabled a path between two endpoints flagged as ignoring
4244 * suspend will not be disabled. The path must already be enabled via
4245 * normal means at suspend time, it will not be turned on if it was not
4246 * already enabled.
4247 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004248int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4249 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004250{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004251 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004252
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004253 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004254 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004255 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004256 }
4257
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004258 w->ignore_suspend = 1;
4259
4260 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004261}
4262EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4263
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004264/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004265 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004266 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004267 *
4268 * Free all dapm widgets and resources.
4269 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004270void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004271{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004272 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004273 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004274 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004275}
4276EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4277
Xiang Xiao57996352014-03-02 00:04:02 +08004278static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004279{
Liam Girdwood01005a72012-07-06 16:57:05 +01004280 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004281 struct snd_soc_dapm_widget *w;
4282 LIST_HEAD(down_list);
4283 int powerdown = 0;
4284
Liam Girdwood01005a72012-07-06 16:57:05 +01004285 mutex_lock(&card->dapm_mutex);
4286
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004287 list_for_each_entry(w, &dapm->card->widgets, list) {
4288 if (w->dapm != dapm)
4289 continue;
Mark Brown51737472009-06-22 13:16:51 +01004290 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004291 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004292 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004293 powerdown = 1;
4294 }
4295 }
4296
4297 /* If there were no widgets to power down we're already in
4298 * standby.
4299 */
4300 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004301 if (dapm->bias_level == SND_SOC_BIAS_ON)
4302 snd_soc_dapm_set_bias_level(dapm,
4303 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004304 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004305 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4306 snd_soc_dapm_set_bias_level(dapm,
4307 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004308 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004309
4310 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004311}
Mark Brown51737472009-06-22 13:16:51 +01004312
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004313/*
4314 * snd_soc_dapm_shutdown - callback for system shutdown
4315 */
4316void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4317{
Xiang Xiao57996352014-03-02 00:04:02 +08004318 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004319
Xiang Xiao57996352014-03-02 00:04:02 +08004320 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004321 if (dapm != &card->dapm) {
4322 soc_dapm_shutdown_dapm(dapm);
4323 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4324 snd_soc_dapm_set_bias_level(dapm,
4325 SND_SOC_BIAS_OFF);
4326 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004327 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004328
4329 soc_dapm_shutdown_dapm(&card->dapm);
4330 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4331 snd_soc_dapm_set_bias_level(&card->dapm,
4332 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004333}
4334
Richard Purdie2b97eab2006-10-06 18:32:18 +02004335/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004336MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004337MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4338MODULE_LICENSE("GPL");