blob: 461d951917c0569096eacd4274fd9eb1ade8f9c5 [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 if (!data->widget) {
Charles Keepax773da9b2015-05-01 12:37:25 +0100368 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200369 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200370 }
371 }
372 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200373 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100374 case snd_soc_dapm_mux:
375 e = (struct soc_enum *)kcontrol->private_value;
376
377 if (e->autodisable) {
378 struct snd_soc_dapm_widget template;
379
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100380 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
Charles Keepax561ed682015-05-01 12:37:26 +0100381 "Autodisable");
382 if (!name) {
383 ret = -ENOMEM;
384 goto err_data;
385 }
386
387 memset(&template, 0, sizeof(template));
388 template.reg = e->reg;
389 template.mask = e->mask << e->shift_l;
390 template.shift = e->shift_l;
391 template.off_val = snd_soc_enum_item_to_val(e, 0);
392 template.on_val = template.off_val;
393 template.id = snd_soc_dapm_kcontrol;
394 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200395
396 data->value = template.on_val;
397
Charles Keepaxffacb482015-06-26 10:39:43 +0100398 data->widget = snd_soc_dapm_new_control_unlocked(
399 widget->dapm, &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200400 kfree(name);
Linus Walleij37e1df82017-01-13 10:23:52 +0100401 if (IS_ERR(data->widget)) {
402 ret = PTR_ERR(data->widget);
403 goto err_data;
404 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200405 if (!data->widget) {
Charles Keepax561ed682015-05-01 12:37:26 +0100406 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200407 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200408 }
Charles Keepax561ed682015-05-01 12:37:26 +0100409
410 snd_soc_dapm_add_path(widget->dapm, data->widget,
411 widget, NULL, NULL);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200412 }
413 break;
414 default:
415 break;
416 }
417
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200418 kcontrol->private_data = data;
419
420 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100421
Charles Keepax773da9b2015-05-01 12:37:25 +0100422err_data:
423 kfree(data);
424 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200425}
426
427static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
428{
429 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Srinivas Kandagatlaff2faf12018-06-04 12:13:26 +0100430
431 list_del(&data->paths);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200432 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200433 kfree(data);
434}
435
436static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
437 const struct snd_kcontrol *kcontrol)
438{
439 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
440
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200441 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200442}
443
444static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
445 struct snd_soc_dapm_widget *widget)
446{
447 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200448 struct snd_soc_dapm_widget_list *new_wlist;
449 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200450
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200451 if (data->wlist)
452 n = data->wlist->num_widgets + 1;
453 else
454 n = 1;
455
456 new_wlist = krealloc(data->wlist,
457 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
458 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200459 return -ENOMEM;
460
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200461 new_wlist->widgets[n - 1] = widget;
462 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200463
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200464 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200465
466 return 0;
467}
468
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200469static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
470 struct snd_soc_dapm_path *path)
471{
472 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
473
474 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200475}
476
477static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
478{
479 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
480
481 if (!data->widget)
482 return true;
483
484 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200485}
486
487static struct list_head *dapm_kcontrol_get_path_list(
488 const struct snd_kcontrol *kcontrol)
489{
490 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
491
492 return &data->paths;
493}
494
495#define dapm_kcontrol_for_each_path(path, kcontrol) \
496 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
497 list_kcontrol)
498
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530499unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200500{
501 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
502
503 return data->value;
504}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530505EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200506
507static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
508 unsigned int value)
509{
510 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
511
512 if (data->value == value)
513 return false;
514
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200515 if (data->widget)
516 data->widget->on_val = value;
517
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200518 data->value = value;
519
520 return true;
521}
522
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200523/**
Mythri P K93e39a12015-10-20 22:30:08 +0530524 * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
525 * kcontrol
526 * @kcontrol: The kcontrol
527 */
528struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
529 struct snd_kcontrol *kcontrol)
530{
531 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
532}
533EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
534
535/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200536 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
537 * kcontrol
538 * @kcontrol: The kcontrol
539 *
540 * Note: This function must only be used on kcontrols that are known to have
541 * been registered for a CODEC. Otherwise the behaviour is undefined.
542 */
543struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
544 struct snd_kcontrol *kcontrol)
545{
546 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
547}
548EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
549
Liam Girdwood6c120e12012-02-15 15:15:34 +0000550static void dapm_reset(struct snd_soc_card *card)
551{
552 struct snd_soc_dapm_widget *w;
553
Mark Brownf9fa2b12014-03-06 16:49:11 +0800554 lockdep_assert_held(&card->dapm_mutex);
555
Liam Girdwood6c120e12012-02-15 15:15:34 +0000556 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
557
558 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200559 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000560 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000561 }
562}
563
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200564static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
565{
566 if (!dapm->component)
567 return NULL;
568 return dapm->component->name_prefix;
569}
570
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200571static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800572 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;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200576 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100577}
578
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200579static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800580 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100581{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200582 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200583 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000584 return snd_soc_component_update_bits(dapm->component, reg,
585 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000586}
587
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200588static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
589 int reg, unsigned int mask, unsigned int value)
590{
591 if (!dapm->component)
592 return -EIO;
593 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
594}
595
Mark Browneb270e92013-10-09 13:52:52 +0100596static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
597{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200598 if (dapm->component)
599 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100600}
601
Charles Keepax45a110a2015-05-11 13:50:30 +0100602static struct snd_soc_dapm_widget *
603dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
604{
605 struct snd_soc_dapm_widget *w = wcache->widget;
606 struct list_head *wlist;
607 const int depth = 2;
608 int i = 0;
609
610 if (w) {
611 wlist = &w->dapm->card->widgets;
612
613 list_for_each_entry_from(w, wlist, list) {
614 if (!strcmp(name, w->name))
615 return w;
616
617 if (++i == depth)
618 break;
619 }
620 }
621
622 return NULL;
623}
624
625static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
626 struct snd_soc_dapm_widget *w)
627{
628 wcache->widget = w;
629}
630
Mark Brown452c5ea2009-05-17 21:41:23 +0100631/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200632 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
633 * @dapm: The DAPM context for which to set the level
634 * @level: The level to set
635 *
636 * Forces the DAPM bias level to a specific state. It will call the bias level
637 * callback of DAPM context with the specified level. This will even happen if
638 * the context is already at the same level. Furthermore it will not go through
639 * the normal bias level sequencing, meaning any intermediate states between the
640 * current and the target state will not be entered.
641 *
642 * Note that the change in bias level is only temporary and the next time
643 * snd_soc_dapm_sync() is called the state will be set to the level as
644 * determined by the DAPM core. The function is mainly intended to be used to
645 * used during probe or resume from suspend to power up the device so
646 * initialization can be done, before the DAPM core takes over.
647 */
648int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
649 enum snd_soc_bias_level level)
650{
651 int ret = 0;
652
653 if (dapm->set_bias_level)
654 ret = dapm->set_bias_level(dapm, level);
655
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200656 if (ret == 0)
657 dapm->bias_level = level;
658
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200659 return ret;
660}
661EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
662
Mark Brown452c5ea2009-05-17 21:41:23 +0100663/**
664 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800665 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100666 * @level: level to configure
667 *
668 * Configure the bias (power) levels for the SoC audio device.
669 *
670 * Returns 0 for success else error.
671 */
Mark Browned5a4c42011-02-18 11:12:42 -0800672static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200673 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100674{
Mark Browned5a4c42011-02-18 11:12:42 -0800675 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100676 int ret = 0;
677
Mark Brown84e90932010-11-04 00:07:02 -0400678 trace_snd_soc_bias_level_start(card, level);
679
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000680 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100681 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100682 if (ret != 0)
683 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100684
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200685 if (!card || dapm != &card->dapm)
686 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100687
Mark Brown171ec6b2011-06-06 18:15:19 +0100688 if (ret != 0)
689 goto out;
690
691 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100692 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100693out:
Mark Brown84e90932010-11-04 00:07:02 -0400694 trace_snd_soc_bias_level_done(card, level);
695
Mark Brown452c5ea2009-05-17 21:41:23 +0100696 return ret;
697}
698
Mark Brown74b8f952009-06-06 11:26:15 +0100699/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200700static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200701 struct snd_soc_dapm_path *path, const char *control_name,
702 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200703{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200704 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200705 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100706 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200707 int i;
708
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100709 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200710 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100711 val = (val >> e->shift_l) & e->mask;
712 item = snd_soc_enum_val_to_item(e, val);
713 } else {
714 /* since a virtual mux has no backing registers to
715 * decide which path to connect, it will try to match
716 * with the first enumeration. This is to ensure
717 * that the default mux choice (the first) will be
718 * correctly powered up during initialization.
719 */
720 item = 0;
721 }
722
Xie Yishengf9e0b4a2018-05-31 19:11:23 +0800723 i = match_string(e->texts, e->items, control_name);
724 if (i < 0)
725 return -ENODEV;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200726
Xie Yishengf9e0b4a2018-05-31 19:11:23 +0800727 path->name = e->texts[i];
728 path->connect = (i == item);
729 return 0;
730
Richard Purdie2b97eab2006-10-06 18:32:18 +0200731}
732
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100733/* set up initial codec paths */
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800734static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
735 int nth_path)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100736{
737 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200738 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100739 unsigned int reg = mc->reg;
740 unsigned int shift = mc->shift;
741 unsigned int max = mc->max;
742 unsigned int mask = (1 << fls(max)) - 1;
743 unsigned int invert = mc->invert;
744 unsigned int val;
745
746 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200747 soc_dapm_read(p->sink->dapm, reg, &val);
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800748 /*
749 * The nth_path argument allows this function to know
750 * which path of a kcontrol it is setting the initial
751 * status for. Ideally this would support any number
752 * of paths and channels. But since kcontrols only come
753 * in mono and stereo variants, we are limited to 2
754 * channels.
755 *
756 * The following code assumes for stereo controls the
757 * first path is the left channel, and all remaining
758 * paths are the right channel.
759 */
760 if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
761 if (reg != mc->rreg)
762 soc_dapm_read(p->sink->dapm, mc->rreg, &val);
763 val = (val >> mc->rshift) & mask;
764 } else {
765 val = (val >> shift) & mask;
766 }
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100767 if (invert)
768 val = max - val;
769 p->connect = !!val;
770 } else {
771 p->connect = 0;
772 }
773}
774
Mark Brown74b8f952009-06-06 11:26:15 +0100775/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200776static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200777 struct snd_soc_dapm_path *path, const char *control_name)
778{
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800779 int i, nth_path = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200780
781 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200782 for (i = 0; i < path->sink->num_kcontrols; i++) {
783 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
784 path->name = path->sink->kcontrol_news[i].name;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800785 dapm_set_mixer_path_status(path, i, nth_path++);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200786 return 0;
787 }
788 }
789 return -ENODEV;
790}
791
Stephen Warrenaf468002011-04-28 17:38:01 -0600792static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600793 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600794 const struct snd_kcontrol_new *kcontrol_new,
795 struct snd_kcontrol **kcontrol)
796{
797 struct snd_soc_dapm_widget *w;
798 int i;
799
800 *kcontrol = NULL;
801
802 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600803 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
804 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600805 for (i = 0; i < w->num_kcontrols; i++) {
806 if (&w->kcontrol_news[i] == kcontrol_new) {
807 if (w->kcontrols)
808 *kcontrol = w->kcontrols[i];
809 return 1;
810 }
811 }
812 }
813
814 return 0;
815}
816
Stephen Warren85762e72013-03-29 15:40:10 -0600817/*
818 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
819 * create it. Either way, add the widget into the control's widget list
820 */
Jeeja KP19a2557b2015-10-20 22:30:06 +0530821static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100822 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200823{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200824 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000825 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000826 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600827 size_t prefix_len;
828 int shared;
829 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600830 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200831 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600832 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200833 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000834
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200835 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000836 if (prefix)
837 prefix_len = strlen(prefix) + 1;
838 else
839 prefix_len = 0;
840
Stephen Warren85762e72013-03-29 15:40:10 -0600841 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
842 &kcontrol);
843
Stephen Warren85762e72013-03-29 15:40:10 -0600844 if (!kcontrol) {
845 if (shared) {
846 wname_in_long_name = false;
847 kcname_in_long_name = true;
848 } else {
849 switch (w->id) {
850 case snd_soc_dapm_switch:
851 case snd_soc_dapm_mixer:
Jeeja KP19a2557b2015-10-20 22:30:06 +0530852 case snd_soc_dapm_pga:
Chen-Yu Tsaia3930ed2016-08-27 19:28:00 +0800853 case snd_soc_dapm_out_drv:
Stephen Warren85762e72013-03-29 15:40:10 -0600854 wname_in_long_name = true;
855 kcname_in_long_name = true;
856 break;
857 case snd_soc_dapm_mixer_named_ctl:
858 wname_in_long_name = false;
859 kcname_in_long_name = true;
860 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200861 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600862 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600863 wname_in_long_name = true;
864 kcname_in_long_name = false;
865 break;
866 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600867 return -EINVAL;
868 }
869 }
870
871 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600872 /*
873 * The control will get a prefix from the control
874 * creation process but we're also using the same
875 * prefix for widgets so cut the prefix off the
876 * front of the widget name.
877 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200878 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600879 w->name + prefix_len,
880 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200881 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200882 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600883
884 name = long_name;
885 } else if (wname_in_long_name) {
886 long_name = NULL;
887 name = w->name + prefix_len;
888 } else {
889 long_name = NULL;
890 name = w->kcontrol_news[kci].name;
891 }
892
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200893 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600894 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200895 if (!kcontrol) {
896 ret = -ENOMEM;
897 goto exit_free;
898 }
899
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200900 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200901
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100902 ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200903 if (ret) {
904 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200905 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200906 }
907
Stephen Warren85762e72013-03-29 15:40:10 -0600908 ret = snd_ctl_add(card, kcontrol);
909 if (ret < 0) {
910 dev_err(dapm->dev,
911 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
912 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200913 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600914 }
Stephen Warren85762e72013-03-29 15:40:10 -0600915 }
916
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200917 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200918 if (ret == 0)
919 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200920
Daniel Macke5092c92014-10-07 13:41:24 +0200921exit_free:
922 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600923
Daniel Macke5092c92014-10-07 13:41:24 +0200924 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600925}
926
927/* create new dapm mixer control */
928static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
929{
930 int i, ret;
931 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100932 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600933
Richard Purdie2b97eab2006-10-06 18:32:18 +0200934 /* add kcontrol */
935 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200936 /* match name */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200937 snd_soc_dapm_widget_for_each_source_path(w, path) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200938 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600939 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200940 continue;
941
Charles Keepax561ed682015-05-01 12:37:26 +0100942 if (!w->kcontrols[i]) {
Jeeja KP19a2557b2015-10-20 22:30:06 +0530943 ret = dapm_create_or_share_kcontrol(w, i);
Charles Keepax561ed682015-05-01 12:37:26 +0100944 if (ret < 0)
945 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200946 }
947
Mark Brown946d92a2013-08-12 23:28:42 +0100948 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100949
950 data = snd_kcontrol_chip(w->kcontrols[i]);
951 if (data->widget)
952 snd_soc_dapm_add_path(data->widget->dapm,
953 data->widget,
954 path->source,
955 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200956 }
957 }
Stephen Warren85762e72013-03-29 15:40:10 -0600958
959 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200960}
961
962/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200963static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200964{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200965 struct snd_soc_dapm_context *dapm = w->dapm;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200966 enum snd_soc_dapm_direction dir;
Stephen Warren85762e72013-03-29 15:40:10 -0600967 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200968 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600969 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200970
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200971 switch (w->id) {
972 case snd_soc_dapm_mux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200973 dir = SND_SOC_DAPM_DIR_OUT;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200974 type = "mux";
975 break;
976 case snd_soc_dapm_demux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200977 dir = SND_SOC_DAPM_DIR_IN;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200978 type = "demux";
979 break;
980 default:
981 return -EINVAL;
982 }
983
Stephen Warrenaf468002011-04-28 17:38:01 -0600984 if (w->num_kcontrols != 1) {
985 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200986 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600987 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200988 return -EINVAL;
989 }
990
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200991 if (list_empty(&w->edges[dir])) {
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200992 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600993 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600994 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200995
Jeeja KP19a2557b2015-10-20 22:30:06 +0530996 ret = dapm_create_or_share_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600997 if (ret < 0)
998 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600999
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001000 snd_soc_dapm_widget_for_each_path(w, dir, path) {
1001 if (path->name)
1002 dapm_kcontrol_add_path(w->kcontrols[0], path);
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +02001003 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001004
Stephen Warrenaf468002011-04-28 17:38:01 -06001005 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001006}
1007
1008/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02001009static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001010{
Jeeja KP19a2557b2015-10-20 22:30:06 +05301011 int i, ret;
1012
1013 for (i = 0; i < w->num_kcontrols; i++) {
1014 ret = dapm_create_or_share_kcontrol(w, i);
1015 if (ret < 0)
1016 return ret;
1017 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001018
Mark Browna6c65732010-03-03 17:45:21 +00001019 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001020}
1021
Nikesh Oswalc6615082015-02-02 17:06:44 +00001022/* create new dapm dai link control */
1023static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
1024{
1025 int i, ret;
1026 struct snd_kcontrol *kcontrol;
1027 struct snd_soc_dapm_context *dapm = w->dapm;
1028 struct snd_card *card = dapm->card->snd_card;
1029
1030 /* create control for links with > 1 config */
1031 if (w->num_params <= 1)
1032 return 0;
1033
1034 /* add kcontrol */
1035 for (i = 0; i < w->num_kcontrols; i++) {
1036 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
1037 w->name, NULL);
1038 ret = snd_ctl_add(card, kcontrol);
1039 if (ret < 0) {
1040 dev_err(dapm->dev,
1041 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1042 w->name, w->kcontrol_news[i].name, ret);
1043 return ret;
1044 }
1045 kcontrol->private_data = w;
1046 w->kcontrols[i] = kcontrol;
1047 }
1048
1049 return 0;
1050}
1051
Mark Brown9949788b2010-05-07 20:24:05 +01001052/* We implement power down on suspend by checking the power state of
1053 * the ALSA card - when we are suspending the ALSA state for the card
1054 * is set to D3.
1055 */
1056static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1057{
Mark Brown12ea2c72011-03-02 18:17:32 +00001058 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown9949788b2010-05-07 20:24:05 +01001059
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001060 switch (level) {
Mark Brown9949788b2010-05-07 20:24:05 +01001061 case SNDRV_CTL_POWER_D3hot:
1062 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +01001063 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001064 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001065 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +01001066 return widget->ignore_suspend;
Mark Brown9949788b2010-05-07 20:24:05 +01001067 default:
1068 return 1;
1069 }
1070}
1071
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001072static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1073 struct list_head *widgets)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001074{
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001075 struct snd_soc_dapm_widget *w;
1076 struct list_head *it;
1077 unsigned int size = 0;
1078 unsigned int i = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001079
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001080 list_for_each(it, widgets)
1081 size++;
1082
Kees Cookacafe7e2018-05-08 13:45:50 -07001083 *list = kzalloc(struct_size(*list, widgets, size), GFP_KERNEL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001084 if (*list == NULL)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001085 return -ENOMEM;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001086
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001087 list_for_each_entry(w, widgets, work_list)
1088 (*list)->widgets[i++] = w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001089
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001090 (*list)->num_widgets = i;
1091
1092 return 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001093}
1094
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001095/*
1096 * Common implementation for is_connected_output_ep() and
1097 * is_connected_input_ep(). The function is inlined since the combined size of
1098 * the two specialized functions is only marginally larger then the size of the
1099 * generic function and at the same time the fast path of the specialized
1100 * functions is significantly smaller than the generic function.
1101 */
1102static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
1103 struct list_head *list, enum snd_soc_dapm_direction dir,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001104 int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
1105 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1106 enum snd_soc_dapm_direction)),
1107 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1108 enum snd_soc_dapm_direction))
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001109{
1110 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001111 struct snd_soc_dapm_path *path;
1112 int con = 0;
1113
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001114 if (widget->endpoints[dir] >= 0)
1115 return widget->endpoints[dir];
Mark Brown024dc072011-10-09 11:52:05 +01001116
Mark Brownde02d072011-09-20 21:43:24 +01001117 DAPM_UPDATE_STAT(widget, path_checks);
1118
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001119 /* do we need to add this widget to the list ? */
1120 if (list)
1121 list_add_tail(&widget->work_list, list);
1122
Jeeja KP09464972016-06-15 11:16:55 +05301123 if (custom_stop_condition && custom_stop_condition(widget, dir)) {
1124 widget->endpoints[dir] = 1;
1125 return widget->endpoints[dir];
1126 }
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001127
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001128 if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
1129 widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
1130 return widget->endpoints[dir];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001131 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001132
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001133 snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
Mark Browne56235e02011-09-21 18:19:14 +01001134 DAPM_UPDATE_STAT(widget, neighbour_checks);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001135
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001136 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001137 continue;
1138
Mark Brown8af294b2013-02-22 17:48:15 +00001139 if (path->walking)
1140 return 1;
1141
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001142 trace_snd_soc_dapm_path(widget, dir, path);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001143
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001144 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001145 path->walking = 1;
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001146 con += fn(path->node[dir], list, custom_stop_condition);
Mark Brown8af294b2013-02-22 17:48:15 +00001147 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001148 }
1149 }
1150
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001151 widget->endpoints[dir] = con;
Mark Brown024dc072011-10-09 11:52:05 +01001152
Richard Purdie2b97eab2006-10-06 18:32:18 +02001153 return con;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001154}
1155
1156/*
1157 * Recursively check for a completed path to an active or physically connected
1158 * output widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001159 *
1160 * Optionally, can be supplied with a function acting as a stopping condition.
1161 * This function takes the dapm widget currently being examined and the walk
1162 * direction as an arguments, it should return true if the walk should be
1163 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001164 */
1165static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001166 struct list_head *list,
1167 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1168 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001169{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001170 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001171 is_connected_output_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001172}
1173
1174/*
1175 * Recursively check for a completed path to an active or physically connected
1176 * input widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001177 *
1178 * Optionally, can be supplied with a function acting as a stopping condition.
1179 * This function takes the dapm widget currently being examined and the walk
1180 * direction as an arguments, it should return true if the walk should be
1181 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001182 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001183static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001184 struct list_head *list,
1185 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1186 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001187{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001188 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001189 is_connected_input_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001190}
1191
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001192/**
1193 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1194 * @dai: the soc DAI.
1195 * @stream: stream direction.
1196 * @list: list of active widgets for this stream.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001197 * @custom_stop_condition: (optional) a function meant to stop the widget graph
1198 * walk based on custom logic.
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001199 *
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001200 * Queries DAPM graph as to whether a valid audio stream path exists for
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001201 * the initial stream specified by name. This takes into account
1202 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1203 *
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001204 * Optionally, can be supplied with a function acting as a stopping condition.
1205 * This function takes the dapm widget currently being examined and the walk
1206 * direction as an arguments, it should return true if the walk should be
1207 * stopped and false otherwise.
1208 *
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001209 * Returns the number of valid paths or negative error.
1210 */
1211int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001212 struct snd_soc_dapm_widget_list **list,
1213 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1214 enum snd_soc_dapm_direction))
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001215{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001216 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001217 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001218 LIST_HEAD(widgets);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001219 int paths;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001220 int ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001221
1222 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001223
1224 /*
1225 * For is_connected_{output,input}_ep fully discover the graph we need
1226 * to reset the cached number of inputs and outputs.
1227 */
1228 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001229 w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
1230 w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001231 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001232
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001233 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001234 paths = is_connected_output_ep(dai->playback_widget, &widgets,
1235 custom_stop_condition);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001236 else
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001237 paths = is_connected_input_ep(dai->capture_widget, &widgets,
1238 custom_stop_condition);
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001239
1240 /* Drop starting point */
1241 list_del(widgets.next);
1242
1243 ret = dapm_widget_list_create(list, &widgets);
1244 if (ret)
Lars-Peter Clausen30abbe72015-08-11 21:37:59 +02001245 paths = ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001246
1247 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001248 mutex_unlock(&card->dapm_mutex);
1249
1250 return paths;
1251}
1252
Richard Purdie2b97eab2006-10-06 18:32:18 +02001253/*
Mark Brown62ea8742012-01-21 21:14:48 +00001254 * Handler for regulator supply widget.
1255 */
1256int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1257 struct snd_kcontrol *kcontrol, int event)
1258{
Mark Brownc05b84d2012-09-07 12:57:11 +08001259 int ret;
1260
Mark Browneb270e92013-10-09 13:52:52 +01001261 soc_dapm_async_complete(w->dapm);
1262
Mark Brownc05b84d2012-09-07 12:57:11 +08001263 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001264 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001265 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001266 if (ret != 0)
1267 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001268 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001269 w->name, ret);
1270 }
1271
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001272 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001273 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001274 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001275 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001276 if (ret != 0)
1277 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001278 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001279 w->name, ret);
1280 }
1281
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001282 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001283 }
Mark Brown62ea8742012-01-21 21:14:48 +00001284}
1285EXPORT_SYMBOL_GPL(dapm_regulator_event);
1286
Ola Liljad7e7eb92012-05-24 15:26:25 +02001287/*
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00001288 * Handler for pinctrl widget.
1289 */
1290int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
1291 struct snd_kcontrol *kcontrol, int event)
1292{
1293 struct snd_soc_dapm_pinctrl_priv *priv = w->priv;
1294 struct pinctrl *p = w->pinctrl;
1295 struct pinctrl_state *s;
1296
1297 if (!p || !priv)
1298 return -EIO;
1299
1300 if (SND_SOC_DAPM_EVENT_ON(event))
1301 s = pinctrl_lookup_state(p, priv->active_state);
1302 else
1303 s = pinctrl_lookup_state(p, priv->sleep_state);
1304
1305 if (IS_ERR(s))
1306 return PTR_ERR(s);
1307
1308 return pinctrl_select_state(p, s);
1309}
1310EXPORT_SYMBOL_GPL(dapm_pinctrl_event);
1311
1312/*
Ola Liljad7e7eb92012-05-24 15:26:25 +02001313 * Handler for clock supply widget.
1314 */
1315int dapm_clock_event(struct snd_soc_dapm_widget *w,
1316 struct snd_kcontrol *kcontrol, int event)
1317{
1318 if (!w->clk)
1319 return -EIO;
1320
Mark Browneb270e92013-10-09 13:52:52 +01001321 soc_dapm_async_complete(w->dapm);
1322
Mark Brownec029952012-06-04 08:16:20 +01001323#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001324 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001325 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001326 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001327 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001328 return 0;
1329 }
Mark Brownec029952012-06-04 08:16:20 +01001330#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001331 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001332}
1333EXPORT_SYMBOL_GPL(dapm_clock_event);
1334
Mark Brownd805002b2011-09-28 18:28:23 +01001335static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1336{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001337 if (w->power_checked)
1338 return w->new_power;
1339
Mark Brownd805002b2011-09-28 18:28:23 +01001340 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001341 w->new_power = 1;
Mark Brownd805002b2011-09-28 18:28:23 +01001342 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001343 w->new_power = w->power_check(w);
1344
1345 w->power_checked = true;
1346
1347 return w->new_power;
Mark Brownd805002b2011-09-28 18:28:23 +01001348}
1349
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001350/* Generic check to see if a widget should be powered. */
Mark Browncd0f2d42009-04-20 16:56:59 +01001351static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1352{
1353 int in, out;
1354
Mark Brownde02d072011-09-20 21:43:24 +01001355 DAPM_UPDATE_STAT(w, power_checks);
1356
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001357 in = is_connected_input_ep(w, NULL, NULL);
1358 out = is_connected_output_ep(w, NULL, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001359 return out != 0 && in != 0;
1360}
1361
Mark Brown246d0a12009-04-22 18:24:55 +01001362/* Check to see if a power supply is needed */
1363static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1364{
1365 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001366
Mark Brownde02d072011-09-20 21:43:24 +01001367 DAPM_UPDATE_STAT(w, power_checks);
1368
Mark Brown246d0a12009-04-22 18:24:55 +01001369 /* Check if one of our outputs is connected */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001370 snd_soc_dapm_widget_for_each_sink_path(w, path) {
Mark Browna8fdac82011-09-28 18:20:26 +01001371 DAPM_UPDATE_STAT(w, neighbour_checks);
1372
Mark Brownbf3a9e12011-06-13 16:42:29 +01001373 if (path->weak)
1374 continue;
1375
Mark Brown215edda2009-09-08 18:59:05 +01001376 if (path->connected &&
1377 !path->connected(path->source, path->sink))
1378 continue;
1379
Mark Brownf68d7e12011-10-04 22:57:50 +01001380 if (dapm_widget_power_check(path->sink))
1381 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001382 }
1383
Mark Brownf68d7e12011-10-04 22:57:50 +01001384 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001385}
1386
Mark Brown35c64bc2011-09-28 18:23:53 +01001387static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1388{
Charles Keepax20bb0182015-12-02 10:22:16 +00001389 return w->connected;
Mark Brown35c64bc2011-09-28 18:23:53 +01001390}
1391
Mark Brown38357ab2009-06-06 19:03:23 +01001392static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1393 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001394 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001395{
Mark Brown828a8422011-01-15 13:14:30 +00001396 int *sort;
1397
1398 if (power_up)
1399 sort = dapm_up_seq;
1400 else
1401 sort = dapm_down_seq;
1402
Mark Brown38357ab2009-06-06 19:03:23 +01001403 if (sort[a->id] != sort[b->id])
1404 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001405 if (a->subseq != b->subseq) {
1406 if (power_up)
1407 return a->subseq - b->subseq;
1408 else
1409 return b->subseq - a->subseq;
1410 }
Mark Brownb22ead22009-06-07 12:51:26 +01001411 if (a->reg != b->reg)
1412 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001413 if (a->dapm != b->dapm)
1414 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001415
Mark Brown38357ab2009-06-06 19:03:23 +01001416 return 0;
1417}
Mark Brown42aa3412009-03-01 19:21:10 +00001418
Mark Brown38357ab2009-06-06 19:03:23 +01001419/* Insert a widget in order into a DAPM power sequence. */
1420static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1421 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001422 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001423{
1424 struct snd_soc_dapm_widget *w;
1425
1426 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001427 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001428 list_add_tail(&new_widget->power_list, &w->power_list);
1429 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001430 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001431
Mark Brown38357ab2009-06-06 19:03:23 +01001432 list_add_tail(&new_widget->power_list, list);
1433}
Mark Brown42aa3412009-03-01 19:21:10 +00001434
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001435static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001436 struct snd_soc_dapm_widget *w, int event)
1437{
Mark Brown68f89ad2010-11-03 23:51:49 -04001438 const char *ev_name;
1439 int power, ret;
1440
1441 switch (event) {
1442 case SND_SOC_DAPM_PRE_PMU:
1443 ev_name = "PRE_PMU";
1444 power = 1;
1445 break;
1446 case SND_SOC_DAPM_POST_PMU:
1447 ev_name = "POST_PMU";
1448 power = 1;
1449 break;
1450 case SND_SOC_DAPM_PRE_PMD:
1451 ev_name = "PRE_PMD";
1452 power = 0;
1453 break;
1454 case SND_SOC_DAPM_POST_PMD:
1455 ev_name = "POST_PMD";
1456 power = 0;
1457 break;
Mark Brown80114122013-02-25 15:14:19 +00001458 case SND_SOC_DAPM_WILL_PMU:
1459 ev_name = "WILL_PMU";
1460 power = 1;
1461 break;
1462 case SND_SOC_DAPM_WILL_PMD:
1463 ev_name = "WILL_PMD";
1464 power = 0;
1465 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001466 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001467 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001468 return;
1469 }
1470
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001471 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001472 return;
1473
1474 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001475 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001476 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001477 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001478 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001479 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001480 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001481 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001482 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001483 ev_name, w->name, ret);
1484 }
1485}
1486
Mark Brownb22ead22009-06-07 12:51:26 +01001487/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001488static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001489 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001490{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001491 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001492 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001493 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001494 unsigned int value = 0;
1495 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001496
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001497 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1498 reg = w->reg;
1499 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001500
1501 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001502 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001503 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001504
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001505 mask |= w->mask << w->shift;
1506 if (w->power)
1507 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001508 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001509 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001510
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001511 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001512 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1513 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001514
Mark Brown68f89ad2010-11-03 23:51:49 -04001515 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001516 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1517 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001518 }
1519
Mark Brown81628102009-06-07 13:21:24 +01001520 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001521 /* Any widget will do, they should all be updating the
1522 * same register.
1523 */
Mark Brown29376bc2011-06-19 13:49:28 +01001524
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001525 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001526 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001527 value, mask, reg, card->pop_time);
1528 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001529 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001530 }
1531
1532 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001533 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1534 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001535 }
Mark Brown42aa3412009-03-01 19:21:10 +00001536}
1537
Mark Brownb22ead22009-06-07 12:51:26 +01001538/* Apply a DAPM power sequence.
1539 *
1540 * We walk over a pre-sorted list of widgets to apply power to. In
1541 * order to minimise the number of writes to the device required
1542 * multiple widgets will be updated in a single write where possible.
1543 * Currently anything that requires more than a single write is not
1544 * handled.
1545 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001546static void dapm_seq_run(struct snd_soc_card *card,
1547 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001548{
1549 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001550 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001551 LIST_HEAD(pending);
1552 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001553 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001554 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001555 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001556 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001557 int *sort;
1558
1559 if (power_up)
1560 sort = dapm_up_seq;
1561 else
1562 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001563
Mark Brownb22ead22009-06-07 12:51:26 +01001564 list_for_each_entry_safe(w, n, list, power_list) {
1565 ret = 0;
1566
1567 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001568 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001569 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001570 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001571 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001572
Mark Brown474b62d2011-01-18 16:14:44 +00001573 if (cur_dapm && cur_dapm->seq_notifier) {
1574 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1575 if (sort[i] == cur_sort)
1576 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001577 i,
1578 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001579 }
1580
Mark Browneb270e92013-10-09 13:52:52 +01001581 if (cur_dapm && w->dapm != cur_dapm)
1582 soc_dapm_async_complete(cur_dapm);
1583
Mark Brownb22ead22009-06-07 12:51:26 +01001584 INIT_LIST_HEAD(&pending);
1585 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001586 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001587 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001588 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001589 }
1590
Mark Brown163cac02009-06-07 10:12:52 +01001591 switch (w->id) {
1592 case snd_soc_dapm_pre:
1593 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001594 list_for_each_entry_safe_continue(w, n, list,
1595 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001596
Mark Brownb22ead22009-06-07 12:51:26 +01001597 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001598 ret = w->event(w,
1599 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001600 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001601 ret = w->event(w,
1602 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001603 break;
1604
1605 case snd_soc_dapm_post:
1606 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001607 list_for_each_entry_safe_continue(w, n, list,
1608 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001609
Mark Brownb22ead22009-06-07 12:51:26 +01001610 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001611 ret = w->event(w,
1612 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001613 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001614 ret = w->event(w,
1615 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001616 break;
1617
Mark Brown163cac02009-06-07 10:12:52 +01001618 default:
Mark Brown81628102009-06-07 13:21:24 +01001619 /* Queue it up for application */
1620 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001621 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001622 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001623 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001624 list_move(&w->power_list, &pending);
1625 break;
Mark Brown163cac02009-06-07 10:12:52 +01001626 }
Mark Brownb22ead22009-06-07 12:51:26 +01001627
1628 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001629 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001630 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001631 }
Mark Brownb22ead22009-06-07 12:51:26 +01001632
1633 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001634 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001635
1636 if (cur_dapm && cur_dapm->seq_notifier) {
1637 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1638 if (sort[i] == cur_sort)
1639 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001640 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001641 }
Mark Browneb270e92013-10-09 13:52:52 +01001642
1643 list_for_each_entry(d, &card->dapm_list, list) {
1644 soc_dapm_async_complete(d);
1645 }
Mark Brown163cac02009-06-07 10:12:52 +01001646}
1647
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001648static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001649{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001650 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001651 struct snd_soc_dapm_widget_list *wlist;
1652 struct snd_soc_dapm_widget *w = NULL;
1653 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001654 int ret;
1655
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001656 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001657 return;
1658
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001659 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001660
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001661 for (wi = 0; wi < wlist->num_widgets; wi++) {
1662 w = wlist->widgets[wi];
1663
1664 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1665 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1666 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001667 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001668 w->name, ret);
1669 }
Mark Brown97404f22010-12-14 16:13:57 +00001670 }
1671
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001672 if (!w)
1673 return;
1674
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001675 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1676 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001677 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001678 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001679 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001680
Chen-Yu Tsaie411b0b2016-11-02 15:35:58 +08001681 if (update->has_second_set) {
1682 ret = soc_dapm_update_bits(w->dapm, update->reg2,
1683 update->mask2, update->val2);
1684 if (ret < 0)
1685 dev_err(w->dapm->dev,
1686 "ASoC: %s DAPM update failed: %d\n",
1687 w->name, ret);
1688 }
1689
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001690 for (wi = 0; wi < wlist->num_widgets; wi++) {
1691 w = wlist->widgets[wi];
1692
1693 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1694 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1695 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001696 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001697 w->name, ret);
1698 }
Mark Brown97404f22010-12-14 16:13:57 +00001699 }
1700}
1701
Mark Brown9d0624a2011-02-18 11:49:43 -08001702/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1703 * they're changing state.
1704 */
1705static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1706{
1707 struct snd_soc_dapm_context *d = data;
1708 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001709
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001710 /* If we're off and we're not supposed to go into STANDBY */
Mark Brown56fba412011-06-04 11:25:10 +01001711 if (d->bias_level == SND_SOC_BIAS_OFF &&
1712 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001713 if (d->dev)
1714 pm_runtime_get_sync(d->dev);
1715
Mark Brown9d0624a2011-02-18 11:49:43 -08001716 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1717 if (ret != 0)
1718 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001719 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001720 }
1721
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001722 /* Prepare for a transition to ON or away from ON */
1723 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1724 d->bias_level != SND_SOC_BIAS_ON) ||
1725 (d->target_bias_level != SND_SOC_BIAS_ON &&
1726 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001727 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1728 if (ret != 0)
1729 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001730 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001731 }
1732}
1733
1734/* Async callback run prior to DAPM sequences - brings to their final
1735 * state.
1736 */
1737static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1738{
1739 struct snd_soc_dapm_context *d = data;
1740 int ret;
1741
1742 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001743 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1744 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1745 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001746 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1747 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001748 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001749 ret);
1750 }
1751
1752 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001753 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1754 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001755 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1756 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001757 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1758 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001759
1760 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001761 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001762 }
1763
1764 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001765 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1766 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001767 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1768 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001769 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001770 ret);
1771 }
1772}
Mark Brown97404f22010-12-14 16:13:57 +00001773
Mark Brownfe4fda52011-10-03 22:36:57 +01001774static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1775 bool power, bool connect)
1776{
1777 /* If a connection is being made or broken then that update
1778 * will have marked the peer dirty, otherwise the widgets are
1779 * not connected and this update has no impact. */
1780 if (!connect)
1781 return;
1782
1783 /* If the peer is already in the state we're moving to then we
1784 * won't have an impact on it. */
1785 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001786 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001787}
1788
Mark Brown05623c42011-09-28 17:02:31 +01001789static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1790 struct list_head *up_list,
1791 struct list_head *down_list)
1792{
Mark Browndb432b42011-10-03 21:06:40 +01001793 struct snd_soc_dapm_path *path;
1794
Mark Brown05623c42011-09-28 17:02:31 +01001795 if (w->power == power)
1796 return;
1797
1798 trace_snd_soc_dapm_widget_power(w, power);
1799
Mark Browndb432b42011-10-03 21:06:40 +01001800 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001801 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001802 */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001803 snd_soc_dapm_widget_for_each_source_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001804 dapm_widget_set_peer_power(path->source, power, path->connect);
1805
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001806 /* Supplies can't affect their outputs, only their inputs */
1807 if (!w->is_supply) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001808 snd_soc_dapm_widget_for_each_sink_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001809 dapm_widget_set_peer_power(path->sink, power,
1810 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001811 }
1812
Mark Brown05623c42011-09-28 17:02:31 +01001813 if (power)
1814 dapm_seq_insert(w, up_list, true);
1815 else
1816 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001817}
1818
Mark Brown7c81beb2011-09-20 22:22:32 +01001819static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1820 struct list_head *up_list,
1821 struct list_head *down_list)
1822{
Mark Brown7c81beb2011-09-20 22:22:32 +01001823 int power;
1824
1825 switch (w->id) {
1826 case snd_soc_dapm_pre:
1827 dapm_seq_insert(w, down_list, false);
1828 break;
1829 case snd_soc_dapm_post:
1830 dapm_seq_insert(w, up_list, true);
1831 break;
1832
1833 default:
Mark Brownd805002b2011-09-28 18:28:23 +01001834 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001835
Mark Brown05623c42011-09-28 17:02:31 +01001836 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001837 break;
1838 }
1839}
1840
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001841static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1842{
1843 if (dapm->idle_bias_off)
1844 return true;
1845
1846 switch (snd_power_get_state(dapm->card->snd_card)) {
1847 case SNDRV_CTL_POWER_D3hot:
1848 case SNDRV_CTL_POWER_D3cold:
1849 return dapm->suspend_bias_off;
1850 default:
1851 break;
1852 }
1853
1854 return false;
1855}
1856
Mark Brown42aa3412009-03-01 19:21:10 +00001857/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001858 * Scan each dapm widget for complete audio path.
1859 * A complete path is a route that has valid endpoints i.e.:-
1860 *
1861 * o DAC to output pin.
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001862 * o Input pin to ADC.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001863 * o Input pin to Output pin (bypass, sidetone)
1864 * o DAC to ADC (loopback).
1865 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001866static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001867{
1868 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001869 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001870 LIST_HEAD(up_list);
1871 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001872 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001873 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001874
Mark Brownf9fa2b12014-03-06 16:49:11 +08001875 lockdep_assert_held(&card->dapm_mutex);
1876
Mark Brown84e90932010-11-04 00:07:02 -04001877 trace_snd_soc_dapm_start(card);
1878
Mark Brown56fba412011-06-04 11:25:10 +01001879 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001880 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001881 d->target_bias_level = SND_SOC_BIAS_OFF;
1882 else
1883 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001884 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001885
Liam Girdwood6c120e12012-02-15 15:15:34 +00001886 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001887
Mark Brown6d3ddc82009-05-16 17:47:29 +01001888 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001889 * lists indicating if they should be powered up or down. We
1890 * only check widgets that have been flagged as dirty but note
1891 * that new widgets may be added to the dirty list while we
1892 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001893 */
Mark Browndb432b42011-10-03 21:06:40 +01001894 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001895 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001896 }
1897
Mark Brownf9de6d72011-09-28 17:19:47 +01001898 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001899 switch (w->id) {
1900 case snd_soc_dapm_pre:
1901 case snd_soc_dapm_post:
1902 /* These widgets always need to be powered */
1903 break;
1904 default:
1905 list_del_init(&w->dirty);
1906 break;
1907 }
Mark Browndb432b42011-10-03 21:06:40 +01001908
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001909 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001910 d = w->dapm;
1911
1912 /* Supplies and micbiases only bring the
1913 * context up to STANDBY as unless something
1914 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001915 * generally don't require full power. Signal
1916 * generators are virtual pins and have no
1917 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001918 */
1919 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001920 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001921 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001922 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001923 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001924 case snd_soc_dapm_regulator_supply:
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00001925 case snd_soc_dapm_pinctrl:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001926 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001927 case snd_soc_dapm_micbias:
1928 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1929 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1930 break;
1931 default:
1932 d->target_bias_level = SND_SOC_BIAS_ON;
1933 break;
1934 }
1935 }
1936
1937 }
1938
Mark Brown85a843c2011-09-21 21:29:47 +01001939 /* Force all contexts in the card to the same bias state if
1940 * they're not ground referenced.
1941 */
Mark Brown56fba412011-06-04 11:25:10 +01001942 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001943 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001944 if (d->target_bias_level > bias)
1945 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001946 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001947 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001948 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001949
Mark Brownde02d072011-09-20 21:43:24 +01001950 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001951
Xiang Xiao17282ba2014-03-02 00:04:03 +08001952 /* Run card bias changes at first */
1953 dapm_pre_sequence_async(&card->dapm, 0);
1954 /* Run other bias changes in parallel */
1955 list_for_each_entry(d, &card->dapm_list, list) {
1956 if (d != &card->dapm)
1957 async_schedule_domain(dapm_pre_sequence_async, d,
1958 &async_domain);
1959 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001960 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001961
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001962 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001963 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001964 }
1965
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001966 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001967 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001968 }
1969
Mark Brown6d3ddc82009-05-16 17:47:29 +01001970 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001971 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001972
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001973 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001974
Mark Brown6d3ddc82009-05-16 17:47:29 +01001975 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001976 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001977
Mark Brown9d0624a2011-02-18 11:49:43 -08001978 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001979 list_for_each_entry(d, &card->dapm_list, list) {
1980 if (d != &card->dapm)
1981 async_schedule_domain(dapm_post_sequence_async, d,
1982 &async_domain);
1983 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001984 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001985 /* Run card bias changes at last */
1986 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001987
Liam Girdwood8078d872012-02-15 15:15:35 +00001988 /* do we need to notify any clients that DAPM event is complete */
1989 list_for_each_entry(d, &card->dapm_list, list) {
1990 if (d->stream_event)
1991 d->stream_event(d, event);
1992 }
1993
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001994 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001995 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001996 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001997
Mark Brown84e90932010-11-04 00:07:02 -04001998 trace_snd_soc_dapm_done(card);
1999
Mark Brown42aa3412009-03-01 19:21:10 +00002000 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002001}
2002
Mark Brown79fb9382009-08-21 16:38:13 +01002003#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01002004static ssize_t dapm_widget_power_read_file(struct file *file,
2005 char __user *user_buf,
2006 size_t count, loff_t *ppos)
2007{
2008 struct snd_soc_dapm_widget *w = file->private_data;
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002009 struct snd_soc_card *card = w->dapm->card;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002010 enum snd_soc_dapm_direction dir, rdir;
Mark Brown79fb9382009-08-21 16:38:13 +01002011 char *buf;
2012 int in, out;
2013 ssize_t ret;
2014 struct snd_soc_dapm_path *p = NULL;
2015
2016 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2017 if (!buf)
2018 return -ENOMEM;
2019
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002020 mutex_lock(&card->dapm_mutex);
2021
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002022 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
2023 if (w->is_supply) {
2024 in = 0;
2025 out = 0;
2026 } else {
Piotr Stankiewicz67420642016-05-13 17:03:55 +01002027 in = is_connected_input_ep(w, NULL, NULL);
2028 out = is_connected_output_ep(w, NULL, NULL);
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002029 }
Mark Brown79fb9382009-08-21 16:38:13 +01002030
Mark Brownf13ebad2012-03-03 18:01:01 +00002031 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
2032 w->name, w->power ? "On" : "Off",
2033 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01002034
Mark Brownd033c362009-12-04 15:25:56 +00002035 if (w->reg >= 0)
2036 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002037 " - R%d(0x%x) mask 0x%x",
2038 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00002039
2040 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
2041
Mark Brown3eef08b2009-09-14 16:49:00 +01002042 if (w->sname)
2043 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
2044 w->sname,
2045 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01002046
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002047 snd_soc_dapm_for_each_direction(dir) {
2048 rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
2049 snd_soc_dapm_widget_for_each_path(w, dir, p) {
KaiChieh Chuang28735af2018-02-05 13:00:00 +08002050 if (p->connected && !p->connected(p->source, p->sink))
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002051 continue;
Mark Brown215edda2009-09-08 18:59:05 +01002052
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002053 if (!p->connect)
2054 continue;
Mark Brown215edda2009-09-08 18:59:05 +01002055
Mark Brown79fb9382009-08-21 16:38:13 +01002056 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002057 " %s \"%s\" \"%s\"\n",
2058 (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
Mark Brown79fb9382009-08-21 16:38:13 +01002059 p->name ? p->name : "static",
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002060 p->node[rdir]->name);
2061 }
Mark Brown79fb9382009-08-21 16:38:13 +01002062 }
2063
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002064 mutex_unlock(&card->dapm_mutex);
2065
Mark Brown79fb9382009-08-21 16:38:13 +01002066 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
2067
2068 kfree(buf);
2069 return ret;
2070}
2071
2072static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002073 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01002074 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002075 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01002076};
2077
Mark Brownef49e4f2011-04-04 20:48:13 +09002078static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
2079 size_t count, loff_t *ppos)
2080{
2081 struct snd_soc_dapm_context *dapm = file->private_data;
2082 char *level;
2083
2084 switch (dapm->bias_level) {
2085 case SND_SOC_BIAS_ON:
2086 level = "On\n";
2087 break;
2088 case SND_SOC_BIAS_PREPARE:
2089 level = "Prepare\n";
2090 break;
2091 case SND_SOC_BIAS_STANDBY:
2092 level = "Standby\n";
2093 break;
2094 case SND_SOC_BIAS_OFF:
2095 level = "Off\n";
2096 break;
2097 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002098 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002099 level = "Unknown\n";
2100 break;
2101 }
2102
2103 return simple_read_from_buffer(user_buf, count, ppos, level,
2104 strlen(level));
2105}
2106
2107static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002108 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002109 .read = dapm_bias_read_file,
2110 .llseek = default_llseek,
2111};
2112
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002113void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2114 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002115{
Mark Brown79fb9382009-08-21 16:38:13 +01002116 struct dentry *d;
2117
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002118 if (!parent)
2119 return;
2120
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002121 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2122
2123 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002124 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002125 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002126 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002127 }
Mark Brown79fb9382009-08-21 16:38:13 +01002128
Mark Brownef49e4f2011-04-04 20:48:13 +09002129 d = debugfs_create_file("bias_level", 0444,
2130 dapm->debugfs_dapm, dapm,
2131 &dapm_bias_fops);
2132 if (!d)
2133 dev_warn(dapm->dev,
2134 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002135}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002136
2137static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2138{
2139 struct snd_soc_dapm_context *dapm = w->dapm;
2140 struct dentry *d;
2141
2142 if (!dapm->debugfs_dapm || !w->name)
2143 return;
2144
2145 d = debugfs_create_file(w->name, 0444,
2146 dapm->debugfs_dapm, w,
2147 &dapm_widget_power_fops);
2148 if (!d)
2149 dev_warn(w->dapm->dev,
2150 "ASoC: Failed to create %s debugfs file\n",
2151 w->name);
2152}
2153
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002154static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2155{
2156 debugfs_remove_recursive(dapm->debugfs_dapm);
2157}
2158
Mark Brown79fb9382009-08-21 16:38:13 +01002159#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002160void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2161 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002162{
2163}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002164
2165static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2166{
2167}
2168
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002169static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2170{
2171}
2172
Mark Brown79fb9382009-08-21 16:38:13 +01002173#endif
2174
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002175/*
2176 * soc_dapm_connect_path() - Connects or disconnects a path
2177 * @path: The path to update
2178 * @connect: The new connect state of the path. True if the path is connected,
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002179 * false if it is disconnected.
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002180 * @reason: The reason why the path changed (for debugging only)
2181 */
2182static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2183 bool connect, const char *reason)
2184{
2185 if (path->connect == connect)
2186 return;
2187
2188 path->connect = connect;
2189 dapm_mark_dirty(path->source, reason);
2190 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002191 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002192}
2193
Richard Purdie2b97eab2006-10-06 18:32:18 +02002194/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002195static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002196 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002197{
2198 struct snd_soc_dapm_path *path;
2199 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002200 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002201
Mark Brownf9fa2b12014-03-06 16:49:11 +08002202 lockdep_assert_held(&card->dapm_mutex);
2203
Richard Purdie2b97eab2006-10-06 18:32:18 +02002204 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002205 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002206 found = 1;
2207 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002208 if (!(strcmp(path->name, e->texts[mux])))
2209 connect = true;
2210 else
2211 connect = false;
2212
2213 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002214 }
2215
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002216 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002217 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002218
Liam Girdwood618dae12012-04-25 12:12:51 +01002219 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002220}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002221
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002222int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002223 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2224 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002225{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002226 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002227 int ret;
2228
Liam Girdwood3cd04342012-03-09 12:02:08 +00002229 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002230 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002231 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002232 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002233 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002234 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002235 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002236 return ret;
2237}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002238EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002239
Milan plzik1b075e32008-01-10 14:39:46 +01002240/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002241static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002242 struct snd_kcontrol *kcontrol,
2243 int connect, int rconnect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002244{
2245 struct snd_soc_dapm_path *path;
2246 int found = 0;
2247
Mark Brownf9fa2b12014-03-06 16:49:11 +08002248 lockdep_assert_held(&card->dapm_mutex);
2249
Richard Purdie2b97eab2006-10-06 18:32:18 +02002250 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002251 dapm_kcontrol_for_each_path(path, kcontrol) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002252 /*
2253 * Ideally this function should support any number of
2254 * paths and channels. But since kcontrols only come
2255 * in mono and stereo variants, we are limited to 2
2256 * channels.
2257 *
2258 * The following code assumes for stereo controls the
2259 * first path (when 'found == 0') is the left channel,
2260 * and all remaining paths (when 'found == 1') are the
2261 * right channel.
2262 *
2263 * A stereo control is signified by a valid 'rconnect'
2264 * value, either 0 for unconnected, or >= 0 for connected.
2265 * This is chosen instead of using snd_soc_volsw_is_stereo,
2266 * so that the behavior of snd_soc_dapm_mixer_update_power
2267 * doesn't change even when the kcontrol passed in is
2268 * stereo.
2269 *
2270 * It passes 'connect' as the path connect status for
2271 * the left channel, and 'rconnect' for the right
2272 * channel.
2273 */
2274 if (found && rconnect >= 0)
2275 soc_dapm_connect_path(path, rconnect, "mixer update");
2276 else
2277 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002278 found = 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002279 }
2280
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002281 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002282 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002283
Liam Girdwood618dae12012-04-25 12:12:51 +01002284 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002285}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002286
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002287int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002288 struct snd_kcontrol *kcontrol, int connect,
2289 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002290{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002291 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002292 int ret;
2293
Liam Girdwood3cd04342012-03-09 12:02:08 +00002294 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002295 card->update = update;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002296 ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002297 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002298 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002299 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002300 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002301 return ret;
2302}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002303EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002304
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002305static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
2306 char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002307{
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002308 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002309 struct snd_soc_dapm_widget *w;
2310 int count = 0;
2311 char *state = "not set";
2312
Mark Brown47325072016-03-18 12:04:23 +00002313 /* card won't be set for the dummy component, as a spot fix
2314 * we're checking for that case specifically here but in future
2315 * we will ensure that the dummy component looks like others.
2316 */
2317 if (!cmpnt->card)
2318 return 0;
2319
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002320 list_for_each_entry(w, &cmpnt->card->widgets, list) {
2321 if (w->dapm != dapm)
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002322 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002323
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002324 /* only display widgets that burn power */
Richard Purdie2b97eab2006-10-06 18:32:18 +02002325 switch (w->id) {
2326 case snd_soc_dapm_hp:
2327 case snd_soc_dapm_mic:
2328 case snd_soc_dapm_spk:
2329 case snd_soc_dapm_line:
2330 case snd_soc_dapm_micbias:
2331 case snd_soc_dapm_dac:
2332 case snd_soc_dapm_adc:
2333 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002334 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002335 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002336 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002337 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002338 case snd_soc_dapm_regulator_supply:
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00002339 case snd_soc_dapm_pinctrl:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002340 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002341 if (w->name)
2342 count += sprintf(buf + count, "%s: %s\n",
2343 w->name, w->power ? "On":"Off");
2344 break;
2345 default:
2346 break;
2347 }
2348 }
2349
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002350 switch (snd_soc_dapm_get_bias_level(dapm)) {
Mark Brown0be98982008-05-19 12:31:28 +02002351 case SND_SOC_BIAS_ON:
2352 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002353 break;
Mark Brown0be98982008-05-19 12:31:28 +02002354 case SND_SOC_BIAS_PREPARE:
2355 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002356 break;
Mark Brown0be98982008-05-19 12:31:28 +02002357 case SND_SOC_BIAS_STANDBY:
2358 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002359 break;
Mark Brown0be98982008-05-19 12:31:28 +02002360 case SND_SOC_BIAS_OFF:
2361 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002362 break;
2363 }
2364 count += sprintf(buf + count, "PM State: %s\n", state);
2365
2366 return count;
2367}
2368
Benoit Cousson44ba2642014-07-08 23:19:36 +02002369/* show dapm widget status in sys fs */
2370static ssize_t dapm_widget_show(struct device *dev,
2371 struct device_attribute *attr, char *buf)
2372{
2373 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2374 int i, count = 0;
2375
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002376 mutex_lock(&rtd->card->dapm_mutex);
2377
Benoit Cousson44ba2642014-07-08 23:19:36 +02002378 for (i = 0; i < rtd->num_codecs; i++) {
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002379 struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component;
2380
2381 count += dapm_widget_show_component(cmpnt, buf + count);
Benoit Cousson44ba2642014-07-08 23:19:36 +02002382 }
2383
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002384 mutex_unlock(&rtd->card->dapm_mutex);
2385
Benoit Cousson44ba2642014-07-08 23:19:36 +02002386 return count;
2387}
2388
Joe Perchesc828a892017-12-19 10:15:08 -08002389static DEVICE_ATTR_RO(dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002390
Takashi Iwaid29697d2015-01-30 20:16:37 +01002391struct attribute *soc_dapm_dev_attrs[] = {
2392 &dev_attr_dapm_widget.attr,
2393 NULL
2394};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002395
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002396static void dapm_free_path(struct snd_soc_dapm_path *path)
2397{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002398 list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
2399 list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002400 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002401 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002402 kfree(path);
2403}
2404
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002405void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2406{
2407 struct snd_soc_dapm_path *p, *next_p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002408 enum snd_soc_dapm_direction dir;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002409
2410 list_del(&w->list);
2411 /*
2412 * remove source and sink paths associated to this widget.
2413 * While removing the path, remove reference to it from both
2414 * source and sink widgets so that path is removed only once.
2415 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002416 snd_soc_dapm_for_each_direction(dir) {
2417 snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
2418 dapm_free_path(p);
2419 }
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002420
2421 kfree(w->kcontrols);
Lars-Peter Clausen48068962015-07-21 18:11:08 +02002422 kfree_const(w->name);
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002423 kfree(w);
2424}
2425
Jyri Sarhafd589a12015-11-10 18:12:42 +02002426void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
2427{
2428 dapm->path_sink_cache.widget = NULL;
2429 dapm->path_source_cache.widget = NULL;
2430}
2431
Richard Purdie2b97eab2006-10-06 18:32:18 +02002432/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002433static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002434{
2435 struct snd_soc_dapm_widget *w, *next_w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002436
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002437 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2438 if (w->dapm != dapm)
2439 continue;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002440 snd_soc_dapm_free_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002441 }
Jyri Sarhafd589a12015-11-10 18:12:42 +02002442 snd_soc_dapm_reset_cache(dapm);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002443}
2444
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002445static struct snd_soc_dapm_widget *dapm_find_widget(
2446 struct snd_soc_dapm_context *dapm, const char *pin,
2447 bool search_other_contexts)
2448{
2449 struct snd_soc_dapm_widget *w;
2450 struct snd_soc_dapm_widget *fallback = NULL;
2451
2452 list_for_each_entry(w, &dapm->card->widgets, list) {
2453 if (!strcmp(w->name, pin)) {
2454 if (w->dapm == dapm)
2455 return w;
2456 else
2457 fallback = w;
2458 }
2459 }
2460
2461 if (search_other_contexts)
2462 return fallback;
2463
2464 return NULL;
2465}
2466
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002467static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002468 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002469{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002470 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002471
Mark Brownf9fa2b12014-03-06 16:49:11 +08002472 dapm_assert_locked(dapm);
2473
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002474 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002475 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002476 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002477 }
2478
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002479 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002480 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002481 dapm_widget_invalidate_input_paths(w);
2482 dapm_widget_invalidate_output_paths(w);
2483 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002484
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002485 w->connected = status;
2486 if (status == 0)
2487 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002488
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002489 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002490}
2491
Richard Purdie2b97eab2006-10-06 18:32:18 +02002492/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002493 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2494 * @dapm: DAPM context
2495 *
2496 * Walks all dapm audio paths and powers widgets according to their
2497 * stream or path usage.
2498 *
2499 * Requires external locking.
2500 *
2501 * Returns 0 for success.
2502 */
2503int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2504{
2505 /*
2506 * Suppress early reports (eg, jacks syncing their state) to avoid
2507 * silly DAPM runs during card startup.
2508 */
2509 if (!dapm->card || !dapm->card->instantiated)
2510 return 0;
2511
2512 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2513}
2514EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2515
2516/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002517 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002518 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002519 *
2520 * Walks all dapm audio paths and powers widgets according to their
2521 * stream or path usage.
2522 *
2523 * Returns 0 for success.
2524 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002525int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002526{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002527 int ret;
2528
Liam Girdwood3cd04342012-03-09 12:02:08 +00002529 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002530 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002531 mutex_unlock(&dapm->card->dapm_mutex);
2532 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002533}
Liam Girdwooda5302182008-07-07 13:35:17 +01002534EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002535
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002536/*
2537 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2538 * @w: The widget for which to update the flags
2539 *
2540 * Some widgets have a dynamic category which depends on which neighbors they
2541 * are connected to. This function update the category for these widgets.
2542 *
2543 * This function must be called whenever a path is added or removed to a widget.
2544 */
2545static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2546{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002547 enum snd_soc_dapm_direction dir;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002548 struct snd_soc_dapm_path *p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002549 unsigned int ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002550
2551 switch (w->id) {
2552 case snd_soc_dapm_input:
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002553 /* On a fully routed card an input is never a source */
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002554 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002555 return;
2556 ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002557 snd_soc_dapm_widget_for_each_source_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002558 if (p->source->id == snd_soc_dapm_micbias ||
2559 p->source->id == snd_soc_dapm_mic ||
2560 p->source->id == snd_soc_dapm_line ||
2561 p->source->id == snd_soc_dapm_output) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002562 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002563 break;
2564 }
2565 }
2566 break;
2567 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002568 /* On a fully routed card a output is never a sink */
2569 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002570 return;
2571 ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002572 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002573 if (p->sink->id == snd_soc_dapm_spk ||
2574 p->sink->id == snd_soc_dapm_hp ||
2575 p->sink->id == snd_soc_dapm_line ||
2576 p->sink->id == snd_soc_dapm_input) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002577 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002578 break;
2579 }
2580 }
2581 break;
2582 case snd_soc_dapm_line:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002583 ep = 0;
2584 snd_soc_dapm_for_each_direction(dir) {
2585 if (!list_empty(&w->edges[dir]))
2586 ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
2587 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002588 break;
2589 default:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002590 return;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002591 }
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002592
2593 w->is_ep = ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002594}
2595
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002596static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2597 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2598 const char *control)
2599{
2600 bool dynamic_source = false;
2601 bool dynamic_sink = false;
2602
2603 if (!control)
2604 return 0;
2605
2606 switch (source->id) {
2607 case snd_soc_dapm_demux:
2608 dynamic_source = true;
2609 break;
2610 default:
2611 break;
2612 }
2613
2614 switch (sink->id) {
2615 case snd_soc_dapm_mux:
2616 case snd_soc_dapm_switch:
2617 case snd_soc_dapm_mixer:
2618 case snd_soc_dapm_mixer_named_ctl:
2619 dynamic_sink = true;
2620 break;
2621 default:
2622 break;
2623 }
2624
2625 if (dynamic_source && dynamic_sink) {
2626 dev_err(dapm->dev,
2627 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2628 source->name, control, sink->name);
2629 return -EINVAL;
2630 } else if (!dynamic_source && !dynamic_sink) {
2631 dev_err(dapm->dev,
2632 "Control not supported for path %s -> [%s] -> %s\n",
2633 source->name, control, sink->name);
2634 return -EINVAL;
2635 }
2636
2637 return 0;
2638}
2639
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002640static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2641 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2642 const char *control,
2643 int (*connected)(struct snd_soc_dapm_widget *source,
2644 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002645{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002646 struct snd_soc_dapm_widget *widgets[2];
2647 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002648 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002649 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002650
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002651 if (wsink->is_supply && !wsource->is_supply) {
2652 dev_err(dapm->dev,
2653 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2654 wsource->name, wsink->name);
2655 return -EINVAL;
2656 }
2657
2658 if (connected && !wsource->is_supply) {
2659 dev_err(dapm->dev,
2660 "connected() callback only supported for supply widgets (%s -> %s)\n",
2661 wsource->name, wsink->name);
2662 return -EINVAL;
2663 }
2664
2665 if (wsource->is_supply && control) {
2666 dev_err(dapm->dev,
2667 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2668 wsource->name, control, wsink->name);
2669 return -EINVAL;
2670 }
2671
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002672 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2673 if (ret)
2674 return ret;
2675
Richard Purdie2b97eab2006-10-06 18:32:18 +02002676 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2677 if (!path)
2678 return -ENOMEM;
2679
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002680 path->node[SND_SOC_DAPM_DIR_IN] = wsource;
2681 path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
2682 widgets[SND_SOC_DAPM_DIR_IN] = wsource;
2683 widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
2684
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002685 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002686 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002687 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002688
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002689 if (wsource->is_supply || wsink->is_supply)
2690 path->is_supply = 1;
2691
Richard Purdie2b97eab2006-10-06 18:32:18 +02002692 /* connect static paths */
2693 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002694 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002695 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002696 switch (wsource->id) {
2697 case snd_soc_dapm_demux:
2698 ret = dapm_connect_mux(dapm, path, control, wsource);
2699 if (ret)
2700 goto err;
2701 break;
2702 default:
2703 break;
2704 }
2705
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002706 switch (wsink->id) {
2707 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002708 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002709 if (ret != 0)
2710 goto err;
2711 break;
2712 case snd_soc_dapm_switch:
2713 case snd_soc_dapm_mixer:
2714 case snd_soc_dapm_mixer_named_ctl:
2715 ret = dapm_connect_mixer(dapm, path, control);
2716 if (ret != 0)
2717 goto err;
2718 break;
2719 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002720 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002721 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002722 }
2723
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002724 list_add(&path->list, &dapm->card->paths);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002725 snd_soc_dapm_for_each_direction(dir)
2726 list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002727
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002728 snd_soc_dapm_for_each_direction(dir) {
2729 dapm_update_widget_flags(widgets[dir]);
2730 dapm_mark_dirty(widgets[dir], "Route added");
2731 }
Mark Brownfabd0382012-07-05 17:20:06 +01002732
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002733 if (dapm->card->instantiated && path->connect)
2734 dapm_path_invalidate(path);
2735
Richard Purdie2b97eab2006-10-06 18:32:18 +02002736 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002737err:
2738 kfree(path);
2739 return ret;
2740}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002741
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002742static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002743 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002744{
2745 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2746 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2747 const char *sink;
2748 const char *source;
2749 char prefixed_sink[80];
2750 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002751 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002752 int ret;
2753
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002754 prefix = soc_dapm_prefix(dapm);
2755 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002756 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002757 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002758 sink = prefixed_sink;
2759 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002760 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002761 source = prefixed_source;
2762 } else {
2763 sink = route->sink;
2764 source = route->source;
2765 }
2766
Charles Keepax45a110a2015-05-11 13:50:30 +01002767 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2768 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2769
2770 if (wsink && wsource)
2771 goto skip_search;
2772
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002773 /*
2774 * find src and dest widgets over all widgets but favor a widget from
2775 * current DAPM context
2776 */
2777 list_for_each_entry(w, &dapm->card->widgets, list) {
2778 if (!wsink && !(strcmp(w->name, sink))) {
2779 wtsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002780 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002781 wsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002782 if (wsource)
2783 break;
2784 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002785 continue;
2786 }
2787 if (!wsource && !(strcmp(w->name, source))) {
2788 wtsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002789 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002790 wsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002791 if (wsink)
2792 break;
2793 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002794 }
2795 }
2796 /* use widget from another DAPM context if not found from this */
2797 if (!wsink)
2798 wsink = wtsink;
2799 if (!wsource)
2800 wsource = wtsource;
2801
2802 if (wsource == NULL) {
2803 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2804 route->source);
2805 return -ENODEV;
2806 }
2807 if (wsink == NULL) {
2808 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2809 route->sink);
2810 return -ENODEV;
2811 }
2812
Charles Keepax45a110a2015-05-11 13:50:30 +01002813skip_search:
2814 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2815 dapm_wcache_update(&dapm->path_source_cache, wsource);
2816
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002817 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2818 route->connected);
2819 if (ret)
2820 goto err;
2821
2822 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002823err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002824 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002825 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002826 return ret;
2827}
Mark Brown105f1c22008-05-13 14:52:19 +02002828
Mark Brownefcc3c62012-07-05 17:24:19 +01002829static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2830 const struct snd_soc_dapm_route *route)
2831{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002832 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002833 struct snd_soc_dapm_path *path, *p;
2834 const char *sink;
2835 const char *source;
2836 char prefixed_sink[80];
2837 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002838 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002839
2840 if (route->control) {
2841 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002842 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002843 return -EINVAL;
2844 }
2845
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002846 prefix = soc_dapm_prefix(dapm);
2847 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002848 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002849 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002850 sink = prefixed_sink;
2851 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002852 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002853 source = prefixed_source;
2854 } else {
2855 sink = route->sink;
2856 source = route->source;
2857 }
2858
2859 path = NULL;
2860 list_for_each_entry(p, &dapm->card->paths, list) {
2861 if (strcmp(p->source->name, source) != 0)
2862 continue;
2863 if (strcmp(p->sink->name, sink) != 0)
2864 continue;
2865 path = p;
2866 break;
2867 }
2868
2869 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002870 wsource = path->source;
2871 wsink = path->sink;
2872
2873 dapm_mark_dirty(wsource, "Route removed");
2874 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002875 if (path->connect)
2876 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002877
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002878 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002879
2880 /* Update any path related flags */
2881 dapm_update_widget_flags(wsource);
2882 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002883 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002884 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002885 source, sink);
2886 }
2887
2888 return 0;
2889}
2890
Mark Brown105f1c22008-05-13 14:52:19 +02002891/**
Mark Brown105f1c22008-05-13 14:52:19 +02002892 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002893 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002894 * @route: audio routes
2895 * @num: number of routes
2896 *
2897 * Connects 2 dapm widgets together via a named audio path. The sink is
2898 * the widget receiving the audio signal, whilst the source is the sender
2899 * of the audio signal.
2900 *
2901 * Returns 0 for success else error. On error all resources can be freed
2902 * with a call to snd_soc_card_free().
2903 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002904int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002905 const struct snd_soc_dapm_route *route, int num)
2906{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002907 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002908
Stuart Hendersonf19c1812017-09-21 11:02:12 +01002909 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown105f1c22008-05-13 14:52:19 +02002910 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002911 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002912 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002913 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2914 route->source,
2915 route->control ? route->control : "direct",
2916 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002917 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002918 }
2919 route++;
2920 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002921 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002922
Dan Carpenter60884c22012-04-13 22:25:43 +03002923 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002924}
2925EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2926
Mark Brownefcc3c62012-07-05 17:24:19 +01002927/**
2928 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2929 * @dapm: DAPM context
2930 * @route: audio routes
2931 * @num: number of routes
2932 *
2933 * Removes routes from the DAPM context.
2934 */
2935int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2936 const struct snd_soc_dapm_route *route, int num)
2937{
Rajan Vajae066ea22016-02-11 11:23:35 +05302938 int i;
Mark Brownefcc3c62012-07-05 17:24:19 +01002939
Stuart Hendersonf19c1812017-09-21 11:02:12 +01002940 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownefcc3c62012-07-05 17:24:19 +01002941 for (i = 0; i < num; i++) {
2942 snd_soc_dapm_del_route(dapm, route);
2943 route++;
2944 }
2945 mutex_unlock(&dapm->card->dapm_mutex);
2946
Rajan Vajae066ea22016-02-11 11:23:35 +05302947 return 0;
Mark Brownefcc3c62012-07-05 17:24:19 +01002948}
2949EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2950
Mark Brownbf3a9e12011-06-13 16:42:29 +01002951static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2952 const struct snd_soc_dapm_route *route)
2953{
2954 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2955 route->source,
2956 true);
2957 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2958 route->sink,
2959 true);
2960 struct snd_soc_dapm_path *path;
2961 int count = 0;
2962
2963 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002964 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002965 route->source);
2966 return -ENODEV;
2967 }
2968
2969 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002970 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002971 route->sink);
2972 return -ENODEV;
2973 }
2974
2975 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002976 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002977 route->source, route->sink);
2978
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002979 snd_soc_dapm_widget_for_each_sink_path(source, path) {
Mark Brownbf3a9e12011-06-13 16:42:29 +01002980 if (path->sink == sink) {
2981 path->weak = 1;
2982 count++;
2983 }
2984 }
2985
2986 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002987 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002988 route->source, route->sink);
2989 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002990 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002991 count, route->source, route->sink);
2992
2993 return 0;
2994}
2995
2996/**
2997 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2998 * @dapm: DAPM context
2999 * @route: audio routes
3000 * @num: number of routes
3001 *
3002 * Mark existing routes matching those specified in the passed array
3003 * as being weak, meaning that they are ignored for the purpose of
3004 * power decisions. The main intended use case is for sidetone paths
3005 * which couple audio between other independent paths if they are both
3006 * active in order to make the combination work better at the user
3007 * level but which aren't intended to be "used".
3008 *
3009 * Note that CODEC drivers should not use this as sidetone type paths
3010 * can frequently also be used as bypass paths.
3011 */
3012int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
3013 const struct snd_soc_dapm_route *route, int num)
3014{
3015 int i, err;
3016 int ret = 0;
3017
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003018 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01003019 for (i = 0; i < num; i++) {
3020 err = snd_soc_dapm_weak_route(dapm, route);
3021 if (err)
3022 ret = err;
3023 route++;
3024 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003025 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01003026
3027 return ret;
3028}
3029EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
3030
Mark Brown105f1c22008-05-13 14:52:19 +02003031/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02003032 * snd_soc_dapm_new_widgets - add new dapm widgets
Jonathan Corbet628536e2015-08-25 01:14:48 -06003033 * @card: card to be checked for new dapm widgets
Richard Purdie2b97eab2006-10-06 18:32:18 +02003034 *
3035 * Checks the codec for any new dapm widgets and creates them if found.
3036 *
3037 * Returns 0 for success.
3038 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02003039int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003040{
3041 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00003042 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003043
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003044 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003045
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003046 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003047 {
3048 if (w->new)
3049 continue;
3050
Stephen Warrenfad59882011-04-28 17:37:59 -06003051 if (w->num_kcontrols) {
Kees Cook6396bb22018-06-12 14:03:40 -07003052 w->kcontrols = kcalloc(w->num_kcontrols,
Stephen Warrenfad59882011-04-28 17:37:59 -06003053 sizeof(struct snd_kcontrol *),
3054 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003055 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003056 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06003057 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003058 }
Stephen Warrenfad59882011-04-28 17:37:59 -06003059 }
3060
Richard Purdie2b97eab2006-10-06 18:32:18 +02003061 switch(w->id) {
3062 case snd_soc_dapm_switch:
3063 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00003064 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003065 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003066 break;
3067 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003068 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003069 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003070 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003071 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06003072 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003073 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003074 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003075 case snd_soc_dapm_dai_link:
3076 dapm_new_dai_link(w);
3077 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01003078 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003079 break;
3080 }
Mark Brownb66a70d2011-02-09 18:04:11 +00003081
3082 /* Read the initial power state from the device */
3083 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003084 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08003085 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003086 val &= w->mask;
3087 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00003088 w->power = 1;
3089 }
3090
Richard Purdie2b97eab2006-10-06 18:32:18 +02003091 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003092
Mark Brown7508b122011-10-05 12:09:12 +01003093 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003094 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003095 }
3096
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003097 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
3098 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003099 return 0;
3100}
3101EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
3102
3103/**
3104 * snd_soc_dapm_get_volsw - dapm mixer get callback
3105 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003106 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003107 *
3108 * Callback to get the value of a dapm mixer control.
3109 *
3110 * Returns 0 for success.
3111 */
3112int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
3113 struct snd_ctl_elem_value *ucontrol)
3114{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003115 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3116 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003117 struct soc_mixer_control *mc =
3118 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003119 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003120 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003121 int max = mc->max;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003122 unsigned int width = fls(max);
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003123 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003124 unsigned int invert = mc->invert;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003125 unsigned int reg_val, val, rval = 0;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003126 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003127
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003128 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003129 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003130 ret = soc_dapm_read(dapm, reg, &reg_val);
3131 val = (reg_val >> shift) & mask;
3132
3133 if (ret == 0 && reg != mc->rreg)
3134 ret = soc_dapm_read(dapm, mc->rreg, &reg_val);
3135
3136 if (snd_soc_volsw_is_stereo(mc))
3137 rval = (reg_val >> mc->rshift) & mask;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003138 } else {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003139 reg_val = dapm_kcontrol_get_value(kcontrol);
3140 val = reg_val & mask;
3141
3142 if (snd_soc_volsw_is_stereo(mc))
3143 rval = (reg_val >> width) & mask;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003144 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003145 mutex_unlock(&card->dapm_mutex);
3146
Chen-Yu Tsai01ad5e72016-08-27 19:27:58 +08003147 if (ret)
3148 return ret;
3149
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003150 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003151 ucontrol->value.integer.value[0] = max - val;
3152 else
3153 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003154
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003155 if (snd_soc_volsw_is_stereo(mc)) {
3156 if (invert)
3157 ucontrol->value.integer.value[1] = max - rval;
3158 else
3159 ucontrol->value.integer.value[1] = rval;
3160 }
3161
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003162 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003163}
3164EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3165
3166/**
3167 * snd_soc_dapm_put_volsw - dapm mixer set callback
3168 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003169 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003170 *
3171 * Callback to set the value of a dapm mixer control.
3172 *
3173 * Returns 0 for success.
3174 */
3175int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3176 struct snd_ctl_elem_value *ucontrol)
3177{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003178 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3179 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003180 struct soc_mixer_control *mc =
3181 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003182 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003183 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003184 int max = mc->max;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003185 unsigned int width = fls(max);
3186 unsigned int mask = (1 << width) - 1;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003187 unsigned int invert = mc->invert;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003188 unsigned int val, rval = 0;
3189 int connect, rconnect = -1, change, reg_change = 0;
Fabio Estevam33d92452018-02-14 13:39:05 -02003190 struct snd_soc_dapm_update update = {};
Nenghua Cao52765972013-12-13 20:13:49 +08003191 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003192
3193 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003194 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003195
3196 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003197 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003198
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003199 if (snd_soc_volsw_is_stereo(mc)) {
3200 rval = (ucontrol->value.integer.value[1] & mask);
3201 rconnect = !!rval;
3202 if (invert)
3203 rval = max - rval;
3204 }
3205
Liam Girdwood3cd04342012-03-09 12:02:08 +00003206 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003207
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003208 /* This assumes field width < (bits in unsigned int / 2) */
3209 if (width > sizeof(unsigned int) * 8 / 2)
3210 dev_warn(dapm->dev,
3211 "ASoC: control %s field width limit exceeded\n",
3212 kcontrol->id.name);
3213 change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
Mark Brown283375c2009-12-07 18:09:03 +00003214
Jarkko Nikula18626c72014-06-09 14:20:29 +03003215 if (reg != SND_SOC_NOPM) {
Jarkko Nikula18626c72014-06-09 14:20:29 +03003216 val = val << shift;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003217 rval = rval << mc->rshift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003218
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003219 reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
3220
3221 if (snd_soc_volsw_is_stereo(mc))
3222 reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
3223 mask << mc->rshift,
3224 rval);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003225 }
3226
3227 if (change || reg_change) {
3228 if (reg_change) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003229 if (snd_soc_volsw_is_stereo(mc)) {
3230 update.has_second_set = true;
3231 update.reg2 = mc->rreg;
3232 update.mask2 = mask << mc->rshift;
3233 update.val2 = rval;
3234 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003235 update.kcontrol = kcontrol;
3236 update.reg = reg;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003237 update.mask = mask << shift;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003238 update.val = val;
3239 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003240 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003241 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003242
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003243 ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
3244 rconnect);
Mark Brown97404f22010-12-14 16:13:57 +00003245
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003246 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003247 }
3248
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003249 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003250
3251 if (ret > 0)
3252 soc_dpcm_runtime_update(card);
3253
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003254 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003255}
3256EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3257
3258/**
3259 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3260 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003261 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003262 *
3263 * Callback to get the value of a dapm enumerated double mixer control.
3264 *
3265 * Returns 0 for success.
3266 */
3267int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3268 struct snd_ctl_elem_value *ucontrol)
3269{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003270 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003271 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003272 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003273 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003274
Charles Keepax561ed682015-05-01 12:37:26 +01003275 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3276 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003277 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003278 if (ret) {
3279 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003280 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003281 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003282 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003283 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003284 }
Charles Keepax561ed682015-05-01 12:37:26 +01003285 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003286
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003287 val = (reg_val >> e->shift_l) & e->mask;
3288 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3289 if (e->shift_l != e->shift_r) {
3290 val = (reg_val >> e->shift_r) & e->mask;
3291 val = snd_soc_enum_val_to_item(e, val);
3292 ucontrol->value.enumerated.item[1] = val;
3293 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003294
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003295 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003296}
3297EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3298
3299/**
3300 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3301 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003302 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003303 *
3304 * Callback to set the value of a dapm enumerated double mixer control.
3305 *
3306 * Returns 0 for success.
3307 */
3308int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3309 struct snd_ctl_elem_value *ucontrol)
3310{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003311 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3312 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003313 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003314 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003315 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003316 unsigned int mask;
Fabio Estevam33d92452018-02-14 13:39:05 -02003317 struct snd_soc_dapm_update update = {};
Nenghua Cao52765972013-12-13 20:13:49 +08003318 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003319
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003320 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003321 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003322
3323 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003324 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003325 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003326 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003327 return -EINVAL;
Chen-Yu Tsai071133a2016-08-27 19:27:59 +08003328 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003329 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003330 }
3331
Liam Girdwood3cd04342012-03-09 12:02:08 +00003332 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003333
Charles Keepax561ed682015-05-01 12:37:26 +01003334 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003335
Charles Keepax561ed682015-05-01 12:37:26 +01003336 if (e->reg != SND_SOC_NOPM)
3337 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3338
3339 if (change || reg_change) {
3340 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003341 update.kcontrol = kcontrol;
3342 update.reg = e->reg;
3343 update.mask = mask;
3344 update.val = val;
3345 card->update = &update;
3346 }
Charles Keepax561ed682015-05-01 12:37:26 +01003347 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003348
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003349 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003350
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003351 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003352 }
3353
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003354 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003355
3356 if (ret > 0)
3357 soc_dpcm_runtime_update(card);
3358
Mark Brown97404f22010-12-14 16:13:57 +00003359 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003360}
3361EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3362
3363/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003364 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3365 *
3366 * @kcontrol: mixer control
3367 * @uinfo: control element information
3368 *
3369 * Callback to provide information about a pin switch control.
3370 */
3371int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3372 struct snd_ctl_elem_info *uinfo)
3373{
3374 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3375 uinfo->count = 1;
3376 uinfo->value.integer.min = 0;
3377 uinfo->value.integer.max = 1;
3378
3379 return 0;
3380}
3381EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3382
3383/**
3384 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3385 *
3386 * @kcontrol: mixer control
3387 * @ucontrol: Value
3388 */
3389int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3390 struct snd_ctl_elem_value *ucontrol)
3391{
Mark Brown48a8c392012-02-14 17:11:15 -08003392 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003393 const char *pin = (const char *)kcontrol->private_value;
3394
Liam Girdwood3cd04342012-03-09 12:02:08 +00003395 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003396
3397 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003398 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003399
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003400 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003401
3402 return 0;
3403}
3404EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3405
3406/**
3407 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3408 *
3409 * @kcontrol: mixer control
3410 * @ucontrol: Value
3411 */
3412int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3413 struct snd_ctl_elem_value *ucontrol)
3414{
Mark Brown48a8c392012-02-14 17:11:15 -08003415 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003416 const char *pin = (const char *)kcontrol->private_value;
3417
Mark Brown8b37dbd2009-02-28 21:14:20 +00003418 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003419 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003420 else
Mark Brown48a8c392012-02-14 17:11:15 -08003421 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003422
Mark Brown48a8c392012-02-14 17:11:15 -08003423 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003424 return 0;
3425}
3426EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3427
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +01003428struct snd_soc_dapm_widget *
Mark Brown5ba06fc2012-02-16 11:07:13 -08003429snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003430 const struct snd_soc_dapm_widget *widget)
3431{
3432 struct snd_soc_dapm_widget *w;
3433
3434 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3435 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Linus Walleij37e1df82017-01-13 10:23:52 +01003436 /* Do not nag about probe deferrals */
3437 if (IS_ERR(w)) {
3438 int ret = PTR_ERR(w);
3439
3440 if (ret != -EPROBE_DEFER)
3441 dev_err(dapm->dev,
3442 "ASoC: Failed to create DAPM control %s (%d)\n",
3443 widget->name, ret);
3444 goto out_unlock;
3445 }
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003446 if (!w)
3447 dev_err(dapm->dev,
3448 "ASoC: Failed to create DAPM control %s\n",
3449 widget->name);
3450
Linus Walleij37e1df82017-01-13 10:23:52 +01003451out_unlock:
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003452 mutex_unlock(&dapm->card->dapm_mutex);
3453 return w;
3454}
Subhransu S. Prustya5d56392016-06-27 09:18:03 +05303455EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003456
3457struct snd_soc_dapm_widget *
3458snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003459 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003460{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003461 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003462 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003463 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003464 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003465
3466 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003467 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003468
Mark Brown62ea8742012-01-21 21:14:48 +00003469 switch (w->id) {
3470 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003471 w->regulator = devm_regulator_get(dapm->dev, w->name);
3472 if (IS_ERR(w->regulator)) {
3473 ret = PTR_ERR(w->regulator);
Linus Walleij37e1df82017-01-13 10:23:52 +01003474 if (ret == -EPROBE_DEFER)
3475 return ERR_PTR(ret);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003476 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003477 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003478 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003479 }
Mark Brown8784c772013-01-10 19:33:47 +00003480
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003481 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003482 ret = regulator_allow_bypass(w->regulator, true);
3483 if (ret != 0)
3484 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003485 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003486 w->name, ret);
3487 }
Mark Brown62ea8742012-01-21 21:14:48 +00003488 break;
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00003489 case snd_soc_dapm_pinctrl:
3490 w->pinctrl = devm_pinctrl_get(dapm->dev);
3491 if (IS_ERR_OR_NULL(w->pinctrl)) {
3492 ret = PTR_ERR(w->pinctrl);
3493 if (ret == -EPROBE_DEFER)
3494 return ERR_PTR(ret);
3495 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
3496 w->name, ret);
3497 return NULL;
3498 }
3499 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003500 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003501#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003502 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003503 if (IS_ERR(w->clk)) {
3504 ret = PTR_ERR(w->clk);
Linus Walleij37e1df82017-01-13 10:23:52 +01003505 if (ret == -EPROBE_DEFER)
3506 return ERR_PTR(ret);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003507 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003508 w->name, ret);
3509 return NULL;
3510 }
Mark Brownec029952012-06-04 08:16:20 +01003511#else
3512 return NULL;
3513#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003514 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003515 default:
3516 break;
3517 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003518
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003519 prefix = soc_dapm_prefix(dapm);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003520 if (prefix)
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003521 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003522 else
Lars-Peter Clausen48068962015-07-21 18:11:08 +02003523 w->name = kstrdup_const(widget->name, GFP_KERNEL);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003524 if (w->name == NULL) {
3525 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003526 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003527 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003528
Mark Brown7ca3a182011-10-08 14:04:50 +01003529 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003530 case snd_soc_dapm_mic:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003531 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003532 w->power_check = dapm_generic_check_power;
3533 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003534 case snd_soc_dapm_input:
3535 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003536 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003537 w->power_check = dapm_generic_check_power;
3538 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003539 case snd_soc_dapm_spk:
3540 case snd_soc_dapm_hp:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003541 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003542 w->power_check = dapm_generic_check_power;
3543 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003544 case snd_soc_dapm_output:
3545 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003546 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003547 w->power_check = dapm_generic_check_power;
3548 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003549 case snd_soc_dapm_vmid:
3550 case snd_soc_dapm_siggen:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003551 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003552 w->power_check = dapm_always_on_check_power;
3553 break;
Vinod Koul56b44372015-11-23 21:22:30 +05303554 case snd_soc_dapm_sink:
3555 w->is_ep = SND_SOC_DAPM_EP_SINK;
3556 w->power_check = dapm_always_on_check_power;
3557 break;
3558
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003559 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003560 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003561 case snd_soc_dapm_switch:
3562 case snd_soc_dapm_mixer:
3563 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003564 case snd_soc_dapm_adc:
3565 case snd_soc_dapm_aif_out:
3566 case snd_soc_dapm_dac:
3567 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003568 case snd_soc_dapm_pga:
3569 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003570 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003571 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003572 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003573 case snd_soc_dapm_dai_out:
3574 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003575 w->power_check = dapm_generic_check_power;
3576 break;
3577 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003578 case snd_soc_dapm_regulator_supply:
Srinivas Kandagatla5b2d15b2018-03-10 02:37:27 +00003579 case snd_soc_dapm_pinctrl:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003580 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003581 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003582 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003583 w->power_check = dapm_supply_check_power;
3584 break;
3585 default:
3586 w->power_check = dapm_always_on_check_power;
3587 break;
3588 }
3589
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003590 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003591 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003592 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003593 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003594
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003595 snd_soc_dapm_for_each_direction(dir) {
3596 INIT_LIST_HEAD(&w->edges[dir]);
3597 w->endpoints[dir] = -1;
3598 }
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003599
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02003600 /* machine layer sets up unconnected pins and insertions */
Richard Purdie2b97eab2006-10-06 18:32:18 +02003601 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003602 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003603}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003604
3605/**
Mark Brown4ba13272008-05-13 14:51:19 +02003606 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003607 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003608 * @widget: widget array
3609 * @num: number of widgets
3610 *
3611 * Creates new DAPM controls based upon the templates.
3612 *
3613 * Returns 0 for success else error.
3614 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003615int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003616 const struct snd_soc_dapm_widget *widget,
3617 int num)
3618{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003619 struct snd_soc_dapm_widget *w;
3620 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003621 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003622
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003623 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003624 for (i = 0; i < num; i++) {
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003625 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Linus Walleij37e1df82017-01-13 10:23:52 +01003626 if (IS_ERR(w)) {
3627 ret = PTR_ERR(w);
3628 /* Do not nag about probe deferrals */
3629 if (ret == -EPROBE_DEFER)
3630 break;
3631 dev_err(dapm->dev,
3632 "ASoC: Failed to create DAPM control %s (%d)\n",
3633 widget->name, ret);
3634 break;
3635 }
Mark Brown5ba06fc2012-02-16 11:07:13 -08003636 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003637 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003638 "ASoC: Failed to create DAPM control %s\n",
3639 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003640 ret = -ENOMEM;
3641 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003642 }
Mark Brown4ba13272008-05-13 14:51:19 +02003643 widget++;
3644 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003645 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003646 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003647}
3648EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3649
Mark Brownc74184e2012-04-04 22:12:09 +01003650static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3651 struct snd_kcontrol *kcontrol, int event)
3652{
3653 struct snd_soc_dapm_path *source_p, *sink_p;
3654 struct snd_soc_dai *source, *sink;
Charles Keepax249dc492018-08-15 13:11:35 +01003655 struct snd_soc_pcm_runtime *rtd = w->priv;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003656 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003657 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003658 struct snd_pcm_hw_params *params = NULL;
Nicolin Chen8053f212016-07-26 14:55:51 -07003659 struct snd_pcm_runtime *runtime = NULL;
Takashi Iwai3ba66fe2018-07-25 22:43:26 +02003660 unsigned int fmt;
Mark Brownc74184e2012-04-04 22:12:09 +01003661 int ret;
3662
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003663 if (WARN_ON(!config) ||
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003664 WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3665 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003666 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003667
3668 /* We only support a single source and sink, pick the first */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003669 source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
3670 struct snd_soc_dapm_path,
3671 list_node[SND_SOC_DAPM_DIR_OUT]);
3672 sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
3673 struct snd_soc_dapm_path,
3674 list_node[SND_SOC_DAPM_DIR_IN]);
Mark Brownc74184e2012-04-04 22:12:09 +01003675
3676 source = source_p->source->priv;
3677 sink = sink_p->sink->priv;
3678
3679 /* Be a little careful as we don't want to overflow the mask array */
3680 if (config->formats) {
3681 fmt = ffs(config->formats) - 1;
3682 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003683 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003684 config->formats);
3685 fmt = 0;
3686 }
3687
3688 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003689 params = kzalloc(sizeof(*params), GFP_KERNEL);
3690 if (!params) {
3691 ret = -ENOMEM;
3692 goto out;
3693 }
3694 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003695
Mark Brown9747cec2012-04-26 19:12:21 +01003696 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003697 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003698 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003699 config->rate_max;
3700
Mark Brown9747cec2012-04-26 19:12:21 +01003701 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003702 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003703 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003704 = config->channels_max;
3705
3706 memset(&substream, 0, sizeof(substream));
3707
Nicolin Chen8053f212016-07-26 14:55:51 -07003708 /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */
3709 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
3710 if (!runtime) {
3711 ret = -ENOMEM;
3712 goto out;
3713 }
3714 substream.runtime = runtime;
Charles Keepax249dc492018-08-15 13:11:35 +01003715 substream.private_data = rtd;
Nicolin Chen8053f212016-07-26 14:55:51 -07003716
Mark Brownc74184e2012-04-04 22:12:09 +01003717 switch (event) {
3718 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003719 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
Kuninori Morimoto9900a422017-09-25 01:38:54 +00003720 if (source->driver->ops->startup) {
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303721 ret = source->driver->ops->startup(&substream, source);
3722 if (ret < 0) {
3723 dev_err(source->dev,
3724 "ASoC: startup() failed: %d\n", ret);
3725 goto out;
3726 }
3727 source->active++;
3728 }
Benoit Cousson93e69582014-07-08 23:19:38 +02003729 ret = soc_dai_hw_params(&substream, params, source);
3730 if (ret < 0)
3731 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003732
Benoit Cousson93e69582014-07-08 23:19:38 +02003733 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
Kuninori Morimoto9900a422017-09-25 01:38:54 +00003734 if (sink->driver->ops->startup) {
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303735 ret = sink->driver->ops->startup(&substream, sink);
3736 if (ret < 0) {
3737 dev_err(sink->dev,
3738 "ASoC: startup() failed: %d\n", ret);
3739 goto out;
3740 }
3741 sink->active++;
3742 }
Benoit Cousson93e69582014-07-08 23:19:38 +02003743 ret = soc_dai_hw_params(&substream, params, sink);
3744 if (ret < 0)
3745 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003746 break;
3747
3748 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003749 ret = snd_soc_dai_digital_mute(sink, 0,
3750 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003751 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003752 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003753 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003754 break;
3755
3756 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003757 ret = snd_soc_dai_digital_mute(sink, 1,
3758 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003759 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003760 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003761 ret = 0;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303762
3763 source->active--;
Kuninori Morimoto9900a422017-09-25 01:38:54 +00003764 if (source->driver->ops->shutdown) {
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303765 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3766 source->driver->ops->shutdown(&substream, source);
3767 }
3768
3769 sink->active--;
Kuninori Morimoto9900a422017-09-25 01:38:54 +00003770 if (sink->driver->ops->shutdown) {
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303771 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3772 sink->driver->ops->shutdown(&substream, sink);
3773 }
Mark Brownc74184e2012-04-04 22:12:09 +01003774 break;
3775
3776 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003777 WARN(1, "Unknown event %d\n", event);
Sudip Mukherjee75881df2015-09-10 18:01:44 +05303778 ret = -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003779 }
3780
Mark Brown9747cec2012-04-26 19:12:21 +01003781out:
Nicolin Chen8053f212016-07-26 14:55:51 -07003782 kfree(runtime);
Mark Brown9747cec2012-04-26 19:12:21 +01003783 kfree(params);
3784 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003785}
3786
Nikesh Oswalc6615082015-02-02 17:06:44 +00003787static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3788 struct snd_ctl_elem_value *ucontrol)
3789{
3790 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3791
Takashi Iwai741338f2016-02-29 17:20:48 +01003792 ucontrol->value.enumerated.item[0] = w->params_select;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003793
3794 return 0;
3795}
3796
3797static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3798 struct snd_ctl_elem_value *ucontrol)
3799{
3800 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3801
3802 /* Can't change the config when widget is already powered */
3803 if (w->power)
3804 return -EBUSY;
3805
Takashi Iwai741338f2016-02-29 17:20:48 +01003806 if (ucontrol->value.enumerated.item[0] == w->params_select)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003807 return 0;
3808
Takashi Iwai741338f2016-02-29 17:20:48 +01003809 if (ucontrol->value.enumerated.item[0] >= w->num_params)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003810 return -EINVAL;
3811
Takashi Iwai741338f2016-02-29 17:20:48 +01003812 w->params_select = ucontrol->value.enumerated.item[0];
Nikesh Oswalc6615082015-02-02 17:06:44 +00003813
3814 return 0;
3815}
3816
Arnd Bergmannc42c5ac2017-10-10 11:20:11 +02003817static void
anish kumar19ad6832017-09-28 21:52:39 -07003818snd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
3819 unsigned long *private_value,
3820 int num_params,
3821 const char **w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003822{
anish kumar19ad6832017-09-28 21:52:39 -07003823 int count;
3824
3825 devm_kfree(card->dev, (void *)*private_value);
3826 for (count = 0 ; count < num_params; count++)
3827 devm_kfree(card->dev, (void *)w_param_text[count]);
3828 devm_kfree(card->dev, w_param_text);
3829}
3830
3831static struct snd_kcontrol_new *
3832snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
3833 char *link_name,
3834 const struct snd_soc_pcm_stream *params,
3835 int num_params, const char **w_param_text,
3836 unsigned long *private_value)
3837{
Nikesh Oswalc6615082015-02-02 17:06:44 +00003838 struct soc_enum w_param_enum[] = {
3839 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3840 };
3841 struct snd_kcontrol_new kcontrol_dai_link[] = {
3842 SOC_ENUM_EXT(NULL, w_param_enum[0],
3843 snd_soc_dapm_dai_link_get,
3844 snd_soc_dapm_dai_link_put),
3845 };
anish kumar19ad6832017-09-28 21:52:39 -07003846 struct snd_kcontrol_new *kcontrol_news;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003847 const struct snd_soc_pcm_stream *config = params;
anish kumar19ad6832017-09-28 21:52:39 -07003848 int count;
Mark Brownc74184e2012-04-04 22:12:09 +01003849
Nikesh Oswalc6615082015-02-02 17:06:44 +00003850 for (count = 0 ; count < num_params; count++) {
3851 if (!config->stream_name) {
3852 dev_warn(card->dapm.dev,
3853 "ASoC: anonymous config %d for dai link %s\n",
3854 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003855 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003856 devm_kasprintf(card->dev, GFP_KERNEL,
3857 "Anonymous Configuration %d",
3858 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003859 } else {
3860 w_param_text[count] = devm_kmemdup(card->dev,
3861 config->stream_name,
3862 strlen(config->stream_name) + 1,
3863 GFP_KERNEL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003864 }
anish kumar19ad6832017-09-28 21:52:39 -07003865 if (!w_param_text[count])
3866 goto outfree_w_param;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003867 config++;
3868 }
anish kumar19ad6832017-09-28 21:52:39 -07003869
Nikesh Oswalc6615082015-02-02 17:06:44 +00003870 w_param_enum[0].items = num_params;
3871 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003872
anish kumar19ad6832017-09-28 21:52:39 -07003873 *private_value =
3874 (unsigned long) devm_kmemdup(card->dev,
3875 (void *)(kcontrol_dai_link[0].private_value),
3876 sizeof(struct soc_enum), GFP_KERNEL);
3877 if (!*private_value) {
3878 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3879 link_name);
3880 goto outfree_w_param;
3881 }
3882 kcontrol_dai_link[0].private_value = *private_value;
3883 /* duplicate kcontrol_dai_link on heap so that memory persists */
3884 kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3885 sizeof(struct snd_kcontrol_new),
3886 GFP_KERNEL);
3887 if (!kcontrol_news) {
3888 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3889 link_name);
3890 goto outfree_w_param;
3891 }
3892 return kcontrol_news;
3893
3894outfree_w_param:
3895 snd_soc_dapm_free_kcontrol(card, private_value, num_params, w_param_text);
3896 return NULL;
3897}
3898
3899int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
Charles Keepax249dc492018-08-15 13:11:35 +01003900 struct snd_soc_pcm_runtime *rtd,
anish kumar19ad6832017-09-28 21:52:39 -07003901 const struct snd_soc_pcm_stream *params,
3902 unsigned int num_params,
3903 struct snd_soc_dapm_widget *source,
3904 struct snd_soc_dapm_widget *sink)
3905{
3906 struct snd_soc_dapm_widget template;
3907 struct snd_soc_dapm_widget *w;
3908 const char **w_param_text;
3909 unsigned long private_value;
3910 char *link_name;
3911 int ret;
3912
3913 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3914 source->name, sink->name);
3915 if (!link_name)
3916 return -ENOMEM;
3917
Mark Brownc74184e2012-04-04 22:12:09 +01003918 memset(&template, 0, sizeof(template));
3919 template.reg = SND_SOC_NOPM;
3920 template.id = snd_soc_dapm_dai_link;
3921 template.name = link_name;
3922 template.event = snd_soc_dai_link_event;
3923 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3924 SND_SOC_DAPM_PRE_PMD;
anish kumar19ad6832017-09-28 21:52:39 -07003925 template.kcontrol_news = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003926
anish kumar19ad6832017-09-28 21:52:39 -07003927 /* allocate memory for control, only in case of multiple configs */
3928 if (num_params > 1) {
3929 w_param_text = devm_kcalloc(card->dev, num_params,
3930 sizeof(char *), GFP_KERNEL);
3931 if (!w_param_text) {
3932 ret = -ENOMEM;
3933 goto param_fail;
3934 }
3935
3936 template.num_kcontrols = 1;
3937 template.kcontrol_news =
3938 snd_soc_dapm_alloc_kcontrol(card,
3939 link_name, params, num_params,
3940 w_param_text, &private_value);
3941 if (!template.kcontrol_news) {
3942 ret = -ENOMEM;
3943 goto param_fail;
3944 }
Arnd Bergmann667ebc92017-10-10 11:20:10 +02003945 } else {
3946 w_param_text = NULL;
anish kumar19ad6832017-09-28 21:52:39 -07003947 }
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003948 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003949
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003950 w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
Linus Walleij37e1df82017-01-13 10:23:52 +01003951 if (IS_ERR(w)) {
3952 ret = PTR_ERR(w);
3953 /* Do not nag about probe deferrals */
3954 if (ret != -EPROBE_DEFER)
3955 dev_err(card->dev,
3956 "ASoC: Failed to create %s widget (%d)\n",
3957 link_name, ret);
3958 goto outfree_kcontrol_news;
3959 }
Mark Brownc74184e2012-04-04 22:12:09 +01003960 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003961 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003962 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003963 ret = -ENOMEM;
3964 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003965 }
3966
3967 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003968 w->num_params = num_params;
Charles Keepax249dc492018-08-15 13:11:35 +01003969 w->priv = rtd;
Mark Brownc74184e2012-04-04 22:12:09 +01003970
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003971 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3972 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003973 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003974 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003975
3976outfree_w:
3977 devm_kfree(card->dev, w);
3978outfree_kcontrol_news:
3979 devm_kfree(card->dev, (void *)template.kcontrol_news);
anish kumar19ad6832017-09-28 21:52:39 -07003980 snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text);
3981param_fail:
Nikesh Oswalc6615082015-02-02 17:06:44 +00003982 devm_kfree(card->dev, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003983 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003984}
3985
Mark Brown888df392012-02-16 19:37:51 -08003986int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3987 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003988{
Mark Brown888df392012-02-16 19:37:51 -08003989 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003990 struct snd_soc_dapm_widget *w;
3991
Mark Brown888df392012-02-16 19:37:51 -08003992 WARN_ON(dapm->dev != dai->dev);
3993
3994 memset(&template, 0, sizeof(template));
3995 template.reg = SND_SOC_NOPM;
3996
3997 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003998 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003999 template.name = dai->driver->playback.stream_name;
4000 template.sname = dai->driver->playback.stream_name;
4001
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004002 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08004003 template.name);
4004
Liam Girdwood02aa78a2015-05-25 18:21:17 +01004005 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Linus Walleij639467c2017-01-20 14:07:52 +01004006 if (IS_ERR(w)) {
4007 int ret = PTR_ERR(w);
4008
4009 /* Do not nag about probe deferrals */
4010 if (ret != -EPROBE_DEFER)
4011 dev_err(dapm->dev,
4012 "ASoC: Failed to create %s widget (%d)\n",
4013 dai->driver->playback.stream_name, ret);
4014 return ret;
4015 }
Mark Brown888df392012-02-16 19:37:51 -08004016 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004017 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08004018 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01004019 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08004020 }
4021
4022 w->priv = dai;
4023 dai->playback_widget = w;
4024 }
4025
4026 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01004027 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08004028 template.name = dai->driver->capture.stream_name;
4029 template.sname = dai->driver->capture.stream_name;
4030
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004031 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08004032 template.name);
4033
Liam Girdwood02aa78a2015-05-25 18:21:17 +01004034 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Linus Walleij639467c2017-01-20 14:07:52 +01004035 if (IS_ERR(w)) {
4036 int ret = PTR_ERR(w);
4037
4038 /* Do not nag about probe deferrals */
4039 if (ret != -EPROBE_DEFER)
4040 dev_err(dapm->dev,
4041 "ASoC: Failed to create %s widget (%d)\n",
4042 dai->driver->playback.stream_name, ret);
4043 return ret;
4044 }
Mark Brown888df392012-02-16 19:37:51 -08004045 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004046 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08004047 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01004048 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08004049 }
4050
4051 w->priv = dai;
4052 dai->capture_widget = w;
4053 }
4054
4055 return 0;
4056}
4057
4058int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
4059{
4060 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004061 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08004062 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08004063
4064 /* For each DAI widget... */
4065 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01004066 switch (dai_w->id) {
4067 case snd_soc_dapm_dai_in:
4068 case snd_soc_dapm_dai_out:
4069 break;
4070 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02004071 continue;
Mark Brown46162742013-06-05 19:36:11 +01004072 }
Mark Brown888df392012-02-16 19:37:51 -08004073
Liam Girdwoode01b4f62018-06-14 20:26:42 +01004074 /* let users know there is no DAI to link */
4075 if (!dai_w->priv) {
4076 dev_dbg(card->dev, "dai widget %s has no DAI\n",
4077 dai_w->name);
4078 continue;
4079 }
4080
Mark Brown888df392012-02-16 19:37:51 -08004081 dai = dai_w->priv;
4082
4083 /* ...find all widgets with the same stream and link them */
4084 list_for_each_entry(w, &card->widgets, list) {
4085 if (w->dapm != dai_w->dapm)
4086 continue;
4087
Mark Brown46162742013-06-05 19:36:11 +01004088 switch (w->id) {
4089 case snd_soc_dapm_dai_in:
4090 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08004091 continue;
Mark Brown46162742013-06-05 19:36:11 +01004092 default:
4093 break;
4094 }
Mark Brown888df392012-02-16 19:37:51 -08004095
Lars-Peter Clausena798c242015-07-21 11:51:35 +02004096 if (!w->sname || !strstr(w->sname, dai_w->sname))
Mark Brown888df392012-02-16 19:37:51 -08004097 continue;
4098
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004099 if (dai_w->id == snd_soc_dapm_dai_in) {
4100 src = dai_w;
4101 sink = w;
4102 } else {
4103 src = w;
4104 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08004105 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004106 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
4107 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004108 }
4109 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02004110
Mark Brown888df392012-02-16 19:37:51 -08004111 return 0;
4112}
Liam Girdwood64a648c2011-07-25 11:15:15 +01004113
Benoit Cousson44ba2642014-07-08 23:19:36 +02004114static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
4115 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004116{
Benoit Cousson44ba2642014-07-08 23:19:36 +02004117 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004118 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004119 int i;
4120
Benoit Cousson44ba2642014-07-08 23:19:36 +02004121 for (i = 0; i < rtd->num_codecs; i++) {
4122 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004123
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004124 /* connect BE DAI playback if widgets are valid */
4125 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004126 source = cpu_dai->playback_widget;
4127 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004128 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02004129 cpu_dai->component->name, source->name,
4130 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004131
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004132 snd_soc_dapm_add_path(&card->dapm, source, sink,
4133 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004134 }
4135
4136 /* connect BE DAI capture if widgets are valid */
4137 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004138 source = codec_dai->capture_widget;
4139 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004140 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02004141 codec_dai->component->name, source->name,
4142 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004143
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004144 snd_soc_dapm_add_path(&card->dapm, source, sink,
4145 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004146 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004147 }
4148}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004149
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004150static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
4151 int event)
4152{
4153 struct snd_soc_dapm_widget *w;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004154 unsigned int ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004155
4156 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
4157 w = dai->playback_widget;
4158 else
4159 w = dai->capture_widget;
4160
4161 if (w) {
4162 dapm_mark_dirty(w, "stream event");
4163
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004164 if (w->id == snd_soc_dapm_dai_in) {
4165 ep = SND_SOC_DAPM_EP_SOURCE;
4166 dapm_widget_invalidate_input_paths(w);
4167 } else {
4168 ep = SND_SOC_DAPM_EP_SINK;
4169 dapm_widget_invalidate_output_paths(w);
4170 }
4171
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004172 switch (event) {
4173 case SND_SOC_DAPM_STREAM_START:
4174 w->active = 1;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004175 w->is_ep = ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004176 break;
4177 case SND_SOC_DAPM_STREAM_STOP:
4178 w->active = 0;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004179 w->is_ep = 0;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004180 break;
4181 case SND_SOC_DAPM_STREAM_SUSPEND:
4182 case SND_SOC_DAPM_STREAM_RESUME:
4183 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
4184 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
4185 break;
4186 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004187 }
4188}
4189
Benoit Cousson44ba2642014-07-08 23:19:36 +02004190void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
4191{
Mengdong Lin1a497982015-11-18 02:34:11 -05004192 struct snd_soc_pcm_runtime *rtd;
Benoit Cousson44ba2642014-07-08 23:19:36 +02004193
4194 /* for each BE DAI link... */
Mengdong Lin1a497982015-11-18 02:34:11 -05004195 list_for_each_entry(rtd, &card->rtd_list, list) {
Benoit Cousson44ba2642014-07-08 23:19:36 +02004196 /*
4197 * dynamic FE links have no fixed DAI mapping.
4198 * CODEC<->CODEC links have no direct connection.
4199 */
4200 if (rtd->dai_link->dynamic || rtd->dai_link->params)
4201 continue;
4202
4203 dapm_connect_dai_link_widgets(card, rtd);
4204 }
4205}
4206
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004207static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4208 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004209{
Benoit Cousson44ba2642014-07-08 23:19:36 +02004210 int i;
4211
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004212 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02004213 for (i = 0; i < rtd->num_codecs; i++)
4214 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004215
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004216 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004217}
4218
4219/**
4220 * snd_soc_dapm_stream_event - send a stream event to the dapm core
4221 * @rtd: PCM runtime data
4222 * @stream: stream name
4223 * @event: stream event
4224 *
4225 * Sends a stream event to the dapm core. The core then makes any
4226 * necessary widget power changes.
4227 *
4228 * Returns 0 for success else error.
4229 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004230void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4231 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004232{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00004233 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004234
Liam Girdwood3cd04342012-03-09 12:02:08 +00004235 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004236 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00004237 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004238}
Richard Purdie2b97eab2006-10-06 18:32:18 +02004239
4240/**
Charles Keepax11391102014-02-18 15:22:14 +00004241 * snd_soc_dapm_enable_pin_unlocked - enable pin.
4242 * @dapm: DAPM context
4243 * @pin: pin name
4244 *
4245 * Enables input/output pin and its parents or children widgets iff there is
4246 * a valid audio route and active audio stream.
4247 *
4248 * Requires external locking.
4249 *
4250 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4251 * do any widget power switching.
4252 */
4253int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4254 const char *pin)
4255{
4256 return snd_soc_dapm_set_pin(dapm, pin, 1);
4257}
4258EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
4259
4260/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004261 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004262 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004263 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02004264 *
Mark Brown74b8f952009-06-06 11:26:15 +01004265 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01004266 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00004267 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004268 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4269 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02004270 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004271int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004272{
Charles Keepax11391102014-02-18 15:22:14 +00004273 int ret;
4274
4275 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4276
4277 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
4278
4279 mutex_unlock(&dapm->card->dapm_mutex);
4280
4281 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02004282}
Liam Girdwooda5302182008-07-07 13:35:17 +01004283EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004284
4285/**
Charles Keepax11391102014-02-18 15:22:14 +00004286 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
4287 * @dapm: DAPM context
4288 * @pin: pin name
4289 *
4290 * Enables input/output pin regardless of any other state. This is
4291 * intended for use with microphone bias supplies used in microphone
4292 * jack detection.
4293 *
4294 * Requires external locking.
4295 *
4296 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4297 * do any widget power switching.
4298 */
4299int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4300 const char *pin)
4301{
4302 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4303
4304 if (!w) {
4305 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4306 return -EINVAL;
4307 }
4308
4309 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02004310 if (!w->connected) {
4311 /*
4312 * w->force does not affect the number of input or output paths,
4313 * so we only have to recheck if w->connected is changed
4314 */
4315 dapm_widget_invalidate_input_paths(w);
4316 dapm_widget_invalidate_output_paths(w);
4317 w->connected = 1;
4318 }
Charles Keepax11391102014-02-18 15:22:14 +00004319 w->force = 1;
4320 dapm_mark_dirty(w, "force enable");
4321
4322 return 0;
4323}
4324EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4325
4326/**
Mark Brownda341832010-03-15 19:23:37 +00004327 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004328 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00004329 * @pin: pin name
4330 *
4331 * Enables input/output pin regardless of any other state. This is
4332 * intended for use with microphone bias supplies used in microphone
4333 * jack detection.
4334 *
4335 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4336 * do any widget power switching.
4337 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004338int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4339 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00004340{
Charles Keepax11391102014-02-18 15:22:14 +00004341 int ret;
Mark Brownda341832010-03-15 19:23:37 +00004342
Charles Keepax11391102014-02-18 15:22:14 +00004343 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00004344
Charles Keepax11391102014-02-18 15:22:14 +00004345 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09004346
Charles Keepax11391102014-02-18 15:22:14 +00004347 mutex_unlock(&dapm->card->dapm_mutex);
4348
4349 return ret;
Mark Brownda341832010-03-15 19:23:37 +00004350}
4351EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4352
4353/**
Charles Keepax11391102014-02-18 15:22:14 +00004354 * snd_soc_dapm_disable_pin_unlocked - disable pin.
4355 * @dapm: DAPM context
4356 * @pin: pin name
4357 *
4358 * Disables input/output pin and its parents or children widgets.
4359 *
4360 * Requires external locking.
4361 *
4362 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4363 * do any widget power switching.
4364 */
4365int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4366 const char *pin)
4367{
4368 return snd_soc_dapm_set_pin(dapm, pin, 0);
4369}
4370EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4371
4372/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004373 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004374 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004375 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004376 *
Mark Brown74b8f952009-06-06 11:26:15 +01004377 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004378 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004379 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4380 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004381 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004382int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4383 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004384{
Charles Keepax11391102014-02-18 15:22:14 +00004385 int ret;
4386
4387 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4388
4389 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4390
4391 mutex_unlock(&dapm->card->dapm_mutex);
4392
4393 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004394}
4395EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4396
4397/**
Charles Keepax11391102014-02-18 15:22:14 +00004398 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4399 * @dapm: DAPM context
4400 * @pin: pin name
4401 *
4402 * Marks the specified pin as being not connected, disabling it along
4403 * any parent or child widgets. At present this is identical to
4404 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4405 * additional things such as disabling controls which only affect
4406 * paths through the pin.
4407 *
4408 * Requires external locking.
4409 *
4410 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4411 * do any widget power switching.
4412 */
4413int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4414 const char *pin)
4415{
4416 return snd_soc_dapm_set_pin(dapm, pin, 0);
4417}
4418EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4419
4420/**
Mark Brown5817b522008-09-24 11:23:11 +01004421 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004422 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004423 * @pin: pin name
4424 *
4425 * Marks the specified pin as being not connected, disabling it along
4426 * any parent or child widgets. At present this is identical to
4427 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4428 * additional things such as disabling controls which only affect
4429 * paths through the pin.
4430 *
4431 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4432 * do any widget power switching.
4433 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004434int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004435{
Charles Keepax11391102014-02-18 15:22:14 +00004436 int ret;
4437
4438 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4439
4440 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4441
4442 mutex_unlock(&dapm->card->dapm_mutex);
4443
4444 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004445}
4446EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4447
4448/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004449 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004450 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004451 * @pin: audio signal pin endpoint (or start point)
4452 *
4453 * Get audio pin status - connected or disconnected.
4454 *
4455 * Returns 1 for connected otherwise 0.
4456 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004457int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4458 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004459{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004460 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004461
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004462 if (w)
4463 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004464
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004465 return 0;
4466}
Liam Girdwooda5302182008-07-07 13:35:17 +01004467EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004468
4469/**
Mark Brown1547aba2010-05-07 21:11:40 +01004470 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004471 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004472 * @pin: audio signal pin endpoint (or start point)
4473 *
4474 * Mark the given endpoint or pin as ignoring suspend. When the
4475 * system is disabled a path between two endpoints flagged as ignoring
4476 * suspend will not be disabled. The path must already be enabled via
4477 * normal means at suspend time, it will not be turned on if it was not
4478 * already enabled.
4479 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004480int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4481 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004482{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004483 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004484
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004485 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004486 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004487 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004488 }
4489
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004490 w->ignore_suspend = 1;
4491
4492 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004493}
4494EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4495
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004496/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004497 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004498 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004499 *
4500 * Free all dapm widgets and resources.
4501 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004502void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004503{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004504 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004505 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004506 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004507}
4508EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4509
Xiang Xiao57996352014-03-02 00:04:02 +08004510static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004511{
Liam Girdwood01005a72012-07-06 16:57:05 +01004512 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004513 struct snd_soc_dapm_widget *w;
4514 LIST_HEAD(down_list);
4515 int powerdown = 0;
4516
Liam Girdwood01005a72012-07-06 16:57:05 +01004517 mutex_lock(&card->dapm_mutex);
4518
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004519 list_for_each_entry(w, &dapm->card->widgets, list) {
4520 if (w->dapm != dapm)
4521 continue;
Mark Brown51737472009-06-22 13:16:51 +01004522 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004523 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004524 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004525 powerdown = 1;
4526 }
4527 }
4528
4529 /* If there were no widgets to power down we're already in
4530 * standby.
4531 */
4532 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004533 if (dapm->bias_level == SND_SOC_BIAS_ON)
4534 snd_soc_dapm_set_bias_level(dapm,
4535 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004536 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004537 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4538 snd_soc_dapm_set_bias_level(dapm,
4539 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004540 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004541
4542 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004543}
Mark Brown51737472009-06-22 13:16:51 +01004544
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004545/*
4546 * snd_soc_dapm_shutdown - callback for system shutdown
4547 */
4548void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4549{
Xiang Xiao57996352014-03-02 00:04:02 +08004550 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004551
Xiang Xiao57996352014-03-02 00:04:02 +08004552 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004553 if (dapm != &card->dapm) {
4554 soc_dapm_shutdown_dapm(dapm);
4555 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4556 snd_soc_dapm_set_bias_level(dapm,
4557 SND_SOC_BIAS_OFF);
4558 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004559 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004560
4561 soc_dapm_shutdown_dapm(&card->dapm);
4562 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4563 snd_soc_dapm_set_bias_level(&card->dapm,
4564 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004565}
4566
Richard Purdie2b97eab2006-10-06 18:32:18 +02004567/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004568MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004569MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4570MODULE_LICENSE("GPL");