blob: e496bc642c990cb4f9fb2da06d54b3287aade4d1 [file] [log] [blame]
Kuninori Morimotoc01f3af2018-07-02 06:24:31 +00001// SPDX-License-Identifier: GPL-2.0+
2//
3// soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
4//
5// Copyright 2005 Wolfson Microelectronics PLC.
6// Author: Liam Girdwood <lrg@slimlogic.co.uk>
7//
8// Features:
9// o Changes power status of internal codec blocks depending on the
10// dynamic configuration of codec internal audio paths and active
11// DACs/ADCs.
12// o Platform power domain - can support external components i.e. amps and
13// mic/headphone insertion events.
14// o Automatic Mic Bias support
15// o Jack insertion power event initiation - e.g. hp insertion will enable
16// sinks, dacs, etc
17// o Delayed power down of audio subsystem to reduce pops between a quick
18// device reopen.
Richard Purdie2b97eab2006-10-06 18:32:18 +020019
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/init.h>
Mark Brown9d0624a2011-02-18 11:49:43 -080023#include <linux/async.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020024#include <linux/delay.h>
25#include <linux/pm.h>
26#include <linux/bitops.h>
27#include <linux/platform_device.h>
28#include <linux/jiffies.h>
Takashi Iwai20496ff2009-08-24 09:40:34 +020029#include <linux/debugfs.h>
Mark Brownf1aac482011-12-05 15:17:06 +000030#include <linux/pm_runtime.h>
Mark Brown62ea8742012-01-21 21:14:48 +000031#include <linux/regulator/consumer.h>
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +000032#include <linux/pinctrl/consumer.h>
Ola Liljad7e7eb92012-05-24 15:26:25 +020033#include <linux/clk.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020035#include <sound/core.h>
36#include <sound/pcm.h>
37#include <sound/pcm_params.h>
Liam Girdwoodce6120c2010-11-05 15:53:46 +020038#include <sound/soc.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020039#include <sound/initval.h>
40
Mark Brown84e90932010-11-04 00:07:02 -040041#include <trace/events/asoc.h>
42
Mark Brownde02d072011-09-20 21:43:24 +010043#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
44
Lars-Peter Clausena3423b02015-08-11 21:38:00 +020045#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
46 SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
47
48#define snd_soc_dapm_for_each_direction(dir) \
49 for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
50 (dir)++)
51
Lars-Peter Clausen57295072013-08-05 11:27:31 +020052static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
53 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
54 const char *control,
55 int (*connected)(struct snd_soc_dapm_widget *source,
56 struct snd_soc_dapm_widget *sink));
Vladimir Zapolskiy5353f652015-06-02 00:57:53 +030057
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +010058struct snd_soc_dapm_widget *
Lars-Peter Clausen57295072013-08-05 11:27:31 +020059snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
60 const struct snd_soc_dapm_widget *widget);
61
Liam Girdwood02aa78a2015-05-25 18:21:17 +010062struct snd_soc_dapm_widget *
63snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +020064 const struct snd_soc_dapm_widget *widget);
65
Richard Purdie2b97eab2006-10-06 18:32:18 +020066/* dapm power sequences - make this per codec in the future */
67static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010068 [snd_soc_dapm_pre] = 0,
Mark Brown62ea8742012-01-21 21:14:48 +000069 [snd_soc_dapm_regulator_supply] = 1,
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +000070 [snd_soc_dapm_pinctrl] = 1,
Ola Liljad7e7eb92012-05-24 15:26:25 +020071 [snd_soc_dapm_clock_supply] = 1,
Mark Brown1dd275b2013-10-09 13:56:37 +010072 [snd_soc_dapm_supply] = 2,
73 [snd_soc_dapm_micbias] = 3,
Mark Brownc74184e2012-04-04 22:12:09 +010074 [snd_soc_dapm_dai_link] = 2,
Mark Brown1dd275b2013-10-09 13:56:37 +010075 [snd_soc_dapm_dai_in] = 4,
76 [snd_soc_dapm_dai_out] = 4,
77 [snd_soc_dapm_aif_in] = 4,
78 [snd_soc_dapm_aif_out] = 4,
79 [snd_soc_dapm_mic] = 5,
80 [snd_soc_dapm_mux] = 6,
Lars-Peter Clausend714f972015-05-01 18:02:43 +020081 [snd_soc_dapm_demux] = 6,
Mark Brown1dd275b2013-10-09 13:56:37 +010082 [snd_soc_dapm_dac] = 7,
83 [snd_soc_dapm_switch] = 8,
84 [snd_soc_dapm_mixer] = 8,
85 [snd_soc_dapm_mixer_named_ctl] = 8,
86 [snd_soc_dapm_pga] = 9,
87 [snd_soc_dapm_adc] = 10,
88 [snd_soc_dapm_out_drv] = 11,
89 [snd_soc_dapm_hp] = 11,
90 [snd_soc_dapm_spk] = 11,
91 [snd_soc_dapm_line] = 11,
92 [snd_soc_dapm_kcontrol] = 12,
93 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020094};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000095
Richard Purdie2b97eab2006-10-06 18:32:18 +020096static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010097 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +020098 [snd_soc_dapm_kcontrol] = 1,
99 [snd_soc_dapm_adc] = 2,
100 [snd_soc_dapm_hp] = 3,
101 [snd_soc_dapm_spk] = 3,
102 [snd_soc_dapm_line] = 3,
103 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +0100104 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +0200105 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +0100106 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +0100107 [snd_soc_dapm_mixer] = 5,
108 [snd_soc_dapm_dac] = 6,
109 [snd_soc_dapm_mic] = 7,
110 [snd_soc_dapm_micbias] = 8,
111 [snd_soc_dapm_mux] = 9,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200112 [snd_soc_dapm_demux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100113 [snd_soc_dapm_aif_in] = 10,
114 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100115 [snd_soc_dapm_dai_in] = 10,
116 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100117 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100118 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100119 [snd_soc_dapm_clock_supply] = 13,
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +0000120 [snd_soc_dapm_pinctrl] = 13,
Mark Brown1dd275b2013-10-09 13:56:37 +0100121 [snd_soc_dapm_regulator_supply] = 13,
122 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200123};
124
Mark Brownf9fa2b12014-03-06 16:49:11 +0800125static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
126{
127 if (dapm->card && dapm->card->instantiated)
128 lockdep_assert_held(&dapm->card->dapm_mutex);
129}
130
Troy Kisky12ef1932008-10-13 17:42:14 -0700131static void pop_wait(u32 pop_time)
Mark Brown15e4c72f2008-07-02 11:51:20 +0100132{
133 if (pop_time)
134 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
135}
136
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200137static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c72f2008-07-02 11:51:20 +0100138{
139 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200140 char *buf;
141
142 if (!pop_time)
143 return;
144
145 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
146 if (buf == NULL)
147 return;
Mark Brown15e4c72f2008-07-02 11:51:20 +0100148
149 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200150 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100151 dev_info(dev, "%s", buf);
Mark Brown15e4c72f2008-07-02 11:51:20 +0100152 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200153
154 kfree(buf);
Mark Brown15e4c72f2008-07-02 11:51:20 +0100155}
156
Mark Browndb432b42011-10-03 21:06:40 +0100157static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
158{
159 return !list_empty(&w->dirty);
160}
161
Mark Brown492c0a12014-03-06 16:15:48 +0800162static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100163{
Mark Brownf9fa2b12014-03-06 16:49:11 +0800164 dapm_assert_locked(w->dapm);
165
Mark Brown75c1f892011-10-04 22:28:08 +0100166 if (!dapm_dirty_widget(w)) {
167 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
168 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100169 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100170 }
Mark Browndb432b42011-10-03 21:06:40 +0100171}
172
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200173/*
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200174 * Common implementation for dapm_widget_invalidate_input_paths() and
175 * dapm_widget_invalidate_output_paths(). The function is inlined since the
176 * combined size of the two specialized functions is only marginally larger then
177 * the size of the generic function and at the same time the fast path of the
178 * specialized functions is significantly smaller than the generic function.
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200179 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200180static __always_inline void dapm_widget_invalidate_paths(
181 struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200182{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200183 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
184 struct snd_soc_dapm_widget *node;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200185 struct snd_soc_dapm_path *p;
186 LIST_HEAD(list);
187
188 dapm_assert_locked(w->dapm);
189
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200190 if (w->endpoints[dir] == -1)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200191 return;
192
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200193 list_add_tail(&w->work_list, &list);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200194 w->endpoints[dir] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200195
196 list_for_each_entry(w, &list, work_list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200197 snd_soc_dapm_widget_for_each_path(w, dir, p) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200198 if (p->is_supply || p->weak || !p->connect)
199 continue;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200200 node = p->node[rdir];
201 if (node->endpoints[dir] != -1) {
202 node->endpoints[dir] = -1;
203 list_add_tail(&node->work_list, &list);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200204 }
205 }
206 }
207}
208
209/*
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200210 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of
211 * input paths
212 * @w: The widget for which to invalidate the cached number of input paths
213 *
214 * Resets the cached number of inputs for the specified widget and all widgets
215 * that can be reached via outcoming paths from the widget.
216 *
217 * This function must be called if the number of output paths for a widget might
218 * have changed. E.g. if the source state of a widget changes or a path is added
219 * or activated with the widget as the sink.
220 */
221static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
222{
223 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN);
224}
225
226/*
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200227 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
228 * output paths
229 * @w: The widget for which to invalidate the cached number of output paths
230 *
231 * Resets the cached number of outputs for the specified widget and all widgets
232 * that can be reached via incoming paths from the widget.
233 *
234 * This function must be called if the number of output paths for a widget might
235 * have changed. E.g. if the sink state of a widget changes or a path is added
236 * or activated with the widget as the source.
237 */
238static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
239{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200240 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200241}
242
243/*
244 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
245 * for the widgets connected to a path
246 * @p: The path to invalidate
247 *
248 * Resets the cached number of inputs for the sink of the path and the cached
249 * number of outputs for the source of the path.
250 *
251 * This function must be called when a path is added, removed or the connected
252 * state changes.
253 */
254static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
255{
256 /*
257 * Weak paths or supply paths do not influence the number of input or
258 * output paths of their neighbors.
259 */
260 if (p->weak || p->is_supply)
261 return;
262
263 /*
264 * The number of connected endpoints is the sum of the number of
265 * connected endpoints of all neighbors. If a node with 0 connected
266 * endpoints is either connected or disconnected that sum won't change,
267 * so there is no need to re-check the path.
268 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200269 if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200270 dapm_widget_invalidate_input_paths(p->sink);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200271 if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200272 dapm_widget_invalidate_output_paths(p->source);
273}
274
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200275void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
Mark Browne2d32ff2012-08-31 17:38:32 -0700276{
Mark Browne2d32ff2012-08-31 17:38:32 -0700277 struct snd_soc_dapm_widget *w;
278
279 mutex_lock(&card->dapm_mutex);
280
281 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200282 if (w->is_ep) {
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200283 dapm_mark_dirty(w, "Rechecking endpoints");
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200284 if (w->is_ep & SND_SOC_DAPM_EP_SINK)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200285 dapm_widget_invalidate_output_paths(w);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200286 if (w->is_ep & SND_SOC_DAPM_EP_SOURCE)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200287 dapm_widget_invalidate_input_paths(w);
288 }
Mark Browne2d32ff2012-08-31 17:38:32 -0700289 }
290
291 mutex_unlock(&card->dapm_mutex);
292}
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200293EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
Mark Browne2d32ff2012-08-31 17:38:32 -0700294
Richard Purdie2b97eab2006-10-06 18:32:18 +0200295/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100296static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200297 const struct snd_soc_dapm_widget *_widget)
298{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100299 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200300}
301
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200302struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200303 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200304 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200305 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200306 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200307};
308
309static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100310 struct snd_kcontrol *kcontrol, const char *ctrl_name)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200311{
312 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200313 struct soc_mixer_control *mc;
Charles Keepax561ed682015-05-01 12:37:26 +0100314 struct soc_enum *e;
Charles Keepax773da9b2015-05-01 12:37:25 +0100315 const char *name;
316 int ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200317
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200318 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100319 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200320 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200321
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200322 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200323
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200324 switch (widget->id) {
325 case snd_soc_dapm_switch:
326 case snd_soc_dapm_mixer:
327 case snd_soc_dapm_mixer_named_ctl:
328 mc = (struct soc_mixer_control *)kcontrol->private_value;
329
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800330 if (mc->autodisable && snd_soc_volsw_is_stereo(mc))
331 dev_warn(widget->dapm->dev,
332 "ASoC: Unsupported stereo autodisable control '%s'\n",
333 ctrl_name);
334
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200335 if (mc->autodisable) {
336 struct snd_soc_dapm_widget template;
337
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100338 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
Charles Keepax773da9b2015-05-01 12:37:25 +0100339 "Autodisable");
340 if (!name) {
341 ret = -ENOMEM;
342 goto err_data;
343 }
344
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200345 memset(&template, 0, sizeof(template));
346 template.reg = mc->reg;
347 template.mask = (1 << fls(mc->max)) - 1;
348 template.shift = mc->shift;
349 if (mc->invert)
350 template.off_val = mc->max;
351 else
352 template.off_val = 0;
353 template.on_val = template.off_val;
354 template.id = snd_soc_dapm_kcontrol;
Charles Keepax773da9b2015-05-01 12:37:25 +0100355 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200356
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200357 data->value = template.on_val;
358
Liam Girdwood02aa78a2015-05-25 18:21:17 +0100359 data->widget =
360 snd_soc_dapm_new_control_unlocked(widget->dapm,
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200361 &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200362 kfree(name);
Linus Walleij37e1df82017-01-13 10:23:52 +0100363 if (IS_ERR(data->widget)) {
364 ret = PTR_ERR(data->widget);
365 goto err_data;
366 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200367 }
368 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200369 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100370 case snd_soc_dapm_mux:
371 e = (struct soc_enum *)kcontrol->private_value;
372
373 if (e->autodisable) {
374 struct snd_soc_dapm_widget template;
375
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100376 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
Charles Keepax561ed682015-05-01 12:37:26 +0100377 "Autodisable");
378 if (!name) {
379 ret = -ENOMEM;
380 goto err_data;
381 }
382
383 memset(&template, 0, sizeof(template));
384 template.reg = e->reg;
385 template.mask = e->mask << e->shift_l;
386 template.shift = e->shift_l;
387 template.off_val = snd_soc_enum_item_to_val(e, 0);
388 template.on_val = template.off_val;
389 template.id = snd_soc_dapm_kcontrol;
390 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200391
392 data->value = template.on_val;
393
Charles Keepaxffacb482015-06-26 10:39:43 +0100394 data->widget = snd_soc_dapm_new_control_unlocked(
395 widget->dapm, &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200396 kfree(name);
Linus Walleij37e1df82017-01-13 10:23:52 +0100397 if (IS_ERR(data->widget)) {
398 ret = PTR_ERR(data->widget);
399 goto err_data;
400 }
Charles Keepax561ed682015-05-01 12:37:26 +0100401
402 snd_soc_dapm_add_path(widget->dapm, data->widget,
403 widget, NULL, NULL);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200404 }
405 break;
406 default:
407 break;
408 }
409
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200410 kcontrol->private_data = data;
411
412 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100413
Charles Keepax773da9b2015-05-01 12:37:25 +0100414err_data:
415 kfree(data);
416 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200417}
418
419static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
420{
421 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Srinivas Kandagatlaff2faf12018-06-04 12:13:26 +0100422
423 list_del(&data->paths);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200424 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200425 kfree(data);
426}
427
428static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
429 const struct snd_kcontrol *kcontrol)
430{
431 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
432
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200433 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200434}
435
436static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
437 struct snd_soc_dapm_widget *widget)
438{
439 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200440 struct snd_soc_dapm_widget_list *new_wlist;
441 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200442
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200443 if (data->wlist)
444 n = data->wlist->num_widgets + 1;
445 else
446 n = 1;
447
448 new_wlist = krealloc(data->wlist,
449 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
450 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200451 return -ENOMEM;
452
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200453 new_wlist->widgets[n - 1] = widget;
454 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200455
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200456 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200457
458 return 0;
459}
460
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200461static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
462 struct snd_soc_dapm_path *path)
463{
464 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
465
466 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200467}
468
469static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
470{
471 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
472
473 if (!data->widget)
474 return true;
475
476 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200477}
478
479static struct list_head *dapm_kcontrol_get_path_list(
480 const struct snd_kcontrol *kcontrol)
481{
482 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
483
484 return &data->paths;
485}
486
487#define dapm_kcontrol_for_each_path(path, kcontrol) \
488 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
489 list_kcontrol)
490
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530491unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200492{
493 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
494
495 return data->value;
496}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530497EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200498
499static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
500 unsigned int value)
501{
502 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
503
504 if (data->value == value)
505 return false;
506
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200507 if (data->widget)
508 data->widget->on_val = value;
509
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200510 data->value = value;
511
512 return true;
513}
514
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200515/**
Mythri P K93e39a12015-10-20 22:30:08 +0530516 * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
517 * kcontrol
518 * @kcontrol: The kcontrol
519 */
520struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
521 struct snd_kcontrol *kcontrol)
522{
523 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
524}
525EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
526
527/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200528 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
529 * kcontrol
530 * @kcontrol: The kcontrol
531 *
532 * Note: This function must only be used on kcontrols that are known to have
533 * been registered for a CODEC. Otherwise the behaviour is undefined.
534 */
535struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
536 struct snd_kcontrol *kcontrol)
537{
538 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
539}
540EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
541
Liam Girdwood6c120e12012-02-15 15:15:34 +0000542static void dapm_reset(struct snd_soc_card *card)
543{
544 struct snd_soc_dapm_widget *w;
545
Mark Brownf9fa2b12014-03-06 16:49:11 +0800546 lockdep_assert_held(&card->dapm_mutex);
547
Liam Girdwood6c120e12012-02-15 15:15:34 +0000548 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
549
550 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200551 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000552 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000553 }
554}
555
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200556static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
557{
558 if (!dapm->component)
559 return NULL;
560 return dapm->component->name_prefix;
561}
562
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200563static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800564 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100565{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200566 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200567 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200568 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100569}
570
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200571static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800572 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100573{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200574 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200575 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000576 return snd_soc_component_update_bits(dapm->component, reg,
577 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000578}
579
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200580static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
581 int reg, unsigned int mask, unsigned int value)
582{
583 if (!dapm->component)
584 return -EIO;
585 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
586}
587
Mark Browneb270e92013-10-09 13:52:52 +0100588static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
589{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200590 if (dapm->component)
591 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100592}
593
Charles Keepax45a110a2015-05-11 13:50:30 +0100594static struct snd_soc_dapm_widget *
595dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
596{
597 struct snd_soc_dapm_widget *w = wcache->widget;
598 struct list_head *wlist;
599 const int depth = 2;
600 int i = 0;
601
602 if (w) {
603 wlist = &w->dapm->card->widgets;
604
605 list_for_each_entry_from(w, wlist, list) {
606 if (!strcmp(name, w->name))
607 return w;
608
609 if (++i == depth)
610 break;
611 }
612 }
613
614 return NULL;
615}
616
617static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
618 struct snd_soc_dapm_widget *w)
619{
620 wcache->widget = w;
621}
622
Mark Brown452c5ea2009-05-17 21:41:23 +0100623/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200624 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
625 * @dapm: The DAPM context for which to set the level
626 * @level: The level to set
627 *
628 * Forces the DAPM bias level to a specific state. It will call the bias level
629 * callback of DAPM context with the specified level. This will even happen if
630 * the context is already at the same level. Furthermore it will not go through
631 * the normal bias level sequencing, meaning any intermediate states between the
632 * current and the target state will not be entered.
633 *
634 * Note that the change in bias level is only temporary and the next time
635 * snd_soc_dapm_sync() is called the state will be set to the level as
636 * determined by the DAPM core. The function is mainly intended to be used to
637 * used during probe or resume from suspend to power up the device so
638 * initialization can be done, before the DAPM core takes over.
639 */
640int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
641 enum snd_soc_bias_level level)
642{
643 int ret = 0;
644
645 if (dapm->set_bias_level)
646 ret = dapm->set_bias_level(dapm, level);
647
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200648 if (ret == 0)
649 dapm->bias_level = level;
650
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200651 return ret;
652}
653EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
654
Mark Brown452c5ea2009-05-17 21:41:23 +0100655/**
656 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800657 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100658 * @level: level to configure
659 *
660 * Configure the bias (power) levels for the SoC audio device.
661 *
662 * Returns 0 for success else error.
663 */
Mark Browned5a4c42011-02-18 11:12:42 -0800664static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200665 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100666{
Mark Browned5a4c42011-02-18 11:12:42 -0800667 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100668 int ret = 0;
669
Mark Brown84e90932010-11-04 00:07:02 -0400670 trace_snd_soc_bias_level_start(card, level);
671
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000672 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100673 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100674 if (ret != 0)
675 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100676
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200677 if (!card || dapm != &card->dapm)
678 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100679
Mark Brown171ec6b2011-06-06 18:15:19 +0100680 if (ret != 0)
681 goto out;
682
683 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100684 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100685out:
Mark Brown84e90932010-11-04 00:07:02 -0400686 trace_snd_soc_bias_level_done(card, level);
687
Mark Brown452c5ea2009-05-17 21:41:23 +0100688 return ret;
689}
690
Mark Brown74b8f952009-06-06 11:26:15 +0100691/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200692static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200693 struct snd_soc_dapm_path *path, const char *control_name,
694 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200695{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200696 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200697 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100698 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200699 int i;
700
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100701 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200702 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100703 val = (val >> e->shift_l) & e->mask;
704 item = snd_soc_enum_val_to_item(e, val);
705 } else {
706 /* since a virtual mux has no backing registers to
707 * decide which path to connect, it will try to match
708 * with the first enumeration. This is to ensure
709 * that the default mux choice (the first) will be
710 * correctly powered up during initialization.
711 */
712 item = 0;
713 }
714
Xie Yishengf9e0b4a2018-05-31 19:11:23 +0800715 i = match_string(e->texts, e->items, control_name);
716 if (i < 0)
717 return -ENODEV;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200718
Xie Yishengf9e0b4a2018-05-31 19:11:23 +0800719 path->name = e->texts[i];
720 path->connect = (i == item);
721 return 0;
722
Richard Purdie2b97eab2006-10-06 18:32:18 +0200723}
724
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100725/* set up initial codec paths */
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800726static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
727 int nth_path)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100728{
729 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200730 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100731 unsigned int reg = mc->reg;
732 unsigned int shift = mc->shift;
733 unsigned int max = mc->max;
734 unsigned int mask = (1 << fls(max)) - 1;
735 unsigned int invert = mc->invert;
736 unsigned int val;
737
738 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200739 soc_dapm_read(p->sink->dapm, reg, &val);
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800740 /*
741 * The nth_path argument allows this function to know
742 * which path of a kcontrol it is setting the initial
743 * status for. Ideally this would support any number
744 * of paths and channels. But since kcontrols only come
745 * in mono and stereo variants, we are limited to 2
746 * channels.
747 *
748 * The following code assumes for stereo controls the
749 * first path is the left channel, and all remaining
750 * paths are the right channel.
751 */
752 if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
753 if (reg != mc->rreg)
754 soc_dapm_read(p->sink->dapm, mc->rreg, &val);
755 val = (val >> mc->rshift) & mask;
756 } else {
757 val = (val >> shift) & mask;
758 }
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100759 if (invert)
760 val = max - val;
761 p->connect = !!val;
762 } else {
763 p->connect = 0;
764 }
765}
766
Mark Brown74b8f952009-06-06 11:26:15 +0100767/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200768static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200769 struct snd_soc_dapm_path *path, const char *control_name)
770{
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800771 int i, nth_path = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200772
773 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200774 for (i = 0; i < path->sink->num_kcontrols; i++) {
775 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
776 path->name = path->sink->kcontrol_news[i].name;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800777 dapm_set_mixer_path_status(path, i, nth_path++);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200778 return 0;
779 }
780 }
781 return -ENODEV;
782}
783
Stephen Warrenaf468002011-04-28 17:38:01 -0600784static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600785 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600786 const struct snd_kcontrol_new *kcontrol_new,
787 struct snd_kcontrol **kcontrol)
788{
789 struct snd_soc_dapm_widget *w;
790 int i;
791
792 *kcontrol = NULL;
793
794 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600795 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
796 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600797 for (i = 0; i < w->num_kcontrols; i++) {
798 if (&w->kcontrol_news[i] == kcontrol_new) {
799 if (w->kcontrols)
800 *kcontrol = w->kcontrols[i];
801 return 1;
802 }
803 }
804 }
805
806 return 0;
807}
808
Stephen Warren85762e72013-03-29 15:40:10 -0600809/*
810 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
811 * create it. Either way, add the widget into the control's widget list
812 */
Jeeja KP19a2557b2015-10-20 22:30:06 +0530813static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100814 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200815{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200816 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000817 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000818 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600819 size_t prefix_len;
820 int shared;
821 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600822 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200823 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600824 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200825 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000826
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200827 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000828 if (prefix)
829 prefix_len = strlen(prefix) + 1;
830 else
831 prefix_len = 0;
832
Stephen Warren85762e72013-03-29 15:40:10 -0600833 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
834 &kcontrol);
835
Stephen Warren85762e72013-03-29 15:40:10 -0600836 if (!kcontrol) {
837 if (shared) {
838 wname_in_long_name = false;
839 kcname_in_long_name = true;
840 } else {
841 switch (w->id) {
842 case snd_soc_dapm_switch:
843 case snd_soc_dapm_mixer:
Jeeja KP19a2557b2015-10-20 22:30:06 +0530844 case snd_soc_dapm_pga:
Chen-Yu Tsaia3930ed2016-08-27 19:28:00 +0800845 case snd_soc_dapm_out_drv:
Stephen Warren85762e72013-03-29 15:40:10 -0600846 wname_in_long_name = true;
847 kcname_in_long_name = true;
848 break;
849 case snd_soc_dapm_mixer_named_ctl:
850 wname_in_long_name = false;
851 kcname_in_long_name = true;
852 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200853 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600854 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600855 wname_in_long_name = true;
856 kcname_in_long_name = false;
857 break;
858 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600859 return -EINVAL;
860 }
861 }
862
863 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600864 /*
865 * The control will get a prefix from the control
866 * creation process but we're also using the same
867 * prefix for widgets so cut the prefix off the
868 * front of the widget name.
869 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200870 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600871 w->name + prefix_len,
872 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200873 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200874 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600875
876 name = long_name;
877 } else if (wname_in_long_name) {
878 long_name = NULL;
879 name = w->name + prefix_len;
880 } else {
881 long_name = NULL;
882 name = w->kcontrol_news[kci].name;
883 }
884
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200885 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600886 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200887 if (!kcontrol) {
888 ret = -ENOMEM;
889 goto exit_free;
890 }
891
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200892 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200893
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100894 ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200895 if (ret) {
896 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200897 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200898 }
899
Stephen Warren85762e72013-03-29 15:40:10 -0600900 ret = snd_ctl_add(card, kcontrol);
901 if (ret < 0) {
902 dev_err(dapm->dev,
903 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
904 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200905 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600906 }
Stephen Warren85762e72013-03-29 15:40:10 -0600907 }
908
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200909 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200910 if (ret == 0)
911 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200912
Daniel Macke5092c92014-10-07 13:41:24 +0200913exit_free:
914 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600915
Daniel Macke5092c92014-10-07 13:41:24 +0200916 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600917}
918
919/* create new dapm mixer control */
920static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
921{
922 int i, ret;
923 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100924 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600925
Richard Purdie2b97eab2006-10-06 18:32:18 +0200926 /* add kcontrol */
927 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200928 /* match name */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200929 snd_soc_dapm_widget_for_each_source_path(w, path) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200930 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600931 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200932 continue;
933
Charles Keepax561ed682015-05-01 12:37:26 +0100934 if (!w->kcontrols[i]) {
Jeeja KP19a2557b2015-10-20 22:30:06 +0530935 ret = dapm_create_or_share_kcontrol(w, i);
Charles Keepax561ed682015-05-01 12:37:26 +0100936 if (ret < 0)
937 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200938 }
939
Mark Brown946d92a2013-08-12 23:28:42 +0100940 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100941
942 data = snd_kcontrol_chip(w->kcontrols[i]);
943 if (data->widget)
944 snd_soc_dapm_add_path(data->widget->dapm,
945 data->widget,
946 path->source,
947 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200948 }
949 }
Stephen Warren85762e72013-03-29 15:40:10 -0600950
951 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200952}
953
954/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200955static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200956{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200957 struct snd_soc_dapm_context *dapm = w->dapm;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200958 enum snd_soc_dapm_direction dir;
Stephen Warren85762e72013-03-29 15:40:10 -0600959 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200960 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600961 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200962
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200963 switch (w->id) {
964 case snd_soc_dapm_mux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200965 dir = SND_SOC_DAPM_DIR_OUT;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200966 type = "mux";
967 break;
968 case snd_soc_dapm_demux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200969 dir = SND_SOC_DAPM_DIR_IN;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200970 type = "demux";
971 break;
972 default:
973 return -EINVAL;
974 }
975
Stephen Warrenaf468002011-04-28 17:38:01 -0600976 if (w->num_kcontrols != 1) {
977 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200978 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600979 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200980 return -EINVAL;
981 }
982
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200983 if (list_empty(&w->edges[dir])) {
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200984 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600985 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600986 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200987
Jeeja KP19a2557b2015-10-20 22:30:06 +0530988 ret = dapm_create_or_share_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600989 if (ret < 0)
990 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600991
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200992 snd_soc_dapm_widget_for_each_path(w, dir, path) {
993 if (path->name)
994 dapm_kcontrol_add_path(w->kcontrols[0], path);
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +0200995 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200996
Stephen Warrenaf468002011-04-28 17:38:01 -0600997 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200998}
999
1000/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02001001static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001002{
Jeeja KP19a2557b2015-10-20 22:30:06 +05301003 int i, ret;
1004
1005 for (i = 0; i < w->num_kcontrols; i++) {
1006 ret = dapm_create_or_share_kcontrol(w, i);
1007 if (ret < 0)
1008 return ret;
1009 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001010
Mark Browna6c65732010-03-03 17:45:21 +00001011 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001012}
1013
Nikesh Oswalc6615082015-02-02 17:06:44 +00001014/* create new dapm dai link control */
1015static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
1016{
1017 int i, ret;
1018 struct snd_kcontrol *kcontrol;
1019 struct snd_soc_dapm_context *dapm = w->dapm;
1020 struct snd_card *card = dapm->card->snd_card;
Charles Keepax243bcfa2018-09-05 15:21:02 +01001021 struct snd_soc_pcm_runtime *rtd = w->priv;
Nikesh Oswalc6615082015-02-02 17:06:44 +00001022
1023 /* create control for links with > 1 config */
Charles Keepax243bcfa2018-09-05 15:21:02 +01001024 if (rtd->dai_link->num_params <= 1)
Nikesh Oswalc6615082015-02-02 17:06:44 +00001025 return 0;
1026
1027 /* add kcontrol */
1028 for (i = 0; i < w->num_kcontrols; i++) {
1029 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
1030 w->name, NULL);
1031 ret = snd_ctl_add(card, kcontrol);
1032 if (ret < 0) {
1033 dev_err(dapm->dev,
1034 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1035 w->name, w->kcontrol_news[i].name, ret);
1036 return ret;
1037 }
1038 kcontrol->private_data = w;
1039 w->kcontrols[i] = kcontrol;
1040 }
1041
1042 return 0;
1043}
1044
Mark Brown9949788b2010-05-07 20:24:05 +01001045/* We implement power down on suspend by checking the power state of
1046 * the ALSA card - when we are suspending the ALSA state for the card
1047 * is set to D3.
1048 */
1049static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1050{
Mark Brown12ea2c72011-03-02 18:17:32 +00001051 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown9949788b2010-05-07 20:24:05 +01001052
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001053 switch (level) {
Mark Brown9949788b2010-05-07 20:24:05 +01001054 case SNDRV_CTL_POWER_D3hot:
1055 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +01001056 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001057 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001058 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +01001059 return widget->ignore_suspend;
Mark Brown9949788b2010-05-07 20:24:05 +01001060 default:
1061 return 1;
1062 }
1063}
1064
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001065static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1066 struct list_head *widgets)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001067{
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001068 struct snd_soc_dapm_widget *w;
1069 struct list_head *it;
1070 unsigned int size = 0;
1071 unsigned int i = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001072
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001073 list_for_each(it, widgets)
1074 size++;
1075
Kees Cookacafe7e2018-05-08 13:45:50 -07001076 *list = kzalloc(struct_size(*list, widgets, size), GFP_KERNEL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001077 if (*list == NULL)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001078 return -ENOMEM;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001079
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001080 list_for_each_entry(w, widgets, work_list)
1081 (*list)->widgets[i++] = w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001082
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001083 (*list)->num_widgets = i;
1084
1085 return 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001086}
1087
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001088/*
1089 * Common implementation for is_connected_output_ep() and
1090 * is_connected_input_ep(). The function is inlined since the combined size of
1091 * the two specialized functions is only marginally larger then the size of the
1092 * generic function and at the same time the fast path of the specialized
1093 * functions is significantly smaller than the generic function.
1094 */
1095static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
1096 struct list_head *list, enum snd_soc_dapm_direction dir,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001097 int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
1098 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1099 enum snd_soc_dapm_direction)),
1100 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1101 enum snd_soc_dapm_direction))
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001102{
1103 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001104 struct snd_soc_dapm_path *path;
1105 int con = 0;
1106
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001107 if (widget->endpoints[dir] >= 0)
1108 return widget->endpoints[dir];
Mark Brown024dc072011-10-09 11:52:05 +01001109
Mark Brownde02d072011-09-20 21:43:24 +01001110 DAPM_UPDATE_STAT(widget, path_checks);
1111
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001112 /* do we need to add this widget to the list ? */
1113 if (list)
1114 list_add_tail(&widget->work_list, list);
1115
Jeeja KP09464972016-06-15 11:16:55 +05301116 if (custom_stop_condition && custom_stop_condition(widget, dir)) {
1117 widget->endpoints[dir] = 1;
1118 return widget->endpoints[dir];
1119 }
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001120
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001121 if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
1122 widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
1123 return widget->endpoints[dir];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001124 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001125
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001126 snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
Mark Browne56235e02011-09-21 18:19:14 +01001127 DAPM_UPDATE_STAT(widget, neighbour_checks);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001128
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001129 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001130 continue;
1131
Mark Brown8af294b2013-02-22 17:48:15 +00001132 if (path->walking)
1133 return 1;
1134
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001135 trace_snd_soc_dapm_path(widget, dir, path);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001136
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001137 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001138 path->walking = 1;
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001139 con += fn(path->node[dir], list, custom_stop_condition);
Mark Brown8af294b2013-02-22 17:48:15 +00001140 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001141 }
1142 }
1143
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001144 widget->endpoints[dir] = con;
Mark Brown024dc072011-10-09 11:52:05 +01001145
Richard Purdie2b97eab2006-10-06 18:32:18 +02001146 return con;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001147}
1148
1149/*
1150 * Recursively check for a completed path to an active or physically connected
1151 * output widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001152 *
1153 * Optionally, can be supplied with a function acting as a stopping condition.
1154 * This function takes the dapm widget currently being examined and the walk
1155 * direction as an arguments, it should return true if the walk should be
1156 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001157 */
1158static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001159 struct list_head *list,
1160 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1161 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001162{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001163 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001164 is_connected_output_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001165}
1166
1167/*
1168 * Recursively check for a completed path to an active or physically connected
1169 * input widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001170 *
1171 * Optionally, can be supplied with a function acting as a stopping condition.
1172 * This function takes the dapm widget currently being examined and the walk
1173 * direction as an arguments, it should return true if the walk should be
1174 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001175 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001176static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001177 struct list_head *list,
1178 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1179 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001180{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001181 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001182 is_connected_input_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001183}
1184
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001185/**
1186 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1187 * @dai: the soc DAI.
1188 * @stream: stream direction.
1189 * @list: list of active widgets for this stream.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001190 * @custom_stop_condition: (optional) a function meant to stop the widget graph
1191 * walk based on custom logic.
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001192 *
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001193 * Queries DAPM graph as to whether a valid audio stream path exists for
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001194 * the initial stream specified by name. This takes into account
1195 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1196 *
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001197 * Optionally, can be supplied with a function acting as a stopping condition.
1198 * This function takes the dapm widget currently being examined and the walk
1199 * direction as an arguments, it should return true if the walk should be
1200 * stopped and false otherwise.
1201 *
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001202 * Returns the number of valid paths or negative error.
1203 */
1204int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001205 struct snd_soc_dapm_widget_list **list,
1206 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1207 enum snd_soc_dapm_direction))
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001208{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001209 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001210 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001211 LIST_HEAD(widgets);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001212 int paths;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001213 int ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001214
1215 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001216
1217 /*
1218 * For is_connected_{output,input}_ep fully discover the graph we need
1219 * to reset the cached number of inputs and outputs.
1220 */
1221 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001222 w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
1223 w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001224 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001225
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001226 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001227 paths = is_connected_output_ep(dai->playback_widget, &widgets,
1228 custom_stop_condition);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001229 else
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001230 paths = is_connected_input_ep(dai->capture_widget, &widgets,
1231 custom_stop_condition);
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001232
1233 /* Drop starting point */
1234 list_del(widgets.next);
1235
1236 ret = dapm_widget_list_create(list, &widgets);
1237 if (ret)
Lars-Peter Clausen30abbe72015-08-11 21:37:59 +02001238 paths = ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001239
1240 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001241 mutex_unlock(&card->dapm_mutex);
1242
1243 return paths;
1244}
1245
Richard Purdie2b97eab2006-10-06 18:32:18 +02001246/*
Mark Brown62ea8742012-01-21 21:14:48 +00001247 * Handler for regulator supply widget.
1248 */
1249int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1250 struct snd_kcontrol *kcontrol, int event)
1251{
Mark Brownc05b84d2012-09-07 12:57:11 +08001252 int ret;
1253
Mark Browneb270e92013-10-09 13:52:52 +01001254 soc_dapm_async_complete(w->dapm);
1255
Mark Brownc05b84d2012-09-07 12:57:11 +08001256 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001257 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001258 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001259 if (ret != 0)
1260 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001261 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001262 w->name, ret);
1263 }
1264
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001265 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001266 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001267 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001268 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001269 if (ret != 0)
1270 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001271 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001272 w->name, ret);
1273 }
1274
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001275 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001276 }
Mark Brown62ea8742012-01-21 21:14:48 +00001277}
1278EXPORT_SYMBOL_GPL(dapm_regulator_event);
1279
Ola Liljad7e7eb92012-05-24 15:26:25 +02001280/*
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00001281 * Handler for pinctrl widget.
1282 */
1283int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
1284 struct snd_kcontrol *kcontrol, int event)
1285{
1286 struct snd_soc_dapm_pinctrl_priv *priv = w->priv;
1287 struct pinctrl *p = w->pinctrl;
1288 struct pinctrl_state *s;
1289
1290 if (!p || !priv)
1291 return -EIO;
1292
1293 if (SND_SOC_DAPM_EVENT_ON(event))
1294 s = pinctrl_lookup_state(p, priv->active_state);
1295 else
1296 s = pinctrl_lookup_state(p, priv->sleep_state);
1297
1298 if (IS_ERR(s))
1299 return PTR_ERR(s);
1300
1301 return pinctrl_select_state(p, s);
1302}
1303EXPORT_SYMBOL_GPL(dapm_pinctrl_event);
1304
1305/*
Ola Liljad7e7eb92012-05-24 15:26:25 +02001306 * Handler for clock supply widget.
1307 */
1308int dapm_clock_event(struct snd_soc_dapm_widget *w,
1309 struct snd_kcontrol *kcontrol, int event)
1310{
1311 if (!w->clk)
1312 return -EIO;
1313
Mark Browneb270e92013-10-09 13:52:52 +01001314 soc_dapm_async_complete(w->dapm);
1315
Ola Liljad7e7eb92012-05-24 15:26:25 +02001316 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001317 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001318 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001319 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001320 return 0;
1321 }
Charles Keepaxd78b1e432018-08-28 14:35:02 +01001322
Marek Belisko98b3cf12012-07-12 23:00:16 +02001323 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001324}
1325EXPORT_SYMBOL_GPL(dapm_clock_event);
1326
Mark Brownd805002b2011-09-28 18:28:23 +01001327static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1328{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001329 if (w->power_checked)
1330 return w->new_power;
1331
Mark Brownd805002b2011-09-28 18:28:23 +01001332 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001333 w->new_power = 1;
Mark Brownd805002b2011-09-28 18:28:23 +01001334 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001335 w->new_power = w->power_check(w);
1336
1337 w->power_checked = true;
1338
1339 return w->new_power;
Mark Brownd805002b2011-09-28 18:28:23 +01001340}
1341
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001342/* Generic check to see if a widget should be powered. */
Mark Browncd0f2d42009-04-20 16:56:59 +01001343static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1344{
1345 int in, out;
1346
Mark Brownde02d072011-09-20 21:43:24 +01001347 DAPM_UPDATE_STAT(w, power_checks);
1348
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001349 in = is_connected_input_ep(w, NULL, NULL);
1350 out = is_connected_output_ep(w, NULL, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001351 return out != 0 && in != 0;
1352}
1353
Mark Brown246d0a12009-04-22 18:24:55 +01001354/* Check to see if a power supply is needed */
1355static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1356{
1357 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001358
Mark Brownde02d072011-09-20 21:43:24 +01001359 DAPM_UPDATE_STAT(w, power_checks);
1360
Mark Brown246d0a12009-04-22 18:24:55 +01001361 /* Check if one of our outputs is connected */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001362 snd_soc_dapm_widget_for_each_sink_path(w, path) {
Mark Browna8fdac82011-09-28 18:20:26 +01001363 DAPM_UPDATE_STAT(w, neighbour_checks);
1364
Mark Brownbf3a9e12011-06-13 16:42:29 +01001365 if (path->weak)
1366 continue;
1367
Mark Brown215edda2009-09-08 18:59:05 +01001368 if (path->connected &&
1369 !path->connected(path->source, path->sink))
1370 continue;
1371
Mark Brownf68d7e12011-10-04 22:57:50 +01001372 if (dapm_widget_power_check(path->sink))
1373 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001374 }
1375
Mark Brownf68d7e12011-10-04 22:57:50 +01001376 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001377}
1378
Mark Brown35c64bc2011-09-28 18:23:53 +01001379static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1380{
Charles Keepax20bb0182015-12-02 10:22:16 +00001381 return w->connected;
Mark Brown35c64bc2011-09-28 18:23:53 +01001382}
1383
Mark Brown38357ab2009-06-06 19:03:23 +01001384static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1385 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001386 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001387{
Mark Brown828a8422011-01-15 13:14:30 +00001388 int *sort;
1389
1390 if (power_up)
1391 sort = dapm_up_seq;
1392 else
1393 sort = dapm_down_seq;
1394
Mark Brown38357ab2009-06-06 19:03:23 +01001395 if (sort[a->id] != sort[b->id])
1396 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001397 if (a->subseq != b->subseq) {
1398 if (power_up)
1399 return a->subseq - b->subseq;
1400 else
1401 return b->subseq - a->subseq;
1402 }
Mark Brownb22ead22009-06-07 12:51:26 +01001403 if (a->reg != b->reg)
1404 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001405 if (a->dapm != b->dapm)
1406 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001407
Mark Brown38357ab2009-06-06 19:03:23 +01001408 return 0;
1409}
Mark Brown42aa3412009-03-01 19:21:10 +00001410
Mark Brown38357ab2009-06-06 19:03:23 +01001411/* Insert a widget in order into a DAPM power sequence. */
1412static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1413 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001414 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001415{
1416 struct snd_soc_dapm_widget *w;
1417
1418 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001419 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001420 list_add_tail(&new_widget->power_list, &w->power_list);
1421 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001422 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001423
Mark Brown38357ab2009-06-06 19:03:23 +01001424 list_add_tail(&new_widget->power_list, list);
1425}
Mark Brown42aa3412009-03-01 19:21:10 +00001426
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001427static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001428 struct snd_soc_dapm_widget *w, int event)
1429{
Mark Brown68f89ad2010-11-03 23:51:49 -04001430 const char *ev_name;
1431 int power, ret;
1432
1433 switch (event) {
1434 case SND_SOC_DAPM_PRE_PMU:
1435 ev_name = "PRE_PMU";
1436 power = 1;
1437 break;
1438 case SND_SOC_DAPM_POST_PMU:
1439 ev_name = "POST_PMU";
1440 power = 1;
1441 break;
1442 case SND_SOC_DAPM_PRE_PMD:
1443 ev_name = "PRE_PMD";
1444 power = 0;
1445 break;
1446 case SND_SOC_DAPM_POST_PMD:
1447 ev_name = "POST_PMD";
1448 power = 0;
1449 break;
Mark Brown80114122013-02-25 15:14:19 +00001450 case SND_SOC_DAPM_WILL_PMU:
1451 ev_name = "WILL_PMU";
1452 power = 1;
1453 break;
1454 case SND_SOC_DAPM_WILL_PMD:
1455 ev_name = "WILL_PMD";
1456 power = 0;
1457 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001458 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001459 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001460 return;
1461 }
1462
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001463 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001464 return;
1465
1466 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001467 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001468 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001469 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001470 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001471 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001472 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001473 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001474 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001475 ev_name, w->name, ret);
1476 }
1477}
1478
Mark Brownb22ead22009-06-07 12:51:26 +01001479/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001480static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001481 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001482{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001483 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001484 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001485 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001486 unsigned int value = 0;
1487 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001488
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001489 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1490 reg = w->reg;
1491 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001492
1493 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001494 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001495 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001496
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001497 mask |= w->mask << w->shift;
1498 if (w->power)
1499 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001500 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001501 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001502
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001503 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001504 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1505 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001506
Mark Brown68f89ad2010-11-03 23:51:49 -04001507 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001508 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1509 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001510 }
1511
Mark Brown81628102009-06-07 13:21:24 +01001512 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001513 /* Any widget will do, they should all be updating the
1514 * same register.
1515 */
Mark Brown29376bc2011-06-19 13:49:28 +01001516
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001517 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001518 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001519 value, mask, reg, card->pop_time);
1520 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001521 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001522 }
1523
1524 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001525 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1526 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001527 }
Mark Brown42aa3412009-03-01 19:21:10 +00001528}
1529
Mark Brownb22ead22009-06-07 12:51:26 +01001530/* Apply a DAPM power sequence.
1531 *
1532 * We walk over a pre-sorted list of widgets to apply power to. In
1533 * order to minimise the number of writes to the device required
1534 * multiple widgets will be updated in a single write where possible.
1535 * Currently anything that requires more than a single write is not
1536 * handled.
1537 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001538static void dapm_seq_run(struct snd_soc_card *card,
1539 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001540{
1541 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001542 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001543 LIST_HEAD(pending);
1544 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001545 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001546 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001547 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001548 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001549 int *sort;
1550
1551 if (power_up)
1552 sort = dapm_up_seq;
1553 else
1554 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001555
Mark Brownb22ead22009-06-07 12:51:26 +01001556 list_for_each_entry_safe(w, n, list, power_list) {
1557 ret = 0;
1558
1559 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001560 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001561 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001562 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001563 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001564
Mark Brown474b62d2011-01-18 16:14:44 +00001565 if (cur_dapm && cur_dapm->seq_notifier) {
1566 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1567 if (sort[i] == cur_sort)
1568 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001569 i,
1570 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001571 }
1572
Mark Browneb270e92013-10-09 13:52:52 +01001573 if (cur_dapm && w->dapm != cur_dapm)
1574 soc_dapm_async_complete(cur_dapm);
1575
Mark Brownb22ead22009-06-07 12:51:26 +01001576 INIT_LIST_HEAD(&pending);
1577 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001578 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001579 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001580 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001581 }
1582
Mark Brown163cac02009-06-07 10:12:52 +01001583 switch (w->id) {
1584 case snd_soc_dapm_pre:
1585 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001586 list_for_each_entry_safe_continue(w, n, list,
1587 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001588
Mark Brownb22ead22009-06-07 12:51:26 +01001589 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001590 ret = w->event(w,
1591 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001592 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001593 ret = w->event(w,
1594 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001595 break;
1596
1597 case snd_soc_dapm_post:
1598 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001599 list_for_each_entry_safe_continue(w, n, list,
1600 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001601
Mark Brownb22ead22009-06-07 12:51:26 +01001602 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001603 ret = w->event(w,
1604 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001605 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001606 ret = w->event(w,
1607 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001608 break;
1609
Mark Brown163cac02009-06-07 10:12:52 +01001610 default:
Mark Brown81628102009-06-07 13:21:24 +01001611 /* Queue it up for application */
1612 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001613 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001614 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001615 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001616 list_move(&w->power_list, &pending);
1617 break;
Mark Brown163cac02009-06-07 10:12:52 +01001618 }
Mark Brownb22ead22009-06-07 12:51:26 +01001619
1620 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001621 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001622 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001623 }
Mark Brownb22ead22009-06-07 12:51:26 +01001624
1625 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001626 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001627
1628 if (cur_dapm && cur_dapm->seq_notifier) {
1629 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1630 if (sort[i] == cur_sort)
1631 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001632 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001633 }
Mark Browneb270e92013-10-09 13:52:52 +01001634
1635 list_for_each_entry(d, &card->dapm_list, list) {
1636 soc_dapm_async_complete(d);
1637 }
Mark Brown163cac02009-06-07 10:12:52 +01001638}
1639
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001640static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001641{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001642 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001643 struct snd_soc_dapm_widget_list *wlist;
1644 struct snd_soc_dapm_widget *w = NULL;
1645 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001646 int ret;
1647
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001648 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001649 return;
1650
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001651 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001652
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001653 for (wi = 0; wi < wlist->num_widgets; wi++) {
1654 w = wlist->widgets[wi];
1655
1656 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1657 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1658 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001659 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001660 w->name, ret);
1661 }
Mark Brown97404f22010-12-14 16:13:57 +00001662 }
1663
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001664 if (!w)
1665 return;
1666
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001667 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1668 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001669 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001670 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001671 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001672
Chen-Yu Tsaie411b0b2016-11-02 15:35:58 +08001673 if (update->has_second_set) {
1674 ret = soc_dapm_update_bits(w->dapm, update->reg2,
1675 update->mask2, update->val2);
1676 if (ret < 0)
1677 dev_err(w->dapm->dev,
1678 "ASoC: %s DAPM update failed: %d\n",
1679 w->name, ret);
1680 }
1681
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001682 for (wi = 0; wi < wlist->num_widgets; wi++) {
1683 w = wlist->widgets[wi];
1684
1685 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1686 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1687 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001688 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001689 w->name, ret);
1690 }
Mark Brown97404f22010-12-14 16:13:57 +00001691 }
1692}
1693
Mark Brown9d0624a2011-02-18 11:49:43 -08001694/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1695 * they're changing state.
1696 */
1697static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1698{
1699 struct snd_soc_dapm_context *d = data;
1700 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001701
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001702 /* If we're off and we're not supposed to go into STANDBY */
Mark Brown56fba412011-06-04 11:25:10 +01001703 if (d->bias_level == SND_SOC_BIAS_OFF &&
1704 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001705 if (d->dev)
1706 pm_runtime_get_sync(d->dev);
1707
Mark Brown9d0624a2011-02-18 11:49:43 -08001708 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1709 if (ret != 0)
1710 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001711 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001712 }
1713
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001714 /* Prepare for a transition to ON or away from ON */
1715 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1716 d->bias_level != SND_SOC_BIAS_ON) ||
1717 (d->target_bias_level != SND_SOC_BIAS_ON &&
1718 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001719 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1720 if (ret != 0)
1721 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001722 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001723 }
1724}
1725
1726/* Async callback run prior to DAPM sequences - brings to their final
1727 * state.
1728 */
1729static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1730{
1731 struct snd_soc_dapm_context *d = data;
1732 int ret;
1733
1734 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001735 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1736 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1737 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001738 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1739 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001740 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001741 ret);
1742 }
1743
1744 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001745 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1746 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001747 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1748 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001749 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1750 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001751
1752 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001753 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001754 }
1755
1756 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001757 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1758 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001759 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1760 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001761 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001762 ret);
1763 }
1764}
Mark Brown97404f22010-12-14 16:13:57 +00001765
Mark Brownfe4fda52011-10-03 22:36:57 +01001766static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1767 bool power, bool connect)
1768{
1769 /* If a connection is being made or broken then that update
1770 * will have marked the peer dirty, otherwise the widgets are
1771 * not connected and this update has no impact. */
1772 if (!connect)
1773 return;
1774
1775 /* If the peer is already in the state we're moving to then we
1776 * won't have an impact on it. */
1777 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001778 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001779}
1780
Mark Brown05623c42011-09-28 17:02:31 +01001781static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1782 struct list_head *up_list,
1783 struct list_head *down_list)
1784{
Mark Browndb432b42011-10-03 21:06:40 +01001785 struct snd_soc_dapm_path *path;
1786
Mark Brown05623c42011-09-28 17:02:31 +01001787 if (w->power == power)
1788 return;
1789
1790 trace_snd_soc_dapm_widget_power(w, power);
1791
Mark Browndb432b42011-10-03 21:06:40 +01001792 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001793 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001794 */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001795 snd_soc_dapm_widget_for_each_source_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001796 dapm_widget_set_peer_power(path->source, power, path->connect);
1797
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001798 /* Supplies can't affect their outputs, only their inputs */
1799 if (!w->is_supply) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001800 snd_soc_dapm_widget_for_each_sink_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001801 dapm_widget_set_peer_power(path->sink, power,
1802 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001803 }
1804
Mark Brown05623c42011-09-28 17:02:31 +01001805 if (power)
1806 dapm_seq_insert(w, up_list, true);
1807 else
1808 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001809}
1810
Mark Brown7c81beb2011-09-20 22:22:32 +01001811static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1812 struct list_head *up_list,
1813 struct list_head *down_list)
1814{
Mark Brown7c81beb2011-09-20 22:22:32 +01001815 int power;
1816
1817 switch (w->id) {
1818 case snd_soc_dapm_pre:
1819 dapm_seq_insert(w, down_list, false);
1820 break;
1821 case snd_soc_dapm_post:
1822 dapm_seq_insert(w, up_list, true);
1823 break;
1824
1825 default:
Mark Brownd805002b2011-09-28 18:28:23 +01001826 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001827
Mark Brown05623c42011-09-28 17:02:31 +01001828 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001829 break;
1830 }
1831}
1832
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001833static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1834{
1835 if (dapm->idle_bias_off)
1836 return true;
1837
1838 switch (snd_power_get_state(dapm->card->snd_card)) {
1839 case SNDRV_CTL_POWER_D3hot:
1840 case SNDRV_CTL_POWER_D3cold:
1841 return dapm->suspend_bias_off;
1842 default:
1843 break;
1844 }
1845
1846 return false;
1847}
1848
Mark Brown42aa3412009-03-01 19:21:10 +00001849/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001850 * Scan each dapm widget for complete audio path.
1851 * A complete path is a route that has valid endpoints i.e.:-
1852 *
1853 * o DAC to output pin.
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001854 * o Input pin to ADC.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001855 * o Input pin to Output pin (bypass, sidetone)
1856 * o DAC to ADC (loopback).
1857 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001858static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001859{
1860 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001861 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001862 LIST_HEAD(up_list);
1863 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001864 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001865 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001866
Mark Brownf9fa2b12014-03-06 16:49:11 +08001867 lockdep_assert_held(&card->dapm_mutex);
1868
Mark Brown84e90932010-11-04 00:07:02 -04001869 trace_snd_soc_dapm_start(card);
1870
Mark Brown56fba412011-06-04 11:25:10 +01001871 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001872 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001873 d->target_bias_level = SND_SOC_BIAS_OFF;
1874 else
1875 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001876 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001877
Liam Girdwood6c120e12012-02-15 15:15:34 +00001878 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001879
Mark Brown6d3ddc82009-05-16 17:47:29 +01001880 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001881 * lists indicating if they should be powered up or down. We
1882 * only check widgets that have been flagged as dirty but note
1883 * that new widgets may be added to the dirty list while we
1884 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001885 */
Mark Browndb432b42011-10-03 21:06:40 +01001886 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001887 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001888 }
1889
Mark Brownf9de6d72011-09-28 17:19:47 +01001890 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001891 switch (w->id) {
1892 case snd_soc_dapm_pre:
1893 case snd_soc_dapm_post:
1894 /* These widgets always need to be powered */
1895 break;
1896 default:
1897 list_del_init(&w->dirty);
1898 break;
1899 }
Mark Browndb432b42011-10-03 21:06:40 +01001900
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001901 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001902 d = w->dapm;
1903
1904 /* Supplies and micbiases only bring the
1905 * context up to STANDBY as unless something
1906 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001907 * generally don't require full power. Signal
1908 * generators are virtual pins and have no
1909 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001910 */
1911 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001912 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001913 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001914 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001915 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001916 case snd_soc_dapm_regulator_supply:
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00001917 case snd_soc_dapm_pinctrl:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001918 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001919 case snd_soc_dapm_micbias:
1920 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1921 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1922 break;
1923 default:
1924 d->target_bias_level = SND_SOC_BIAS_ON;
1925 break;
1926 }
1927 }
1928
1929 }
1930
Mark Brown85a843c2011-09-21 21:29:47 +01001931 /* Force all contexts in the card to the same bias state if
1932 * they're not ground referenced.
1933 */
Mark Brown56fba412011-06-04 11:25:10 +01001934 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001935 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001936 if (d->target_bias_level > bias)
1937 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001938 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001939 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001940 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001941
Mark Brownde02d072011-09-20 21:43:24 +01001942 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001943
Xiang Xiao17282ba2014-03-02 00:04:03 +08001944 /* Run card bias changes at first */
1945 dapm_pre_sequence_async(&card->dapm, 0);
1946 /* Run other bias changes in parallel */
1947 list_for_each_entry(d, &card->dapm_list, list) {
Jon Huntere03546d2018-08-17 16:35:43 +01001948 if (d != &card->dapm && d->bias_level != d->target_bias_level)
Xiang Xiao17282ba2014-03-02 00:04:03 +08001949 async_schedule_domain(dapm_pre_sequence_async, d,
1950 &async_domain);
1951 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001952 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001953
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001954 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001955 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001956 }
1957
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001958 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001959 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001960 }
1961
Mark Brown6d3ddc82009-05-16 17:47:29 +01001962 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001963 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001964
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001965 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001966
Mark Brown6d3ddc82009-05-16 17:47:29 +01001967 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001968 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001969
Mark Brown9d0624a2011-02-18 11:49:43 -08001970 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001971 list_for_each_entry(d, &card->dapm_list, list) {
Jon Huntere03546d2018-08-17 16:35:43 +01001972 if (d != &card->dapm && d->bias_level != d->target_bias_level)
Xiang Xiao17282ba2014-03-02 00:04:03 +08001973 async_schedule_domain(dapm_post_sequence_async, d,
1974 &async_domain);
1975 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001976 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001977 /* Run card bias changes at last */
1978 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001979
Liam Girdwood8078d872012-02-15 15:15:35 +00001980 /* do we need to notify any clients that DAPM event is complete */
1981 list_for_each_entry(d, &card->dapm_list, list) {
1982 if (d->stream_event)
1983 d->stream_event(d, event);
1984 }
1985
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001986 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001987 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001988 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001989
Mark Brown84e90932010-11-04 00:07:02 -04001990 trace_snd_soc_dapm_done(card);
1991
Mark Brown42aa3412009-03-01 19:21:10 +00001992 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001993}
1994
Mark Brown79fb9382009-08-21 16:38:13 +01001995#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001996static ssize_t dapm_widget_power_read_file(struct file *file,
1997 char __user *user_buf,
1998 size_t count, loff_t *ppos)
1999{
2000 struct snd_soc_dapm_widget *w = file->private_data;
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002001 struct snd_soc_card *card = w->dapm->card;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002002 enum snd_soc_dapm_direction dir, rdir;
Mark Brown79fb9382009-08-21 16:38:13 +01002003 char *buf;
2004 int in, out;
2005 ssize_t ret;
2006 struct snd_soc_dapm_path *p = NULL;
2007
2008 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2009 if (!buf)
2010 return -ENOMEM;
2011
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002012 mutex_lock(&card->dapm_mutex);
2013
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002014 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
2015 if (w->is_supply) {
2016 in = 0;
2017 out = 0;
2018 } else {
Piotr Stankiewicz67420642016-05-13 17:03:55 +01002019 in = is_connected_input_ep(w, NULL, NULL);
2020 out = is_connected_output_ep(w, NULL, NULL);
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002021 }
Mark Brown79fb9382009-08-21 16:38:13 +01002022
Mark Brownf13ebad2012-03-03 18:01:01 +00002023 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
2024 w->name, w->power ? "On" : "Off",
2025 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01002026
Mark Brownd033c362009-12-04 15:25:56 +00002027 if (w->reg >= 0)
2028 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002029 " - R%d(0x%x) mask 0x%x",
2030 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00002031
2032 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
2033
Mark Brown3eef08b2009-09-14 16:49:00 +01002034 if (w->sname)
2035 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
2036 w->sname,
2037 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01002038
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002039 snd_soc_dapm_for_each_direction(dir) {
2040 rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
2041 snd_soc_dapm_widget_for_each_path(w, dir, p) {
KaiChieh Chuang28735af2018-02-05 13:00:00 +08002042 if (p->connected && !p->connected(p->source, p->sink))
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002043 continue;
Mark Brown215edda2009-09-08 18:59:05 +01002044
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002045 if (!p->connect)
2046 continue;
Mark Brown215edda2009-09-08 18:59:05 +01002047
Mark Brown79fb9382009-08-21 16:38:13 +01002048 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002049 " %s \"%s\" \"%s\"\n",
2050 (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
Mark Brown79fb9382009-08-21 16:38:13 +01002051 p->name ? p->name : "static",
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002052 p->node[rdir]->name);
2053 }
Mark Brown79fb9382009-08-21 16:38:13 +01002054 }
2055
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002056 mutex_unlock(&card->dapm_mutex);
2057
Mark Brown79fb9382009-08-21 16:38:13 +01002058 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
2059
2060 kfree(buf);
2061 return ret;
2062}
2063
2064static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002065 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01002066 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002067 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01002068};
2069
Mark Brownef49e4f2011-04-04 20:48:13 +09002070static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
2071 size_t count, loff_t *ppos)
2072{
2073 struct snd_soc_dapm_context *dapm = file->private_data;
2074 char *level;
2075
2076 switch (dapm->bias_level) {
2077 case SND_SOC_BIAS_ON:
2078 level = "On\n";
2079 break;
2080 case SND_SOC_BIAS_PREPARE:
2081 level = "Prepare\n";
2082 break;
2083 case SND_SOC_BIAS_STANDBY:
2084 level = "Standby\n";
2085 break;
2086 case SND_SOC_BIAS_OFF:
2087 level = "Off\n";
2088 break;
2089 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002090 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002091 level = "Unknown\n";
2092 break;
2093 }
2094
2095 return simple_read_from_buffer(user_buf, count, ppos, level,
2096 strlen(level));
2097}
2098
2099static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002100 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002101 .read = dapm_bias_read_file,
2102 .llseek = default_llseek,
2103};
2104
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002105void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2106 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002107{
Mark Brown79fb9382009-08-21 16:38:13 +01002108 struct dentry *d;
2109
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002110 if (!parent)
2111 return;
2112
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002113 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2114
2115 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002116 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002117 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002118 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002119 }
Mark Brown79fb9382009-08-21 16:38:13 +01002120
Mark Brownef49e4f2011-04-04 20:48:13 +09002121 d = debugfs_create_file("bias_level", 0444,
2122 dapm->debugfs_dapm, dapm,
2123 &dapm_bias_fops);
2124 if (!d)
2125 dev_warn(dapm->dev,
2126 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002127}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002128
2129static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2130{
2131 struct snd_soc_dapm_context *dapm = w->dapm;
2132 struct dentry *d;
2133
2134 if (!dapm->debugfs_dapm || !w->name)
2135 return;
2136
2137 d = debugfs_create_file(w->name, 0444,
2138 dapm->debugfs_dapm, w,
2139 &dapm_widget_power_fops);
2140 if (!d)
2141 dev_warn(w->dapm->dev,
2142 "ASoC: Failed to create %s debugfs file\n",
2143 w->name);
2144}
2145
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002146static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2147{
2148 debugfs_remove_recursive(dapm->debugfs_dapm);
2149}
2150
Mark Brown79fb9382009-08-21 16:38:13 +01002151#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002152void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2153 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002154{
2155}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002156
2157static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2158{
2159}
2160
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002161static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2162{
2163}
2164
Mark Brown79fb9382009-08-21 16:38:13 +01002165#endif
2166
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002167/*
2168 * soc_dapm_connect_path() - Connects or disconnects a path
2169 * @path: The path to update
2170 * @connect: The new connect state of the path. True if the path is connected,
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002171 * false if it is disconnected.
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002172 * @reason: The reason why the path changed (for debugging only)
2173 */
2174static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2175 bool connect, const char *reason)
2176{
2177 if (path->connect == connect)
2178 return;
2179
2180 path->connect = connect;
2181 dapm_mark_dirty(path->source, reason);
2182 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002183 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002184}
2185
Richard Purdie2b97eab2006-10-06 18:32:18 +02002186/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002187static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002188 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002189{
2190 struct snd_soc_dapm_path *path;
2191 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002192 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002193
Mark Brownf9fa2b12014-03-06 16:49:11 +08002194 lockdep_assert_held(&card->dapm_mutex);
2195
Richard Purdie2b97eab2006-10-06 18:32:18 +02002196 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002197 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002198 found = 1;
2199 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002200 if (!(strcmp(path->name, e->texts[mux])))
2201 connect = true;
2202 else
2203 connect = false;
2204
2205 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002206 }
2207
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002208 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002209 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002210
Liam Girdwood618dae12012-04-25 12:12:51 +01002211 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002212}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002213
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002214int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002215 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2216 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002217{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002218 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002219 int ret;
2220
Liam Girdwood3cd04342012-03-09 12:02:08 +00002221 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002222 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002223 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002224 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002225 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002226 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002227 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002228 return ret;
2229}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002230EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002231
Milan plzik1b075e32008-01-10 14:39:46 +01002232/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002233static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002234 struct snd_kcontrol *kcontrol,
2235 int connect, int rconnect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002236{
2237 struct snd_soc_dapm_path *path;
2238 int found = 0;
2239
Mark Brownf9fa2b12014-03-06 16:49:11 +08002240 lockdep_assert_held(&card->dapm_mutex);
2241
Richard Purdie2b97eab2006-10-06 18:32:18 +02002242 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002243 dapm_kcontrol_for_each_path(path, kcontrol) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002244 /*
2245 * Ideally this function should support any number of
2246 * paths and channels. But since kcontrols only come
2247 * in mono and stereo variants, we are limited to 2
2248 * channels.
2249 *
2250 * The following code assumes for stereo controls the
2251 * first path (when 'found == 0') is the left channel,
2252 * and all remaining paths (when 'found == 1') are the
2253 * right channel.
2254 *
2255 * A stereo control is signified by a valid 'rconnect'
2256 * value, either 0 for unconnected, or >= 0 for connected.
2257 * This is chosen instead of using snd_soc_volsw_is_stereo,
2258 * so that the behavior of snd_soc_dapm_mixer_update_power
2259 * doesn't change even when the kcontrol passed in is
2260 * stereo.
2261 *
2262 * It passes 'connect' as the path connect status for
2263 * the left channel, and 'rconnect' for the right
2264 * channel.
2265 */
2266 if (found && rconnect >= 0)
2267 soc_dapm_connect_path(path, rconnect, "mixer update");
2268 else
2269 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002270 found = 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002271 }
2272
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002273 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002274 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002275
Liam Girdwood618dae12012-04-25 12:12:51 +01002276 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002277}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002278
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002279int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002280 struct snd_kcontrol *kcontrol, int connect,
2281 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002282{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002283 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002284 int ret;
2285
Liam Girdwood3cd04342012-03-09 12:02:08 +00002286 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002287 card->update = update;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002288 ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002289 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002290 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002291 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002292 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002293 return ret;
2294}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002295EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002296
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002297static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
2298 char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002299{
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002300 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002301 struct snd_soc_dapm_widget *w;
2302 int count = 0;
2303 char *state = "not set";
2304
Mark Brown47325072016-03-18 12:04:23 +00002305 /* card won't be set for the dummy component, as a spot fix
2306 * we're checking for that case specifically here but in future
2307 * we will ensure that the dummy component looks like others.
2308 */
2309 if (!cmpnt->card)
2310 return 0;
2311
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002312 list_for_each_entry(w, &cmpnt->card->widgets, list) {
2313 if (w->dapm != dapm)
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002314 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002315
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002316 /* only display widgets that burn power */
Richard Purdie2b97eab2006-10-06 18:32:18 +02002317 switch (w->id) {
2318 case snd_soc_dapm_hp:
2319 case snd_soc_dapm_mic:
2320 case snd_soc_dapm_spk:
2321 case snd_soc_dapm_line:
2322 case snd_soc_dapm_micbias:
2323 case snd_soc_dapm_dac:
2324 case snd_soc_dapm_adc:
2325 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002326 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002327 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002328 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002329 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002330 case snd_soc_dapm_regulator_supply:
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00002331 case snd_soc_dapm_pinctrl:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002332 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002333 if (w->name)
2334 count += sprintf(buf + count, "%s: %s\n",
2335 w->name, w->power ? "On":"Off");
2336 break;
2337 default:
2338 break;
2339 }
2340 }
2341
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002342 switch (snd_soc_dapm_get_bias_level(dapm)) {
Mark Brown0be98982008-05-19 12:31:28 +02002343 case SND_SOC_BIAS_ON:
2344 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002345 break;
Mark Brown0be98982008-05-19 12:31:28 +02002346 case SND_SOC_BIAS_PREPARE:
2347 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002348 break;
Mark Brown0be98982008-05-19 12:31:28 +02002349 case SND_SOC_BIAS_STANDBY:
2350 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002351 break;
Mark Brown0be98982008-05-19 12:31:28 +02002352 case SND_SOC_BIAS_OFF:
2353 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002354 break;
2355 }
2356 count += sprintf(buf + count, "PM State: %s\n", state);
2357
2358 return count;
2359}
2360
Benoit Cousson44ba2642014-07-08 23:19:36 +02002361/* show dapm widget status in sys fs */
2362static ssize_t dapm_widget_show(struct device *dev,
2363 struct device_attribute *attr, char *buf)
2364{
2365 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00002366 struct snd_soc_dai *codec_dai;
Benoit Cousson44ba2642014-07-08 23:19:36 +02002367 int i, count = 0;
2368
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002369 mutex_lock(&rtd->card->dapm_mutex);
2370
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00002371 for_each_rtd_codec_dai(rtd, i, codec_dai) {
2372 struct snd_soc_component *cmpnt = codec_dai->component;
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002373
2374 count += dapm_widget_show_component(cmpnt, buf + count);
Benoit Cousson44ba2642014-07-08 23:19:36 +02002375 }
2376
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002377 mutex_unlock(&rtd->card->dapm_mutex);
2378
Benoit Cousson44ba2642014-07-08 23:19:36 +02002379 return count;
2380}
2381
Joe Perchesc828a892017-12-19 10:15:08 -08002382static DEVICE_ATTR_RO(dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002383
Takashi Iwaid29697d2015-01-30 20:16:37 +01002384struct attribute *soc_dapm_dev_attrs[] = {
2385 &dev_attr_dapm_widget.attr,
2386 NULL
2387};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002388
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002389static void dapm_free_path(struct snd_soc_dapm_path *path)
2390{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002391 list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
2392 list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002393 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002394 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002395 kfree(path);
2396}
2397
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002398void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2399{
2400 struct snd_soc_dapm_path *p, *next_p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002401 enum snd_soc_dapm_direction dir;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002402
2403 list_del(&w->list);
2404 /*
2405 * remove source and sink paths associated to this widget.
2406 * While removing the path, remove reference to it from both
2407 * source and sink widgets so that path is removed only once.
2408 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002409 snd_soc_dapm_for_each_direction(dir) {
2410 snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
2411 dapm_free_path(p);
2412 }
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002413
2414 kfree(w->kcontrols);
Lars-Peter Clausen48068962015-07-21 18:11:08 +02002415 kfree_const(w->name);
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002416 kfree(w);
2417}
2418
Jyri Sarhafd589a12015-11-10 18:12:42 +02002419void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
2420{
2421 dapm->path_sink_cache.widget = NULL;
2422 dapm->path_source_cache.widget = NULL;
2423}
2424
Richard Purdie2b97eab2006-10-06 18:32:18 +02002425/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002426static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002427{
2428 struct snd_soc_dapm_widget *w, *next_w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002429
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002430 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2431 if (w->dapm != dapm)
2432 continue;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002433 snd_soc_dapm_free_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002434 }
Jyri Sarhafd589a12015-11-10 18:12:42 +02002435 snd_soc_dapm_reset_cache(dapm);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002436}
2437
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002438static struct snd_soc_dapm_widget *dapm_find_widget(
2439 struct snd_soc_dapm_context *dapm, const char *pin,
2440 bool search_other_contexts)
2441{
2442 struct snd_soc_dapm_widget *w;
2443 struct snd_soc_dapm_widget *fallback = NULL;
2444
2445 list_for_each_entry(w, &dapm->card->widgets, list) {
2446 if (!strcmp(w->name, pin)) {
2447 if (w->dapm == dapm)
2448 return w;
2449 else
2450 fallback = w;
2451 }
2452 }
2453
2454 if (search_other_contexts)
2455 return fallback;
2456
2457 return NULL;
2458}
2459
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002460static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002461 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002462{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002463 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002464
Mark Brownf9fa2b12014-03-06 16:49:11 +08002465 dapm_assert_locked(dapm);
2466
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002467 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002468 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002469 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002470 }
2471
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002472 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002473 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002474 dapm_widget_invalidate_input_paths(w);
2475 dapm_widget_invalidate_output_paths(w);
2476 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002477
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002478 w->connected = status;
2479 if (status == 0)
2480 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002481
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002482 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002483}
2484
Richard Purdie2b97eab2006-10-06 18:32:18 +02002485/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002486 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2487 * @dapm: DAPM context
2488 *
2489 * Walks all dapm audio paths and powers widgets according to their
2490 * stream or path usage.
2491 *
2492 * Requires external locking.
2493 *
2494 * Returns 0 for success.
2495 */
2496int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2497{
2498 /*
2499 * Suppress early reports (eg, jacks syncing their state) to avoid
2500 * silly DAPM runs during card startup.
2501 */
2502 if (!dapm->card || !dapm->card->instantiated)
2503 return 0;
2504
2505 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2506}
2507EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2508
2509/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002510 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002511 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002512 *
2513 * Walks all dapm audio paths and powers widgets according to their
2514 * stream or path usage.
2515 *
2516 * Returns 0 for success.
2517 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002518int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002519{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002520 int ret;
2521
Liam Girdwood3cd04342012-03-09 12:02:08 +00002522 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002523 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002524 mutex_unlock(&dapm->card->dapm_mutex);
2525 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002526}
Liam Girdwooda5302182008-07-07 13:35:17 +01002527EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002528
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002529/*
2530 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2531 * @w: The widget for which to update the flags
2532 *
2533 * Some widgets have a dynamic category which depends on which neighbors they
2534 * are connected to. This function update the category for these widgets.
2535 *
2536 * This function must be called whenever a path is added or removed to a widget.
2537 */
2538static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2539{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002540 enum snd_soc_dapm_direction dir;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002541 struct snd_soc_dapm_path *p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002542 unsigned int ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002543
2544 switch (w->id) {
2545 case snd_soc_dapm_input:
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002546 /* On a fully routed card an input is never a source */
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002547 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002548 return;
2549 ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002550 snd_soc_dapm_widget_for_each_source_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002551 if (p->source->id == snd_soc_dapm_micbias ||
2552 p->source->id == snd_soc_dapm_mic ||
2553 p->source->id == snd_soc_dapm_line ||
2554 p->source->id == snd_soc_dapm_output) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002555 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002556 break;
2557 }
2558 }
2559 break;
2560 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002561 /* On a fully routed card a output is never a sink */
2562 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002563 return;
2564 ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002565 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002566 if (p->sink->id == snd_soc_dapm_spk ||
2567 p->sink->id == snd_soc_dapm_hp ||
2568 p->sink->id == snd_soc_dapm_line ||
2569 p->sink->id == snd_soc_dapm_input) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002570 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002571 break;
2572 }
2573 }
2574 break;
2575 case snd_soc_dapm_line:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002576 ep = 0;
2577 snd_soc_dapm_for_each_direction(dir) {
2578 if (!list_empty(&w->edges[dir]))
2579 ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
2580 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002581 break;
2582 default:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002583 return;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002584 }
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002585
2586 w->is_ep = ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002587}
2588
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002589static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2590 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2591 const char *control)
2592{
2593 bool dynamic_source = false;
2594 bool dynamic_sink = false;
2595
2596 if (!control)
2597 return 0;
2598
2599 switch (source->id) {
2600 case snd_soc_dapm_demux:
2601 dynamic_source = true;
2602 break;
2603 default:
2604 break;
2605 }
2606
2607 switch (sink->id) {
2608 case snd_soc_dapm_mux:
2609 case snd_soc_dapm_switch:
2610 case snd_soc_dapm_mixer:
2611 case snd_soc_dapm_mixer_named_ctl:
2612 dynamic_sink = true;
2613 break;
2614 default:
2615 break;
2616 }
2617
2618 if (dynamic_source && dynamic_sink) {
2619 dev_err(dapm->dev,
2620 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2621 source->name, control, sink->name);
2622 return -EINVAL;
2623 } else if (!dynamic_source && !dynamic_sink) {
2624 dev_err(dapm->dev,
2625 "Control not supported for path %s -> [%s] -> %s\n",
2626 source->name, control, sink->name);
2627 return -EINVAL;
2628 }
2629
2630 return 0;
2631}
2632
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002633static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2634 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2635 const char *control,
2636 int (*connected)(struct snd_soc_dapm_widget *source,
2637 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002638{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002639 struct snd_soc_dapm_widget *widgets[2];
2640 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002641 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002642 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002643
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002644 if (wsink->is_supply && !wsource->is_supply) {
2645 dev_err(dapm->dev,
2646 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2647 wsource->name, wsink->name);
2648 return -EINVAL;
2649 }
2650
2651 if (connected && !wsource->is_supply) {
2652 dev_err(dapm->dev,
2653 "connected() callback only supported for supply widgets (%s -> %s)\n",
2654 wsource->name, wsink->name);
2655 return -EINVAL;
2656 }
2657
2658 if (wsource->is_supply && control) {
2659 dev_err(dapm->dev,
2660 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2661 wsource->name, control, wsink->name);
2662 return -EINVAL;
2663 }
2664
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002665 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2666 if (ret)
2667 return ret;
2668
Richard Purdie2b97eab2006-10-06 18:32:18 +02002669 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2670 if (!path)
2671 return -ENOMEM;
2672
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002673 path->node[SND_SOC_DAPM_DIR_IN] = wsource;
2674 path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
2675 widgets[SND_SOC_DAPM_DIR_IN] = wsource;
2676 widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
2677
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002678 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002679 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002680 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002681
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002682 if (wsource->is_supply || wsink->is_supply)
2683 path->is_supply = 1;
2684
Richard Purdie2b97eab2006-10-06 18:32:18 +02002685 /* connect static paths */
2686 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002687 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002688 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002689 switch (wsource->id) {
2690 case snd_soc_dapm_demux:
2691 ret = dapm_connect_mux(dapm, path, control, wsource);
2692 if (ret)
2693 goto err;
2694 break;
2695 default:
2696 break;
2697 }
2698
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002699 switch (wsink->id) {
2700 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002701 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002702 if (ret != 0)
2703 goto err;
2704 break;
2705 case snd_soc_dapm_switch:
2706 case snd_soc_dapm_mixer:
2707 case snd_soc_dapm_mixer_named_ctl:
2708 ret = dapm_connect_mixer(dapm, path, control);
2709 if (ret != 0)
2710 goto err;
2711 break;
2712 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002713 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002714 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002715 }
2716
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002717 list_add(&path->list, &dapm->card->paths);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002718 snd_soc_dapm_for_each_direction(dir)
2719 list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002720
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002721 snd_soc_dapm_for_each_direction(dir) {
2722 dapm_update_widget_flags(widgets[dir]);
2723 dapm_mark_dirty(widgets[dir], "Route added");
2724 }
Mark Brownfabd0382012-07-05 17:20:06 +01002725
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002726 if (dapm->card->instantiated && path->connect)
2727 dapm_path_invalidate(path);
2728
Richard Purdie2b97eab2006-10-06 18:32:18 +02002729 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002730err:
2731 kfree(path);
2732 return ret;
2733}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002734
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002735static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002736 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002737{
2738 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2739 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2740 const char *sink;
2741 const char *source;
2742 char prefixed_sink[80];
2743 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002744 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002745 int ret;
2746
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002747 prefix = soc_dapm_prefix(dapm);
2748 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002749 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002750 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002751 sink = prefixed_sink;
2752 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002753 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002754 source = prefixed_source;
2755 } else {
2756 sink = route->sink;
2757 source = route->source;
2758 }
2759
Charles Keepax45a110a2015-05-11 13:50:30 +01002760 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2761 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2762
2763 if (wsink && wsource)
2764 goto skip_search;
2765
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002766 /*
2767 * find src and dest widgets over all widgets but favor a widget from
2768 * current DAPM context
2769 */
2770 list_for_each_entry(w, &dapm->card->widgets, list) {
2771 if (!wsink && !(strcmp(w->name, sink))) {
2772 wtsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002773 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002774 wsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002775 if (wsource)
2776 break;
2777 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002778 continue;
2779 }
2780 if (!wsource && !(strcmp(w->name, source))) {
2781 wtsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002782 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002783 wsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002784 if (wsink)
2785 break;
2786 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002787 }
2788 }
2789 /* use widget from another DAPM context if not found from this */
2790 if (!wsink)
2791 wsink = wtsink;
2792 if (!wsource)
2793 wsource = wtsource;
2794
2795 if (wsource == NULL) {
2796 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2797 route->source);
2798 return -ENODEV;
2799 }
2800 if (wsink == NULL) {
2801 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2802 route->sink);
2803 return -ENODEV;
2804 }
2805
Charles Keepax45a110a2015-05-11 13:50:30 +01002806skip_search:
2807 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2808 dapm_wcache_update(&dapm->path_source_cache, wsource);
2809
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002810 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2811 route->connected);
2812 if (ret)
2813 goto err;
2814
2815 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002816err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002817 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002818 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002819 return ret;
2820}
Mark Brown105f1c22008-05-13 14:52:19 +02002821
Mark Brownefcc3c62012-07-05 17:24:19 +01002822static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2823 const struct snd_soc_dapm_route *route)
2824{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002825 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002826 struct snd_soc_dapm_path *path, *p;
2827 const char *sink;
2828 const char *source;
2829 char prefixed_sink[80];
2830 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002831 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002832
2833 if (route->control) {
2834 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002835 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002836 return -EINVAL;
2837 }
2838
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002839 prefix = soc_dapm_prefix(dapm);
2840 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002841 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002842 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002843 sink = prefixed_sink;
2844 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002845 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002846 source = prefixed_source;
2847 } else {
2848 sink = route->sink;
2849 source = route->source;
2850 }
2851
2852 path = NULL;
2853 list_for_each_entry(p, &dapm->card->paths, list) {
2854 if (strcmp(p->source->name, source) != 0)
2855 continue;
2856 if (strcmp(p->sink->name, sink) != 0)
2857 continue;
2858 path = p;
2859 break;
2860 }
2861
2862 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002863 wsource = path->source;
2864 wsink = path->sink;
2865
2866 dapm_mark_dirty(wsource, "Route removed");
2867 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002868 if (path->connect)
2869 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002870
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002871 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002872
2873 /* Update any path related flags */
2874 dapm_update_widget_flags(wsource);
2875 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002876 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002877 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002878 source, sink);
2879 }
2880
2881 return 0;
2882}
2883
Mark Brown105f1c22008-05-13 14:52:19 +02002884/**
Mark Brown105f1c22008-05-13 14:52:19 +02002885 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002886 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002887 * @route: audio routes
2888 * @num: number of routes
2889 *
2890 * Connects 2 dapm widgets together via a named audio path. The sink is
2891 * the widget receiving the audio signal, whilst the source is the sender
2892 * of the audio signal.
2893 *
2894 * Returns 0 for success else error. On error all resources can be freed
2895 * with a call to snd_soc_card_free().
2896 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002897int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002898 const struct snd_soc_dapm_route *route, int num)
2899{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002900 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002901
Stuart Hendersonf19c1812017-09-21 11:02:12 +01002902 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown105f1c22008-05-13 14:52:19 +02002903 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002904 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002905 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002906 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2907 route->source,
2908 route->control ? route->control : "direct",
2909 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002910 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002911 }
2912 route++;
2913 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002914 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002915
Dan Carpenter60884c22012-04-13 22:25:43 +03002916 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002917}
2918EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2919
Mark Brownefcc3c62012-07-05 17:24:19 +01002920/**
2921 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2922 * @dapm: DAPM context
2923 * @route: audio routes
2924 * @num: number of routes
2925 *
2926 * Removes routes from the DAPM context.
2927 */
2928int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2929 const struct snd_soc_dapm_route *route, int num)
2930{
Rajan Vajae066ea22016-02-11 11:23:35 +05302931 int i;
Mark Brownefcc3c62012-07-05 17:24:19 +01002932
Stuart Hendersonf19c1812017-09-21 11:02:12 +01002933 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownefcc3c62012-07-05 17:24:19 +01002934 for (i = 0; i < num; i++) {
2935 snd_soc_dapm_del_route(dapm, route);
2936 route++;
2937 }
2938 mutex_unlock(&dapm->card->dapm_mutex);
2939
Rajan Vajae066ea22016-02-11 11:23:35 +05302940 return 0;
Mark Brownefcc3c62012-07-05 17:24:19 +01002941}
2942EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2943
Mark Brownbf3a9e12011-06-13 16:42:29 +01002944static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2945 const struct snd_soc_dapm_route *route)
2946{
2947 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2948 route->source,
2949 true);
2950 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2951 route->sink,
2952 true);
2953 struct snd_soc_dapm_path *path;
2954 int count = 0;
2955
2956 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002957 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002958 route->source);
2959 return -ENODEV;
2960 }
2961
2962 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002963 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002964 route->sink);
2965 return -ENODEV;
2966 }
2967
2968 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002969 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002970 route->source, route->sink);
2971
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002972 snd_soc_dapm_widget_for_each_sink_path(source, path) {
Mark Brownbf3a9e12011-06-13 16:42:29 +01002973 if (path->sink == sink) {
2974 path->weak = 1;
2975 count++;
2976 }
2977 }
2978
2979 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002980 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002981 route->source, route->sink);
2982 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002983 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002984 count, route->source, route->sink);
2985
2986 return 0;
2987}
2988
2989/**
2990 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2991 * @dapm: DAPM context
2992 * @route: audio routes
2993 * @num: number of routes
2994 *
2995 * Mark existing routes matching those specified in the passed array
2996 * as being weak, meaning that they are ignored for the purpose of
2997 * power decisions. The main intended use case is for sidetone paths
2998 * which couple audio between other independent paths if they are both
2999 * active in order to make the combination work better at the user
3000 * level but which aren't intended to be "used".
3001 *
3002 * Note that CODEC drivers should not use this as sidetone type paths
3003 * can frequently also be used as bypass paths.
3004 */
3005int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
3006 const struct snd_soc_dapm_route *route, int num)
3007{
3008 int i, err;
3009 int ret = 0;
3010
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003011 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01003012 for (i = 0; i < num; i++) {
3013 err = snd_soc_dapm_weak_route(dapm, route);
3014 if (err)
3015 ret = err;
3016 route++;
3017 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003018 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01003019
3020 return ret;
3021}
3022EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
3023
Mark Brown105f1c22008-05-13 14:52:19 +02003024/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02003025 * snd_soc_dapm_new_widgets - add new dapm widgets
Jonathan Corbet628536e2015-08-25 01:14:48 -06003026 * @card: card to be checked for new dapm widgets
Richard Purdie2b97eab2006-10-06 18:32:18 +02003027 *
3028 * Checks the codec for any new dapm widgets and creates them if found.
3029 *
3030 * Returns 0 for success.
3031 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02003032int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003033{
3034 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00003035 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003036
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003037 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003038
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003039 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003040 {
3041 if (w->new)
3042 continue;
3043
Stephen Warrenfad59882011-04-28 17:37:59 -06003044 if (w->num_kcontrols) {
Kees Cook6396bb22018-06-12 14:03:40 -07003045 w->kcontrols = kcalloc(w->num_kcontrols,
Stephen Warrenfad59882011-04-28 17:37:59 -06003046 sizeof(struct snd_kcontrol *),
3047 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003048 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003049 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06003050 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003051 }
Stephen Warrenfad59882011-04-28 17:37:59 -06003052 }
3053
Richard Purdie2b97eab2006-10-06 18:32:18 +02003054 switch(w->id) {
3055 case snd_soc_dapm_switch:
3056 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00003057 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003058 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003059 break;
3060 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003061 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003062 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003063 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003064 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06003065 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003066 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003067 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003068 case snd_soc_dapm_dai_link:
3069 dapm_new_dai_link(w);
3070 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01003071 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003072 break;
3073 }
Mark Brownb66a70d2011-02-09 18:04:11 +00003074
3075 /* Read the initial power state from the device */
3076 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003077 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08003078 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003079 val &= w->mask;
3080 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00003081 w->power = 1;
3082 }
3083
Richard Purdie2b97eab2006-10-06 18:32:18 +02003084 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003085
Mark Brown7508b122011-10-05 12:09:12 +01003086 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003087 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003088 }
3089
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003090 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
3091 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003092 return 0;
3093}
3094EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
3095
3096/**
3097 * snd_soc_dapm_get_volsw - dapm mixer get callback
3098 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003099 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003100 *
3101 * Callback to get the value of a dapm mixer control.
3102 *
3103 * Returns 0 for success.
3104 */
3105int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
3106 struct snd_ctl_elem_value *ucontrol)
3107{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003108 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3109 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003110 struct soc_mixer_control *mc =
3111 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003112 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003113 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003114 int max = mc->max;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003115 unsigned int width = fls(max);
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003116 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003117 unsigned int invert = mc->invert;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003118 unsigned int reg_val, val, rval = 0;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003119 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003120
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003121 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003122 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003123 ret = soc_dapm_read(dapm, reg, &reg_val);
3124 val = (reg_val >> shift) & mask;
3125
3126 if (ret == 0 && reg != mc->rreg)
3127 ret = soc_dapm_read(dapm, mc->rreg, &reg_val);
3128
3129 if (snd_soc_volsw_is_stereo(mc))
3130 rval = (reg_val >> mc->rshift) & mask;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003131 } else {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003132 reg_val = dapm_kcontrol_get_value(kcontrol);
3133 val = reg_val & mask;
3134
3135 if (snd_soc_volsw_is_stereo(mc))
3136 rval = (reg_val >> width) & mask;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003137 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003138 mutex_unlock(&card->dapm_mutex);
3139
Chen-Yu Tsai01ad5e72016-08-27 19:27:58 +08003140 if (ret)
3141 return ret;
3142
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003143 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003144 ucontrol->value.integer.value[0] = max - val;
3145 else
3146 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003147
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003148 if (snd_soc_volsw_is_stereo(mc)) {
3149 if (invert)
3150 ucontrol->value.integer.value[1] = max - rval;
3151 else
3152 ucontrol->value.integer.value[1] = rval;
3153 }
3154
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003155 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003156}
3157EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3158
3159/**
3160 * snd_soc_dapm_put_volsw - dapm mixer set callback
3161 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003162 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003163 *
3164 * Callback to set the value of a dapm mixer control.
3165 *
3166 * Returns 0 for success.
3167 */
3168int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3169 struct snd_ctl_elem_value *ucontrol)
3170{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003171 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3172 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003173 struct soc_mixer_control *mc =
3174 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003175 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003176 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003177 int max = mc->max;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003178 unsigned int width = fls(max);
3179 unsigned int mask = (1 << width) - 1;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003180 unsigned int invert = mc->invert;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003181 unsigned int val, rval = 0;
3182 int connect, rconnect = -1, change, reg_change = 0;
Fabio Estevam33d92452018-02-14 13:39:05 -02003183 struct snd_soc_dapm_update update = {};
Nenghua Cao52765972013-12-13 20:13:49 +08003184 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003185
3186 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003187 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003188
3189 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003190 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003191
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003192 if (snd_soc_volsw_is_stereo(mc)) {
3193 rval = (ucontrol->value.integer.value[1] & mask);
3194 rconnect = !!rval;
3195 if (invert)
3196 rval = max - rval;
3197 }
3198
Liam Girdwood3cd04342012-03-09 12:02:08 +00003199 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003200
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003201 /* This assumes field width < (bits in unsigned int / 2) */
3202 if (width > sizeof(unsigned int) * 8 / 2)
3203 dev_warn(dapm->dev,
3204 "ASoC: control %s field width limit exceeded\n",
3205 kcontrol->id.name);
3206 change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
Mark Brown283375c2009-12-07 18:09:03 +00003207
Jarkko Nikula18626c72014-06-09 14:20:29 +03003208 if (reg != SND_SOC_NOPM) {
Jarkko Nikula18626c72014-06-09 14:20:29 +03003209 val = val << shift;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003210 rval = rval << mc->rshift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003211
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003212 reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
3213
3214 if (snd_soc_volsw_is_stereo(mc))
3215 reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
3216 mask << mc->rshift,
3217 rval);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003218 }
3219
3220 if (change || reg_change) {
3221 if (reg_change) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003222 if (snd_soc_volsw_is_stereo(mc)) {
3223 update.has_second_set = true;
3224 update.reg2 = mc->rreg;
3225 update.mask2 = mask << mc->rshift;
3226 update.val2 = rval;
3227 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003228 update.kcontrol = kcontrol;
3229 update.reg = reg;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003230 update.mask = mask << shift;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003231 update.val = val;
3232 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003233 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003234 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003235
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003236 ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
3237 rconnect);
Mark Brown97404f22010-12-14 16:13:57 +00003238
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003239 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003240 }
3241
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003242 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003243
3244 if (ret > 0)
3245 soc_dpcm_runtime_update(card);
3246
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003247 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003248}
3249EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3250
3251/**
3252 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3253 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003254 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003255 *
3256 * Callback to get the value of a dapm enumerated double mixer control.
3257 *
3258 * Returns 0 for success.
3259 */
3260int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3261 struct snd_ctl_elem_value *ucontrol)
3262{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003263 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003264 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003265 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003266 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003267
Charles Keepax561ed682015-05-01 12:37:26 +01003268 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3269 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003270 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003271 if (ret) {
3272 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003273 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003274 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003275 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003276 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003277 }
Charles Keepax561ed682015-05-01 12:37:26 +01003278 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003279
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003280 val = (reg_val >> e->shift_l) & e->mask;
3281 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3282 if (e->shift_l != e->shift_r) {
3283 val = (reg_val >> e->shift_r) & e->mask;
3284 val = snd_soc_enum_val_to_item(e, val);
3285 ucontrol->value.enumerated.item[1] = val;
3286 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003287
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003288 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003289}
3290EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3291
3292/**
3293 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3294 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003295 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003296 *
3297 * Callback to set the value of a dapm enumerated double mixer control.
3298 *
3299 * Returns 0 for success.
3300 */
3301int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3302 struct snd_ctl_elem_value *ucontrol)
3303{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003304 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3305 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003306 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003307 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003308 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003309 unsigned int mask;
Fabio Estevam33d92452018-02-14 13:39:05 -02003310 struct snd_soc_dapm_update update = {};
Nenghua Cao52765972013-12-13 20:13:49 +08003311 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003312
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003313 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003314 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003315
3316 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003317 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003318 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003319 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003320 return -EINVAL;
Chen-Yu Tsai071133a2016-08-27 19:27:59 +08003321 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003322 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003323 }
3324
Liam Girdwood3cd04342012-03-09 12:02:08 +00003325 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003326
Charles Keepax561ed682015-05-01 12:37:26 +01003327 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003328
Charles Keepax561ed682015-05-01 12:37:26 +01003329 if (e->reg != SND_SOC_NOPM)
3330 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3331
3332 if (change || reg_change) {
3333 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003334 update.kcontrol = kcontrol;
3335 update.reg = e->reg;
3336 update.mask = mask;
3337 update.val = val;
3338 card->update = &update;
3339 }
Charles Keepax561ed682015-05-01 12:37:26 +01003340 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003341
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003342 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003343
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003344 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003345 }
3346
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003347 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003348
3349 if (ret > 0)
3350 soc_dpcm_runtime_update(card);
3351
Mark Brown97404f22010-12-14 16:13:57 +00003352 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003353}
3354EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3355
3356/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003357 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3358 *
3359 * @kcontrol: mixer control
3360 * @uinfo: control element information
3361 *
3362 * Callback to provide information about a pin switch control.
3363 */
3364int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3365 struct snd_ctl_elem_info *uinfo)
3366{
3367 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3368 uinfo->count = 1;
3369 uinfo->value.integer.min = 0;
3370 uinfo->value.integer.max = 1;
3371
3372 return 0;
3373}
3374EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3375
3376/**
3377 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3378 *
3379 * @kcontrol: mixer control
3380 * @ucontrol: Value
3381 */
3382int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3383 struct snd_ctl_elem_value *ucontrol)
3384{
Mark Brown48a8c392012-02-14 17:11:15 -08003385 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003386 const char *pin = (const char *)kcontrol->private_value;
3387
Liam Girdwood3cd04342012-03-09 12:02:08 +00003388 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003389
3390 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003391 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003392
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003393 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003394
3395 return 0;
3396}
3397EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3398
3399/**
3400 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3401 *
3402 * @kcontrol: mixer control
3403 * @ucontrol: Value
3404 */
3405int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3406 struct snd_ctl_elem_value *ucontrol)
3407{
Mark Brown48a8c392012-02-14 17:11:15 -08003408 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003409 const char *pin = (const char *)kcontrol->private_value;
3410
Mark Brown8b37dbd2009-02-28 21:14:20 +00003411 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003412 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003413 else
Mark Brown48a8c392012-02-14 17:11:15 -08003414 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003415
Mark Brown48a8c392012-02-14 17:11:15 -08003416 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003417 return 0;
3418}
3419EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3420
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +01003421struct snd_soc_dapm_widget *
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003422snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003423 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003424{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003425 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003426 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003427 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003428 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003429
3430 if ((w = dapm_cnew_widget(widget)) == NULL)
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003431 return ERR_PTR(-ENOMEM);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003432
Mark Brown62ea8742012-01-21 21:14:48 +00003433 switch (w->id) {
3434 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003435 w->regulator = devm_regulator_get(dapm->dev, w->name);
3436 if (IS_ERR(w->regulator)) {
3437 ret = PTR_ERR(w->regulator);
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003438 goto request_failed;
Mark Brown62ea8742012-01-21 21:14:48 +00003439 }
Mark Brown8784c772013-01-10 19:33:47 +00003440
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003441 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003442 ret = regulator_allow_bypass(w->regulator, true);
3443 if (ret != 0)
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003444 dev_warn(dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003445 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003446 w->name, ret);
3447 }
Mark Brown62ea8742012-01-21 21:14:48 +00003448 break;
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00003449 case snd_soc_dapm_pinctrl:
3450 w->pinctrl = devm_pinctrl_get(dapm->dev);
Charles Keepaxa5cd7e92018-08-28 14:35:03 +01003451 if (IS_ERR(w->pinctrl)) {
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00003452 ret = PTR_ERR(w->pinctrl);
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003453 goto request_failed;
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00003454 }
3455 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003456 case snd_soc_dapm_clock_supply:
Mark Brown695594f12012-06-04 08:14:13 +01003457 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003458 if (IS_ERR(w->clk)) {
3459 ret = PTR_ERR(w->clk);
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003460 goto request_failed;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003461 }
3462 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003463 default:
3464 break;
3465 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003466
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003467 prefix = soc_dapm_prefix(dapm);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003468 if (prefix)
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003469 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003470 else
Lars-Peter Clausen48068962015-07-21 18:11:08 +02003471 w->name = kstrdup_const(widget->name, GFP_KERNEL);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003472 if (w->name == NULL) {
3473 kfree(w);
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003474 return ERR_PTR(-ENOMEM);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003475 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003476
Mark Brown7ca3a182011-10-08 14:04:50 +01003477 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003478 case snd_soc_dapm_mic:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003479 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003480 w->power_check = dapm_generic_check_power;
3481 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003482 case snd_soc_dapm_input:
3483 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003484 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003485 w->power_check = dapm_generic_check_power;
3486 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003487 case snd_soc_dapm_spk:
3488 case snd_soc_dapm_hp:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003489 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003490 w->power_check = dapm_generic_check_power;
3491 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003492 case snd_soc_dapm_output:
3493 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003494 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003495 w->power_check = dapm_generic_check_power;
3496 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003497 case snd_soc_dapm_vmid:
3498 case snd_soc_dapm_siggen:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003499 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003500 w->power_check = dapm_always_on_check_power;
3501 break;
Vinod Koul56b44372015-11-23 21:22:30 +05303502 case snd_soc_dapm_sink:
3503 w->is_ep = SND_SOC_DAPM_EP_SINK;
3504 w->power_check = dapm_always_on_check_power;
3505 break;
3506
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003507 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003508 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003509 case snd_soc_dapm_switch:
3510 case snd_soc_dapm_mixer:
3511 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003512 case snd_soc_dapm_adc:
3513 case snd_soc_dapm_aif_out:
3514 case snd_soc_dapm_dac:
3515 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003516 case snd_soc_dapm_pga:
3517 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003518 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003519 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003520 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003521 case snd_soc_dapm_dai_out:
3522 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003523 w->power_check = dapm_generic_check_power;
3524 break;
3525 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003526 case snd_soc_dapm_regulator_supply:
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00003527 case snd_soc_dapm_pinctrl:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003528 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003529 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003530 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003531 w->power_check = dapm_supply_check_power;
3532 break;
3533 default:
3534 w->power_check = dapm_always_on_check_power;
3535 break;
3536 }
3537
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003538 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003539 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003540 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003541 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003542
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003543 snd_soc_dapm_for_each_direction(dir) {
3544 INIT_LIST_HEAD(&w->edges[dir]);
3545 w->endpoints[dir] = -1;
3546 }
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003547
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02003548 /* machine layer sets up unconnected pins and insertions */
Richard Purdie2b97eab2006-10-06 18:32:18 +02003549 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003550 return w;
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003551
3552request_failed:
3553 if (ret != -EPROBE_DEFER)
3554 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
3555 w->name, ret);
3556
3557 return ERR_PTR(ret);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003558}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003559
3560/**
Charles Keepax94e630a2018-09-05 15:20:59 +01003561 * snd_soc_dapm_new_control - create new dapm control
3562 * @dapm: DAPM context
3563 * @widget: widget template
3564 *
3565 * Creates new DAPM control based upon a template.
3566 *
3567 * Returns a widget pointer on success or an error pointer on failure
3568 */
3569struct snd_soc_dapm_widget *
3570snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3571 const struct snd_soc_dapm_widget *widget)
3572{
3573 struct snd_soc_dapm_widget *w;
3574
3575 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3576 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3577 mutex_unlock(&dapm->card->dapm_mutex);
3578
3579 return w;
3580}
3581EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
3582
3583/**
Mark Brown4ba13272008-05-13 14:51:19 +02003584 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003585 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003586 * @widget: widget array
3587 * @num: number of widgets
3588 *
3589 * Creates new DAPM controls based upon the templates.
3590 *
3591 * Returns 0 for success else error.
3592 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003593int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003594 const struct snd_soc_dapm_widget *widget,
3595 int num)
3596{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003597 struct snd_soc_dapm_widget *w;
3598 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003599 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003600
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003601 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003602 for (i = 0; i < num; i++) {
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003603 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Linus Walleij37e1df82017-01-13 10:23:52 +01003604 if (IS_ERR(w)) {
3605 ret = PTR_ERR(w);
Dan Carpenter60884c22012-04-13 22:25:43 +03003606 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003607 }
Mark Brown4ba13272008-05-13 14:51:19 +02003608 widget++;
3609 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003610 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003611 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003612}
3613EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3614
Mark Brownc74184e2012-04-04 22:12:09 +01003615static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3616 struct snd_kcontrol *kcontrol, int event)
3617{
Charles Keepax4a75aae2018-09-05 15:21:01 +01003618 struct snd_soc_dapm_path *path;
Mark Brownc74184e2012-04-04 22:12:09 +01003619 struct snd_soc_dai *source, *sink;
Charles Keepax249dc492018-08-15 13:11:35 +01003620 struct snd_soc_pcm_runtime *rtd = w->priv;
Charles Keepax243bcfa2018-09-05 15:21:02 +01003621 const struct snd_soc_pcm_stream *config;
Mark Brownc74184e2012-04-04 22:12:09 +01003622 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003623 struct snd_pcm_hw_params *params = NULL;
Nicolin Chen8053f212016-07-26 14:55:51 -07003624 struct snd_pcm_runtime *runtime = NULL;
Takashi Iwai3ba66fe2018-07-25 22:43:26 +02003625 unsigned int fmt;
Charles Keepaxfc269c02018-09-06 17:41:55 +01003626 int ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003627
Charles Keepax243bcfa2018-09-05 15:21:02 +01003628 config = rtd->dai_link->params + rtd->params_select;
3629
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003630 if (WARN_ON(!config) ||
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003631 WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3632 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003633 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003634
Mark Brownc74184e2012-04-04 22:12:09 +01003635 /* Be a little careful as we don't want to overflow the mask array */
3636 if (config->formats) {
3637 fmt = ffs(config->formats) - 1;
3638 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003639 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003640 config->formats);
3641 fmt = 0;
3642 }
3643
3644 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003645 params = kzalloc(sizeof(*params), GFP_KERNEL);
3646 if (!params) {
3647 ret = -ENOMEM;
3648 goto out;
3649 }
3650 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003651
Mark Brown9747cec2012-04-26 19:12:21 +01003652 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003653 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003654 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003655 config->rate_max;
3656
Mark Brown9747cec2012-04-26 19:12:21 +01003657 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003658 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003659 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003660 = config->channels_max;
3661
3662 memset(&substream, 0, sizeof(substream));
3663
Nicolin Chen8053f212016-07-26 14:55:51 -07003664 /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */
3665 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
3666 if (!runtime) {
3667 ret = -ENOMEM;
3668 goto out;
3669 }
3670 substream.runtime = runtime;
Charles Keepax249dc492018-08-15 13:11:35 +01003671 substream.private_data = rtd;
Nicolin Chen8053f212016-07-26 14:55:51 -07003672
Mark Brownc74184e2012-04-04 22:12:09 +01003673 switch (event) {
3674 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003675 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
Charles Keepax4a75aae2018-09-05 15:21:01 +01003676 snd_soc_dapm_widget_for_each_source_path(w, path) {
3677 source = path->source->priv;
3678
3679 if (source->driver->ops->startup) {
3680 ret = source->driver->ops->startup(&substream,
3681 source);
3682 if (ret < 0) {
3683 dev_err(source->dev,
3684 "ASoC: startup() failed: %d\n",
3685 ret);
3686 goto out;
3687 }
3688 source->active++;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303689 }
Charles Keepax4a75aae2018-09-05 15:21:01 +01003690 ret = soc_dai_hw_params(&substream, params, source);
3691 if (ret < 0)
3692 goto out;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303693 }
Mark Brownc74184e2012-04-04 22:12:09 +01003694
Benoit Cousson93e69582014-07-08 23:19:38 +02003695 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
Charles Keepax4a75aae2018-09-05 15:21:01 +01003696 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3697 sink = path->sink->priv;
3698
3699 if (sink->driver->ops->startup) {
3700 ret = sink->driver->ops->startup(&substream,
3701 sink);
3702 if (ret < 0) {
3703 dev_err(sink->dev,
3704 "ASoC: startup() failed: %d\n",
3705 ret);
3706 goto out;
3707 }
3708 sink->active++;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303709 }
Charles Keepax4a75aae2018-09-05 15:21:01 +01003710 ret = soc_dai_hw_params(&substream, params, sink);
3711 if (ret < 0)
3712 goto out;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303713 }
Mark Brownc74184e2012-04-04 22:12:09 +01003714 break;
3715
3716 case SND_SOC_DAPM_POST_PMU:
Charles Keepax4a75aae2018-09-05 15:21:01 +01003717 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3718 sink = path->sink->priv;
3719
3720 ret = snd_soc_dai_digital_mute(sink, 0,
3721 SNDRV_PCM_STREAM_PLAYBACK);
3722 if (ret != 0 && ret != -ENOTSUPP)
3723 dev_warn(sink->dev,
3724 "ASoC: Failed to unmute: %d\n", ret);
3725 ret = 0;
3726 }
Mark Brownc74184e2012-04-04 22:12:09 +01003727 break;
3728
3729 case SND_SOC_DAPM_PRE_PMD:
Charles Keepax4a75aae2018-09-05 15:21:01 +01003730 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3731 sink = path->sink->priv;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303732
Charles Keepax4a75aae2018-09-05 15:21:01 +01003733 ret = snd_soc_dai_digital_mute(sink, 1,
3734 SNDRV_PCM_STREAM_PLAYBACK);
3735 if (ret != 0 && ret != -ENOTSUPP)
3736 dev_warn(sink->dev,
3737 "ASoC: Failed to mute: %d\n", ret);
3738 ret = 0;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303739 }
3740
Charles Keepax4a75aae2018-09-05 15:21:01 +01003741 snd_soc_dapm_widget_for_each_source_path(w, path) {
3742 source = path->source->priv;
3743
3744 source->active--;
3745 if (source->driver->ops->shutdown) {
3746 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3747 source->driver->ops->shutdown(&substream,
3748 source);
3749 }
3750 }
3751
3752 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3753 sink = path->sink->priv;
3754
3755 sink->active--;
3756 if (sink->driver->ops->shutdown) {
3757 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3758 sink->driver->ops->shutdown(&substream, sink);
3759 }
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303760 }
Mark Brownc74184e2012-04-04 22:12:09 +01003761 break;
3762
3763 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003764 WARN(1, "Unknown event %d\n", event);
Sudip Mukherjee75881df2015-09-10 18:01:44 +05303765 ret = -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003766 }
3767
Mark Brown9747cec2012-04-26 19:12:21 +01003768out:
Nicolin Chen8053f212016-07-26 14:55:51 -07003769 kfree(runtime);
Mark Brown9747cec2012-04-26 19:12:21 +01003770 kfree(params);
3771 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003772}
3773
Nikesh Oswalc6615082015-02-02 17:06:44 +00003774static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3775 struct snd_ctl_elem_value *ucontrol)
3776{
3777 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
Charles Keepax243bcfa2018-09-05 15:21:02 +01003778 struct snd_soc_pcm_runtime *rtd = w->priv;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003779
Charles Keepax243bcfa2018-09-05 15:21:02 +01003780 ucontrol->value.enumerated.item[0] = rtd->params_select;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003781
3782 return 0;
3783}
3784
3785static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3786 struct snd_ctl_elem_value *ucontrol)
3787{
3788 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
Charles Keepax243bcfa2018-09-05 15:21:02 +01003789 struct snd_soc_pcm_runtime *rtd = w->priv;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003790
3791 /* Can't change the config when widget is already powered */
3792 if (w->power)
3793 return -EBUSY;
3794
Charles Keepax243bcfa2018-09-05 15:21:02 +01003795 if (ucontrol->value.enumerated.item[0] == rtd->params_select)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003796 return 0;
3797
Charles Keepax243bcfa2018-09-05 15:21:02 +01003798 if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003799 return -EINVAL;
3800
Charles Keepax243bcfa2018-09-05 15:21:02 +01003801 rtd->params_select = ucontrol->value.enumerated.item[0];
Nikesh Oswalc6615082015-02-02 17:06:44 +00003802
3803 return 0;
3804}
3805
Arnd Bergmannc42c5ac2017-10-10 11:20:11 +02003806static void
anish kumar19ad6832017-09-28 21:52:39 -07003807snd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
3808 unsigned long *private_value,
3809 int num_params,
3810 const char **w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003811{
anish kumar19ad6832017-09-28 21:52:39 -07003812 int count;
3813
3814 devm_kfree(card->dev, (void *)*private_value);
3815 for (count = 0 ; count < num_params; count++)
3816 devm_kfree(card->dev, (void *)w_param_text[count]);
3817 devm_kfree(card->dev, w_param_text);
3818}
3819
3820static struct snd_kcontrol_new *
3821snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
3822 char *link_name,
3823 const struct snd_soc_pcm_stream *params,
3824 int num_params, const char **w_param_text,
3825 unsigned long *private_value)
3826{
Nikesh Oswalc6615082015-02-02 17:06:44 +00003827 struct soc_enum w_param_enum[] = {
3828 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3829 };
3830 struct snd_kcontrol_new kcontrol_dai_link[] = {
3831 SOC_ENUM_EXT(NULL, w_param_enum[0],
3832 snd_soc_dapm_dai_link_get,
3833 snd_soc_dapm_dai_link_put),
3834 };
anish kumar19ad6832017-09-28 21:52:39 -07003835 struct snd_kcontrol_new *kcontrol_news;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003836 const struct snd_soc_pcm_stream *config = params;
anish kumar19ad6832017-09-28 21:52:39 -07003837 int count;
Mark Brownc74184e2012-04-04 22:12:09 +01003838
Nikesh Oswalc6615082015-02-02 17:06:44 +00003839 for (count = 0 ; count < num_params; count++) {
3840 if (!config->stream_name) {
3841 dev_warn(card->dapm.dev,
3842 "ASoC: anonymous config %d for dai link %s\n",
3843 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003844 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003845 devm_kasprintf(card->dev, GFP_KERNEL,
3846 "Anonymous Configuration %d",
3847 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003848 } else {
3849 w_param_text[count] = devm_kmemdup(card->dev,
3850 config->stream_name,
3851 strlen(config->stream_name) + 1,
3852 GFP_KERNEL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003853 }
anish kumar19ad6832017-09-28 21:52:39 -07003854 if (!w_param_text[count])
3855 goto outfree_w_param;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003856 config++;
3857 }
anish kumar19ad6832017-09-28 21:52:39 -07003858
Nikesh Oswalc6615082015-02-02 17:06:44 +00003859 w_param_enum[0].items = num_params;
3860 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003861
anish kumar19ad6832017-09-28 21:52:39 -07003862 *private_value =
3863 (unsigned long) devm_kmemdup(card->dev,
3864 (void *)(kcontrol_dai_link[0].private_value),
3865 sizeof(struct soc_enum), GFP_KERNEL);
3866 if (!*private_value) {
3867 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3868 link_name);
3869 goto outfree_w_param;
3870 }
3871 kcontrol_dai_link[0].private_value = *private_value;
3872 /* duplicate kcontrol_dai_link on heap so that memory persists */
3873 kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3874 sizeof(struct snd_kcontrol_new),
3875 GFP_KERNEL);
3876 if (!kcontrol_news) {
3877 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3878 link_name);
3879 goto outfree_w_param;
3880 }
3881 return kcontrol_news;
3882
3883outfree_w_param:
3884 snd_soc_dapm_free_kcontrol(card, private_value, num_params, w_param_text);
3885 return NULL;
3886}
3887
Charles Keepax778ff5b2018-09-05 15:21:00 +01003888static struct snd_soc_dapm_widget *
3889snd_soc_dapm_new_dai(struct snd_soc_card *card, struct snd_soc_pcm_runtime *rtd,
3890 struct snd_soc_dapm_widget *source,
3891 struct snd_soc_dapm_widget *sink)
anish kumar19ad6832017-09-28 21:52:39 -07003892{
3893 struct snd_soc_dapm_widget template;
3894 struct snd_soc_dapm_widget *w;
3895 const char **w_param_text;
3896 unsigned long private_value;
3897 char *link_name;
3898 int ret;
3899
3900 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3901 source->name, sink->name);
3902 if (!link_name)
Charles Keepax778ff5b2018-09-05 15:21:00 +01003903 return ERR_PTR(-ENOMEM);
anish kumar19ad6832017-09-28 21:52:39 -07003904
Mark Brownc74184e2012-04-04 22:12:09 +01003905 memset(&template, 0, sizeof(template));
3906 template.reg = SND_SOC_NOPM;
3907 template.id = snd_soc_dapm_dai_link;
3908 template.name = link_name;
3909 template.event = snd_soc_dai_link_event;
3910 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3911 SND_SOC_DAPM_PRE_PMD;
anish kumar19ad6832017-09-28 21:52:39 -07003912 template.kcontrol_news = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003913
anish kumar19ad6832017-09-28 21:52:39 -07003914 /* allocate memory for control, only in case of multiple configs */
Charles Keepax778ff5b2018-09-05 15:21:00 +01003915 if (rtd->dai_link->num_params > 1) {
3916 w_param_text = devm_kcalloc(card->dev,
3917 rtd->dai_link->num_params,
3918 sizeof(char *), GFP_KERNEL);
anish kumar19ad6832017-09-28 21:52:39 -07003919 if (!w_param_text) {
3920 ret = -ENOMEM;
3921 goto param_fail;
3922 }
3923
3924 template.num_kcontrols = 1;
3925 template.kcontrol_news =
3926 snd_soc_dapm_alloc_kcontrol(card,
Charles Keepax778ff5b2018-09-05 15:21:00 +01003927 link_name,
3928 rtd->dai_link->params,
3929 rtd->dai_link->num_params,
anish kumar19ad6832017-09-28 21:52:39 -07003930 w_param_text, &private_value);
3931 if (!template.kcontrol_news) {
3932 ret = -ENOMEM;
3933 goto param_fail;
3934 }
Arnd Bergmann667ebc92017-10-10 11:20:10 +02003935 } else {
3936 w_param_text = NULL;
anish kumar19ad6832017-09-28 21:52:39 -07003937 }
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003938 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003939
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003940 w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003941 if (IS_ERR(w))
Linus Walleij37e1df82017-01-13 10:23:52 +01003942 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003943
Charles Keepax249dc492018-08-15 13:11:35 +01003944 w->priv = rtd;
Mark Brownc74184e2012-04-04 22:12:09 +01003945
Charles Keepax778ff5b2018-09-05 15:21:00 +01003946 return w;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003947
Nikesh Oswalc6615082015-02-02 17:06:44 +00003948outfree_kcontrol_news:
3949 devm_kfree(card->dev, (void *)template.kcontrol_news);
Charles Keepax778ff5b2018-09-05 15:21:00 +01003950 snd_soc_dapm_free_kcontrol(card, &private_value,
3951 rtd->dai_link->num_params, w_param_text);
anish kumar19ad6832017-09-28 21:52:39 -07003952param_fail:
Nikesh Oswalc6615082015-02-02 17:06:44 +00003953 devm_kfree(card->dev, link_name);
Charles Keepax778ff5b2018-09-05 15:21:00 +01003954 return ERR_PTR(ret);
Mark Brownc74184e2012-04-04 22:12:09 +01003955}
3956
Mark Brown888df392012-02-16 19:37:51 -08003957int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3958 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003959{
Mark Brown888df392012-02-16 19:37:51 -08003960 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003961 struct snd_soc_dapm_widget *w;
3962
Mark Brown888df392012-02-16 19:37:51 -08003963 WARN_ON(dapm->dev != dai->dev);
3964
3965 memset(&template, 0, sizeof(template));
3966 template.reg = SND_SOC_NOPM;
3967
3968 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003969 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003970 template.name = dai->driver->playback.stream_name;
3971 template.sname = dai->driver->playback.stream_name;
3972
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003973 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003974 template.name);
3975
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003976 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003977 if (IS_ERR(w))
3978 return PTR_ERR(w);
Mark Brown888df392012-02-16 19:37:51 -08003979
3980 w->priv = dai;
3981 dai->playback_widget = w;
3982 }
3983
3984 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003985 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003986 template.name = dai->driver->capture.stream_name;
3987 template.sname = dai->driver->capture.stream_name;
3988
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003989 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003990 template.name);
3991
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003992 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Charles Keepax3bbf5d32018-09-05 15:20:58 +01003993 if (IS_ERR(w))
3994 return PTR_ERR(w);
Mark Brown888df392012-02-16 19:37:51 -08003995
3996 w->priv = dai;
3997 dai->capture_widget = w;
3998 }
3999
4000 return 0;
4001}
4002
4003int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
4004{
4005 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004006 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08004007 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08004008
4009 /* For each DAI widget... */
4010 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01004011 switch (dai_w->id) {
4012 case snd_soc_dapm_dai_in:
4013 case snd_soc_dapm_dai_out:
4014 break;
4015 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02004016 continue;
Mark Brown46162742013-06-05 19:36:11 +01004017 }
Mark Brown888df392012-02-16 19:37:51 -08004018
Liam Girdwoode01b4f62018-06-14 20:26:42 +01004019 /* let users know there is no DAI to link */
4020 if (!dai_w->priv) {
4021 dev_dbg(card->dev, "dai widget %s has no DAI\n",
4022 dai_w->name);
4023 continue;
4024 }
4025
Mark Brown888df392012-02-16 19:37:51 -08004026 dai = dai_w->priv;
4027
4028 /* ...find all widgets with the same stream and link them */
4029 list_for_each_entry(w, &card->widgets, list) {
4030 if (w->dapm != dai_w->dapm)
4031 continue;
4032
Mark Brown46162742013-06-05 19:36:11 +01004033 switch (w->id) {
4034 case snd_soc_dapm_dai_in:
4035 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08004036 continue;
Mark Brown46162742013-06-05 19:36:11 +01004037 default:
4038 break;
4039 }
Mark Brown888df392012-02-16 19:37:51 -08004040
Lars-Peter Clausena798c242015-07-21 11:51:35 +02004041 if (!w->sname || !strstr(w->sname, dai_w->sname))
Mark Brown888df392012-02-16 19:37:51 -08004042 continue;
4043
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004044 if (dai_w->id == snd_soc_dapm_dai_in) {
4045 src = dai_w;
4046 sink = w;
4047 } else {
4048 src = w;
4049 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08004050 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004051 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
4052 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004053 }
4054 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02004055
Mark Brown888df392012-02-16 19:37:51 -08004056 return 0;
4057}
Liam Girdwood64a648c2011-07-25 11:15:15 +01004058
Benoit Cousson44ba2642014-07-08 23:19:36 +02004059static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
4060 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004061{
Benoit Cousson44ba2642014-07-08 23:19:36 +02004062 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00004063 struct snd_soc_dai *codec_dai;
Charles Keepax778ff5b2018-09-05 15:21:00 +01004064 struct snd_soc_dapm_widget *playback = NULL, *capture = NULL;
4065 struct snd_soc_dapm_widget *codec, *playback_cpu, *capture_cpu;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004066 int i;
4067
Charles Keepax778ff5b2018-09-05 15:21:00 +01004068 if (rtd->dai_link->params) {
Charles Keepax778ff5b2018-09-05 15:21:00 +01004069 playback_cpu = cpu_dai->capture_widget;
4070 capture_cpu = cpu_dai->playback_widget;
4071 } else {
4072 playback = cpu_dai->playback_widget;
4073 capture = cpu_dai->capture_widget;
4074 playback_cpu = playback;
4075 capture_cpu = capture;
4076 }
4077
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00004078 for_each_rtd_codec_dai(rtd, i, codec_dai) {
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004079
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004080 /* connect BE DAI playback if widgets are valid */
Charles Keepax778ff5b2018-09-05 15:21:00 +01004081 codec = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004082
Charles Keepax778ff5b2018-09-05 15:21:00 +01004083 if (playback_cpu && codec) {
4084 if (!playback) {
4085 playback = snd_soc_dapm_new_dai(card, rtd,
4086 playback_cpu,
4087 codec);
4088
4089 snd_soc_dapm_add_path(&card->dapm, playback_cpu,
4090 playback, NULL, NULL);
4091 }
4092
4093 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
4094 cpu_dai->component->name, playback_cpu->name,
4095 codec_dai->component->name, codec->name);
4096
4097 snd_soc_dapm_add_path(&card->dapm, playback, codec,
4098 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004099 }
4100
4101 /* connect BE DAI capture if widgets are valid */
Charles Keepax778ff5b2018-09-05 15:21:00 +01004102 codec = codec_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004103
Charles Keepax778ff5b2018-09-05 15:21:00 +01004104 if (codec && capture_cpu) {
4105 if (!capture) {
4106 capture = snd_soc_dapm_new_dai(card, rtd,
4107 codec,
4108 capture_cpu);
4109
4110 snd_soc_dapm_add_path(&card->dapm, capture,
4111 capture_cpu, NULL, NULL);
4112 }
4113
4114 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
4115 codec_dai->component->name, codec->name,
4116 cpu_dai->component->name, capture_cpu->name);
4117
4118 snd_soc_dapm_add_path(&card->dapm, codec, capture,
4119 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004120 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004121 }
4122}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004123
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004124static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
4125 int event)
4126{
4127 struct snd_soc_dapm_widget *w;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004128 unsigned int ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004129
4130 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
4131 w = dai->playback_widget;
4132 else
4133 w = dai->capture_widget;
4134
4135 if (w) {
4136 dapm_mark_dirty(w, "stream event");
4137
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004138 if (w->id == snd_soc_dapm_dai_in) {
4139 ep = SND_SOC_DAPM_EP_SOURCE;
4140 dapm_widget_invalidate_input_paths(w);
4141 } else {
4142 ep = SND_SOC_DAPM_EP_SINK;
4143 dapm_widget_invalidate_output_paths(w);
4144 }
4145
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004146 switch (event) {
4147 case SND_SOC_DAPM_STREAM_START:
4148 w->active = 1;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004149 w->is_ep = ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004150 break;
4151 case SND_SOC_DAPM_STREAM_STOP:
4152 w->active = 0;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004153 w->is_ep = 0;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004154 break;
4155 case SND_SOC_DAPM_STREAM_SUSPEND:
4156 case SND_SOC_DAPM_STREAM_RESUME:
4157 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
4158 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
4159 break;
4160 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004161 }
4162}
4163
Benoit Cousson44ba2642014-07-08 23:19:36 +02004164void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
4165{
Mengdong Lin1a497982015-11-18 02:34:11 -05004166 struct snd_soc_pcm_runtime *rtd;
Benoit Cousson44ba2642014-07-08 23:19:36 +02004167
4168 /* for each BE DAI link... */
Mengdong Lin1a497982015-11-18 02:34:11 -05004169 list_for_each_entry(rtd, &card->rtd_list, list) {
Benoit Cousson44ba2642014-07-08 23:19:36 +02004170 /*
4171 * dynamic FE links have no fixed DAI mapping.
4172 * CODEC<->CODEC links have no direct connection.
4173 */
Charles Keepax778ff5b2018-09-05 15:21:00 +01004174 if (rtd->dai_link->dynamic)
Benoit Cousson44ba2642014-07-08 23:19:36 +02004175 continue;
4176
4177 dapm_connect_dai_link_widgets(card, rtd);
4178 }
4179}
4180
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004181static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4182 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004183{
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00004184 struct snd_soc_dai *codec_dai;
Benoit Cousson44ba2642014-07-08 23:19:36 +02004185 int i;
4186
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004187 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Kuninori Morimoto0b7990e2018-09-03 02:12:56 +00004188 for_each_rtd_codec_dai(rtd, i, codec_dai)
4189 soc_dapm_dai_stream_event(codec_dai, stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004190
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004191 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004192}
4193
4194/**
4195 * snd_soc_dapm_stream_event - send a stream event to the dapm core
4196 * @rtd: PCM runtime data
4197 * @stream: stream name
4198 * @event: stream event
4199 *
4200 * Sends a stream event to the dapm core. The core then makes any
4201 * necessary widget power changes.
4202 *
4203 * Returns 0 for success else error.
4204 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004205void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4206 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004207{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00004208 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004209
Liam Girdwood3cd04342012-03-09 12:02:08 +00004210 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004211 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00004212 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004213}
Richard Purdie2b97eab2006-10-06 18:32:18 +02004214
4215/**
Charles Keepax11391102014-02-18 15:22:14 +00004216 * snd_soc_dapm_enable_pin_unlocked - enable pin.
4217 * @dapm: DAPM context
4218 * @pin: pin name
4219 *
4220 * Enables input/output pin and its parents or children widgets iff there is
4221 * a valid audio route and active audio stream.
4222 *
4223 * Requires external locking.
4224 *
4225 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4226 * do any widget power switching.
4227 */
4228int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4229 const char *pin)
4230{
4231 return snd_soc_dapm_set_pin(dapm, pin, 1);
4232}
4233EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
4234
4235/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004236 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004237 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004238 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02004239 *
Mark Brown74b8f952009-06-06 11:26:15 +01004240 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01004241 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00004242 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004243 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4244 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02004245 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004246int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004247{
Charles Keepax11391102014-02-18 15:22:14 +00004248 int ret;
4249
4250 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4251
4252 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
4253
4254 mutex_unlock(&dapm->card->dapm_mutex);
4255
4256 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02004257}
Liam Girdwooda5302182008-07-07 13:35:17 +01004258EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004259
4260/**
Charles Keepax11391102014-02-18 15:22:14 +00004261 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
4262 * @dapm: DAPM context
4263 * @pin: pin name
4264 *
4265 * Enables input/output pin regardless of any other state. This is
4266 * intended for use with microphone bias supplies used in microphone
4267 * jack detection.
4268 *
4269 * Requires external locking.
4270 *
4271 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4272 * do any widget power switching.
4273 */
4274int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4275 const char *pin)
4276{
4277 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4278
4279 if (!w) {
4280 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4281 return -EINVAL;
4282 }
4283
4284 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02004285 if (!w->connected) {
4286 /*
4287 * w->force does not affect the number of input or output paths,
4288 * so we only have to recheck if w->connected is changed
4289 */
4290 dapm_widget_invalidate_input_paths(w);
4291 dapm_widget_invalidate_output_paths(w);
4292 w->connected = 1;
4293 }
Charles Keepax11391102014-02-18 15:22:14 +00004294 w->force = 1;
4295 dapm_mark_dirty(w, "force enable");
4296
4297 return 0;
4298}
4299EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4300
4301/**
Mark Brownda341832010-03-15 19:23:37 +00004302 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004303 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00004304 * @pin: pin name
4305 *
4306 * Enables input/output pin regardless of any other state. This is
4307 * intended for use with microphone bias supplies used in microphone
4308 * jack detection.
4309 *
4310 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4311 * do any widget power switching.
4312 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004313int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4314 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00004315{
Charles Keepax11391102014-02-18 15:22:14 +00004316 int ret;
Mark Brownda341832010-03-15 19:23:37 +00004317
Charles Keepax11391102014-02-18 15:22:14 +00004318 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00004319
Charles Keepax11391102014-02-18 15:22:14 +00004320 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09004321
Charles Keepax11391102014-02-18 15:22:14 +00004322 mutex_unlock(&dapm->card->dapm_mutex);
4323
4324 return ret;
Mark Brownda341832010-03-15 19:23:37 +00004325}
4326EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4327
4328/**
Charles Keepax11391102014-02-18 15:22:14 +00004329 * snd_soc_dapm_disable_pin_unlocked - disable pin.
4330 * @dapm: DAPM context
4331 * @pin: pin name
4332 *
4333 * Disables input/output pin and its parents or children widgets.
4334 *
4335 * Requires external locking.
4336 *
4337 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4338 * do any widget power switching.
4339 */
4340int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4341 const char *pin)
4342{
4343 return snd_soc_dapm_set_pin(dapm, pin, 0);
4344}
4345EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4346
4347/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004348 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004349 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004350 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004351 *
Mark Brown74b8f952009-06-06 11:26:15 +01004352 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004353 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004354 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4355 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004356 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004357int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4358 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004359{
Charles Keepax11391102014-02-18 15:22:14 +00004360 int ret;
4361
4362 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4363
4364 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4365
4366 mutex_unlock(&dapm->card->dapm_mutex);
4367
4368 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004369}
4370EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4371
4372/**
Charles Keepax11391102014-02-18 15:22:14 +00004373 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4374 * @dapm: DAPM context
4375 * @pin: pin name
4376 *
4377 * Marks the specified pin as being not connected, disabling it along
4378 * any parent or child widgets. At present this is identical to
4379 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4380 * additional things such as disabling controls which only affect
4381 * paths through the pin.
4382 *
4383 * Requires external locking.
4384 *
4385 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4386 * do any widget power switching.
4387 */
4388int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4389 const char *pin)
4390{
4391 return snd_soc_dapm_set_pin(dapm, pin, 0);
4392}
4393EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4394
4395/**
Mark Brown5817b522008-09-24 11:23:11 +01004396 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004397 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004398 * @pin: pin name
4399 *
4400 * Marks the specified pin as being not connected, disabling it along
4401 * any parent or child widgets. At present this is identical to
4402 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4403 * additional things such as disabling controls which only affect
4404 * paths through the pin.
4405 *
4406 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4407 * do any widget power switching.
4408 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004409int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004410{
Charles Keepax11391102014-02-18 15:22:14 +00004411 int ret;
4412
4413 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4414
4415 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4416
4417 mutex_unlock(&dapm->card->dapm_mutex);
4418
4419 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004420}
4421EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4422
4423/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004424 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004425 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004426 * @pin: audio signal pin endpoint (or start point)
4427 *
4428 * Get audio pin status - connected or disconnected.
4429 *
4430 * Returns 1 for connected otherwise 0.
4431 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004432int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4433 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004434{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004435 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004436
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004437 if (w)
4438 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004439
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004440 return 0;
4441}
Liam Girdwooda5302182008-07-07 13:35:17 +01004442EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004443
4444/**
Mark Brown1547aba2010-05-07 21:11:40 +01004445 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004446 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004447 * @pin: audio signal pin endpoint (or start point)
4448 *
4449 * Mark the given endpoint or pin as ignoring suspend. When the
4450 * system is disabled a path between two endpoints flagged as ignoring
4451 * suspend will not be disabled. The path must already be enabled via
4452 * normal means at suspend time, it will not be turned on if it was not
4453 * already enabled.
4454 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004455int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4456 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004457{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004458 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004459
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004460 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004461 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004462 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004463 }
4464
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004465 w->ignore_suspend = 1;
4466
4467 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004468}
4469EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4470
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004471/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004472 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004473 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004474 *
4475 * Free all dapm widgets and resources.
4476 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004477void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004478{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004479 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004480 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004481 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004482}
4483EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4484
Xiang Xiao57996352014-03-02 00:04:02 +08004485static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004486{
Liam Girdwood01005a72012-07-06 16:57:05 +01004487 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004488 struct snd_soc_dapm_widget *w;
4489 LIST_HEAD(down_list);
4490 int powerdown = 0;
4491
Liam Girdwood01005a72012-07-06 16:57:05 +01004492 mutex_lock(&card->dapm_mutex);
4493
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004494 list_for_each_entry(w, &dapm->card->widgets, list) {
4495 if (w->dapm != dapm)
4496 continue;
Mark Brown51737472009-06-22 13:16:51 +01004497 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004498 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004499 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004500 powerdown = 1;
4501 }
4502 }
4503
4504 /* If there were no widgets to power down we're already in
4505 * standby.
4506 */
4507 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004508 if (dapm->bias_level == SND_SOC_BIAS_ON)
4509 snd_soc_dapm_set_bias_level(dapm,
4510 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004511 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004512 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4513 snd_soc_dapm_set_bias_level(dapm,
4514 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004515 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004516
4517 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004518}
Mark Brown51737472009-06-22 13:16:51 +01004519
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004520/*
4521 * snd_soc_dapm_shutdown - callback for system shutdown
4522 */
4523void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4524{
Xiang Xiao57996352014-03-02 00:04:02 +08004525 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004526
Xiang Xiao57996352014-03-02 00:04:02 +08004527 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004528 if (dapm != &card->dapm) {
4529 soc_dapm_shutdown_dapm(dapm);
4530 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4531 snd_soc_dapm_set_bias_level(dapm,
4532 SND_SOC_BIAS_OFF);
4533 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004534 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004535
4536 soc_dapm_shutdown_dapm(&card->dapm);
4537 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4538 snd_soc_dapm_set_bias_level(&card->dapm,
4539 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004540}
4541
Richard Purdie2b97eab2006-10-06 18:32:18 +02004542/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004543MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004544MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4545MODULE_LICENSE("GPL");