xref: /OK3568_Linux_fs/kernel/sound/soc/soc-dapm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright 2005 Wolfson Microelectronics PLC.
6*4882a593Smuzhiyun // Author: Liam Girdwood <lrg@slimlogic.co.uk>
7*4882a593Smuzhiyun //
8*4882a593Smuzhiyun //  Features:
9*4882a593Smuzhiyun //    o Changes power status of internal codec blocks depending on the
10*4882a593Smuzhiyun //      dynamic configuration of codec internal audio paths and active
11*4882a593Smuzhiyun //      DACs/ADCs.
12*4882a593Smuzhiyun //    o Platform power domain - can support external components i.e. amps and
13*4882a593Smuzhiyun //      mic/headphone insertion events.
14*4882a593Smuzhiyun //    o Automatic Mic Bias support
15*4882a593Smuzhiyun //    o Jack insertion power event initiation - e.g. hp insertion will enable
16*4882a593Smuzhiyun //      sinks, dacs, etc
17*4882a593Smuzhiyun //    o Delayed power down of audio subsystem to reduce pops between a quick
18*4882a593Smuzhiyun //      device reopen.
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun #include <linux/init.h>
22*4882a593Smuzhiyun #include <linux/async.h>
23*4882a593Smuzhiyun #include <linux/delay.h>
24*4882a593Smuzhiyun #include <linux/pm.h>
25*4882a593Smuzhiyun #include <linux/bitops.h>
26*4882a593Smuzhiyun #include <linux/platform_device.h>
27*4882a593Smuzhiyun #include <linux/jiffies.h>
28*4882a593Smuzhiyun #include <linux/debugfs.h>
29*4882a593Smuzhiyun #include <linux/pm_runtime.h>
30*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
31*4882a593Smuzhiyun #include <linux/pinctrl/consumer.h>
32*4882a593Smuzhiyun #include <linux/clk.h>
33*4882a593Smuzhiyun #include <linux/slab.h>
34*4882a593Smuzhiyun #include <sound/core.h>
35*4882a593Smuzhiyun #include <sound/pcm.h>
36*4882a593Smuzhiyun #include <sound/pcm_params.h>
37*4882a593Smuzhiyun #include <sound/soc.h>
38*4882a593Smuzhiyun #include <sound/initval.h>
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #include <trace/events/asoc.h>
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
45*4882a593Smuzhiyun 	SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define snd_soc_dapm_for_each_direction(dir) \
48*4882a593Smuzhiyun 	for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
49*4882a593Smuzhiyun 		(dir)++)
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
52*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
53*4882a593Smuzhiyun 	const char *control,
54*4882a593Smuzhiyun 	int (*connected)(struct snd_soc_dapm_widget *source,
55*4882a593Smuzhiyun 			 struct snd_soc_dapm_widget *sink));
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun struct snd_soc_dapm_widget *
58*4882a593Smuzhiyun snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
59*4882a593Smuzhiyun 			 const struct snd_soc_dapm_widget *widget);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun struct snd_soc_dapm_widget *
62*4882a593Smuzhiyun snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
63*4882a593Smuzhiyun 			 const struct snd_soc_dapm_widget *widget);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg);
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun /* dapm power sequences - make this per codec in the future */
68*4882a593Smuzhiyun static int dapm_up_seq[] = {
69*4882a593Smuzhiyun 	[snd_soc_dapm_pre] = 1,
70*4882a593Smuzhiyun 	[snd_soc_dapm_regulator_supply] = 2,
71*4882a593Smuzhiyun 	[snd_soc_dapm_pinctrl] = 2,
72*4882a593Smuzhiyun 	[snd_soc_dapm_clock_supply] = 2,
73*4882a593Smuzhiyun 	[snd_soc_dapm_supply] = 3,
74*4882a593Smuzhiyun 	[snd_soc_dapm_micbias] = 4,
75*4882a593Smuzhiyun 	[snd_soc_dapm_vmid] = 4,
76*4882a593Smuzhiyun 	[snd_soc_dapm_dai_link] = 3,
77*4882a593Smuzhiyun 	[snd_soc_dapm_dai_in] = 5,
78*4882a593Smuzhiyun 	[snd_soc_dapm_dai_out] = 5,
79*4882a593Smuzhiyun 	[snd_soc_dapm_aif_in] = 5,
80*4882a593Smuzhiyun 	[snd_soc_dapm_aif_out] = 5,
81*4882a593Smuzhiyun 	[snd_soc_dapm_mic] = 6,
82*4882a593Smuzhiyun 	[snd_soc_dapm_siggen] = 6,
83*4882a593Smuzhiyun 	[snd_soc_dapm_input] = 6,
84*4882a593Smuzhiyun 	[snd_soc_dapm_output] = 6,
85*4882a593Smuzhiyun 	[snd_soc_dapm_mux] = 7,
86*4882a593Smuzhiyun 	[snd_soc_dapm_demux] = 7,
87*4882a593Smuzhiyun 	[snd_soc_dapm_dac] = 8,
88*4882a593Smuzhiyun 	[snd_soc_dapm_switch] = 9,
89*4882a593Smuzhiyun 	[snd_soc_dapm_mixer] = 9,
90*4882a593Smuzhiyun 	[snd_soc_dapm_mixer_named_ctl] = 9,
91*4882a593Smuzhiyun 	[snd_soc_dapm_pga] = 10,
92*4882a593Smuzhiyun 	[snd_soc_dapm_buffer] = 10,
93*4882a593Smuzhiyun 	[snd_soc_dapm_scheduler] = 10,
94*4882a593Smuzhiyun 	[snd_soc_dapm_effect] = 10,
95*4882a593Smuzhiyun 	[snd_soc_dapm_src] = 10,
96*4882a593Smuzhiyun 	[snd_soc_dapm_asrc] = 10,
97*4882a593Smuzhiyun 	[snd_soc_dapm_encoder] = 10,
98*4882a593Smuzhiyun 	[snd_soc_dapm_decoder] = 10,
99*4882a593Smuzhiyun 	[snd_soc_dapm_adc] = 11,
100*4882a593Smuzhiyun 	[snd_soc_dapm_out_drv] = 12,
101*4882a593Smuzhiyun 	[snd_soc_dapm_hp] = 12,
102*4882a593Smuzhiyun 	[snd_soc_dapm_spk] = 12,
103*4882a593Smuzhiyun 	[snd_soc_dapm_line] = 12,
104*4882a593Smuzhiyun 	[snd_soc_dapm_sink] = 12,
105*4882a593Smuzhiyun 	[snd_soc_dapm_kcontrol] = 13,
106*4882a593Smuzhiyun 	[snd_soc_dapm_post] = 14,
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun static int dapm_down_seq[] = {
110*4882a593Smuzhiyun 	[snd_soc_dapm_pre] = 1,
111*4882a593Smuzhiyun 	[snd_soc_dapm_kcontrol] = 2,
112*4882a593Smuzhiyun 	[snd_soc_dapm_adc] = 3,
113*4882a593Smuzhiyun 	[snd_soc_dapm_hp] = 4,
114*4882a593Smuzhiyun 	[snd_soc_dapm_spk] = 4,
115*4882a593Smuzhiyun 	[snd_soc_dapm_line] = 4,
116*4882a593Smuzhiyun 	[snd_soc_dapm_out_drv] = 4,
117*4882a593Smuzhiyun 	[snd_soc_dapm_sink] = 4,
118*4882a593Smuzhiyun 	[snd_soc_dapm_pga] = 5,
119*4882a593Smuzhiyun 	[snd_soc_dapm_buffer] = 5,
120*4882a593Smuzhiyun 	[snd_soc_dapm_scheduler] = 5,
121*4882a593Smuzhiyun 	[snd_soc_dapm_effect] = 5,
122*4882a593Smuzhiyun 	[snd_soc_dapm_src] = 5,
123*4882a593Smuzhiyun 	[snd_soc_dapm_asrc] = 5,
124*4882a593Smuzhiyun 	[snd_soc_dapm_encoder] = 5,
125*4882a593Smuzhiyun 	[snd_soc_dapm_decoder] = 5,
126*4882a593Smuzhiyun 	[snd_soc_dapm_switch] = 6,
127*4882a593Smuzhiyun 	[snd_soc_dapm_mixer_named_ctl] = 6,
128*4882a593Smuzhiyun 	[snd_soc_dapm_mixer] = 6,
129*4882a593Smuzhiyun 	[snd_soc_dapm_dac] = 7,
130*4882a593Smuzhiyun 	[snd_soc_dapm_mic] = 8,
131*4882a593Smuzhiyun 	[snd_soc_dapm_siggen] = 8,
132*4882a593Smuzhiyun 	[snd_soc_dapm_input] = 8,
133*4882a593Smuzhiyun 	[snd_soc_dapm_output] = 8,
134*4882a593Smuzhiyun 	[snd_soc_dapm_micbias] = 9,
135*4882a593Smuzhiyun 	[snd_soc_dapm_vmid] = 9,
136*4882a593Smuzhiyun 	[snd_soc_dapm_mux] = 10,
137*4882a593Smuzhiyun 	[snd_soc_dapm_demux] = 10,
138*4882a593Smuzhiyun 	[snd_soc_dapm_aif_in] = 11,
139*4882a593Smuzhiyun 	[snd_soc_dapm_aif_out] = 11,
140*4882a593Smuzhiyun 	[snd_soc_dapm_dai_in] = 11,
141*4882a593Smuzhiyun 	[snd_soc_dapm_dai_out] = 11,
142*4882a593Smuzhiyun 	[snd_soc_dapm_dai_link] = 12,
143*4882a593Smuzhiyun 	[snd_soc_dapm_supply] = 13,
144*4882a593Smuzhiyun 	[snd_soc_dapm_clock_supply] = 14,
145*4882a593Smuzhiyun 	[snd_soc_dapm_pinctrl] = 14,
146*4882a593Smuzhiyun 	[snd_soc_dapm_regulator_supply] = 14,
147*4882a593Smuzhiyun 	[snd_soc_dapm_post] = 15,
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun 
dapm_assert_locked(struct snd_soc_dapm_context * dapm)150*4882a593Smuzhiyun static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	if (dapm->card && dapm->card->instantiated)
153*4882a593Smuzhiyun 		lockdep_assert_held(&dapm->card->dapm_mutex);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
pop_wait(u32 pop_time)156*4882a593Smuzhiyun static void pop_wait(u32 pop_time)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	if (pop_time)
159*4882a593Smuzhiyun 		schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun __printf(3, 4)
pop_dbg(struct device * dev,u32 pop_time,const char * fmt,...)163*4882a593Smuzhiyun static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	va_list args;
166*4882a593Smuzhiyun 	char *buf;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	if (!pop_time)
169*4882a593Smuzhiyun 		return;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
172*4882a593Smuzhiyun 	if (buf == NULL)
173*4882a593Smuzhiyun 		return;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	va_start(args, fmt);
176*4882a593Smuzhiyun 	vsnprintf(buf, PAGE_SIZE, fmt, args);
177*4882a593Smuzhiyun 	dev_info(dev, "%s", buf);
178*4882a593Smuzhiyun 	va_end(args);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	kfree(buf);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
dapm_dirty_widget(struct snd_soc_dapm_widget * w)183*4882a593Smuzhiyun static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	return !list_empty(&w->dirty);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
dapm_mark_dirty(struct snd_soc_dapm_widget * w,const char * reason)188*4882a593Smuzhiyun static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	dapm_assert_locked(w->dapm);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	if (!dapm_dirty_widget(w)) {
193*4882a593Smuzhiyun 		dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
194*4882a593Smuzhiyun 			 w->name, reason);
195*4882a593Smuzhiyun 		list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun /*
200*4882a593Smuzhiyun  * Common implementation for dapm_widget_invalidate_input_paths() and
201*4882a593Smuzhiyun  * dapm_widget_invalidate_output_paths(). The function is inlined since the
202*4882a593Smuzhiyun  * combined size of the two specialized functions is only marginally larger then
203*4882a593Smuzhiyun  * the size of the generic function and at the same time the fast path of the
204*4882a593Smuzhiyun  * specialized functions is significantly smaller than the generic function.
205*4882a593Smuzhiyun  */
dapm_widget_invalidate_paths(struct snd_soc_dapm_widget * w,enum snd_soc_dapm_direction dir)206*4882a593Smuzhiyun static __always_inline void dapm_widget_invalidate_paths(
207*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
210*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *node;
211*4882a593Smuzhiyun 	struct snd_soc_dapm_path *p;
212*4882a593Smuzhiyun 	LIST_HEAD(list);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	dapm_assert_locked(w->dapm);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	if (w->endpoints[dir] == -1)
217*4882a593Smuzhiyun 		return;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	list_add_tail(&w->work_list, &list);
220*4882a593Smuzhiyun 	w->endpoints[dir] = -1;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	list_for_each_entry(w, &list, work_list) {
223*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_path(w, dir, p) {
224*4882a593Smuzhiyun 			if (p->is_supply || p->weak || !p->connect)
225*4882a593Smuzhiyun 				continue;
226*4882a593Smuzhiyun 			node = p->node[rdir];
227*4882a593Smuzhiyun 			if (node->endpoints[dir] != -1) {
228*4882a593Smuzhiyun 				node->endpoints[dir] = -1;
229*4882a593Smuzhiyun 				list_add_tail(&node->work_list, &list);
230*4882a593Smuzhiyun 			}
231*4882a593Smuzhiyun 		}
232*4882a593Smuzhiyun 	}
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun /*
236*4882a593Smuzhiyun  * dapm_widget_invalidate_input_paths() - Invalidate the cached number of
237*4882a593Smuzhiyun  *  input paths
238*4882a593Smuzhiyun  * @w: The widget for which to invalidate the cached number of input paths
239*4882a593Smuzhiyun  *
240*4882a593Smuzhiyun  * Resets the cached number of inputs for the specified widget and all widgets
241*4882a593Smuzhiyun  * that can be reached via outcoming paths from the widget.
242*4882a593Smuzhiyun  *
243*4882a593Smuzhiyun  * This function must be called if the number of output paths for a widget might
244*4882a593Smuzhiyun  * have changed. E.g. if the source state of a widget changes or a path is added
245*4882a593Smuzhiyun  * or activated with the widget as the sink.
246*4882a593Smuzhiyun  */
dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget * w)247*4882a593Smuzhiyun static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /*
253*4882a593Smuzhiyun  * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
254*4882a593Smuzhiyun  *  output paths
255*4882a593Smuzhiyun  * @w: The widget for which to invalidate the cached number of output paths
256*4882a593Smuzhiyun  *
257*4882a593Smuzhiyun  * Resets the cached number of outputs for the specified widget and all widgets
258*4882a593Smuzhiyun  * that can be reached via incoming paths from the widget.
259*4882a593Smuzhiyun  *
260*4882a593Smuzhiyun  * This function must be called if the number of output paths for a widget might
261*4882a593Smuzhiyun  * have changed. E.g. if the sink state of a widget changes or a path is added
262*4882a593Smuzhiyun  * or activated with the widget as the source.
263*4882a593Smuzhiyun  */
dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget * w)264*4882a593Smuzhiyun static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun /*
270*4882a593Smuzhiyun  * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
271*4882a593Smuzhiyun  *  for the widgets connected to a path
272*4882a593Smuzhiyun  * @p: The path to invalidate
273*4882a593Smuzhiyun  *
274*4882a593Smuzhiyun  * Resets the cached number of inputs for the sink of the path and the cached
275*4882a593Smuzhiyun  * number of outputs for the source of the path.
276*4882a593Smuzhiyun  *
277*4882a593Smuzhiyun  * This function must be called when a path is added, removed or the connected
278*4882a593Smuzhiyun  * state changes.
279*4882a593Smuzhiyun  */
dapm_path_invalidate(struct snd_soc_dapm_path * p)280*4882a593Smuzhiyun static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	/*
283*4882a593Smuzhiyun 	 * Weak paths or supply paths do not influence the number of input or
284*4882a593Smuzhiyun 	 * output paths of their neighbors.
285*4882a593Smuzhiyun 	 */
286*4882a593Smuzhiyun 	if (p->weak || p->is_supply)
287*4882a593Smuzhiyun 		return;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	/*
290*4882a593Smuzhiyun 	 * The number of connected endpoints is the sum of the number of
291*4882a593Smuzhiyun 	 * connected endpoints of all neighbors. If a node with 0 connected
292*4882a593Smuzhiyun 	 * endpoints is either connected or disconnected that sum won't change,
293*4882a593Smuzhiyun 	 * so there is no need to re-check the path.
294*4882a593Smuzhiyun 	 */
295*4882a593Smuzhiyun 	if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0)
296*4882a593Smuzhiyun 		dapm_widget_invalidate_input_paths(p->sink);
297*4882a593Smuzhiyun 	if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0)
298*4882a593Smuzhiyun 		dapm_widget_invalidate_output_paths(p->source);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
dapm_mark_endpoints_dirty(struct snd_soc_card * card)301*4882a593Smuzhiyun void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	mutex_lock(&card->dapm_mutex);
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	for_each_card_widgets(card, w) {
308*4882a593Smuzhiyun 		if (w->is_ep) {
309*4882a593Smuzhiyun 			dapm_mark_dirty(w, "Rechecking endpoints");
310*4882a593Smuzhiyun 			if (w->is_ep & SND_SOC_DAPM_EP_SINK)
311*4882a593Smuzhiyun 				dapm_widget_invalidate_output_paths(w);
312*4882a593Smuzhiyun 			if (w->is_ep & SND_SOC_DAPM_EP_SOURCE)
313*4882a593Smuzhiyun 				dapm_widget_invalidate_input_paths(w);
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun /* create a new dapm widget */
dapm_cnew_widget(const struct snd_soc_dapm_widget * _widget)322*4882a593Smuzhiyun static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
323*4882a593Smuzhiyun 	const struct snd_soc_dapm_widget *_widget)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	w = kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
328*4882a593Smuzhiyun 	if (!w)
329*4882a593Smuzhiyun 		return NULL;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/*
332*4882a593Smuzhiyun 	 * w->name is duplicated in caller, but w->sname isn't.
333*4882a593Smuzhiyun 	 * Duplicate it here if defined
334*4882a593Smuzhiyun 	 */
335*4882a593Smuzhiyun 	if (_widget->sname) {
336*4882a593Smuzhiyun 		w->sname = kstrdup_const(_widget->sname, GFP_KERNEL);
337*4882a593Smuzhiyun 		if (!w->sname) {
338*4882a593Smuzhiyun 			kfree(w);
339*4882a593Smuzhiyun 			return NULL;
340*4882a593Smuzhiyun 		}
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 	return w;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun struct dapm_kcontrol_data {
346*4882a593Smuzhiyun 	unsigned int value;
347*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *widget;
348*4882a593Smuzhiyun 	struct list_head paths;
349*4882a593Smuzhiyun 	struct snd_soc_dapm_widget_list *wlist;
350*4882a593Smuzhiyun };
351*4882a593Smuzhiyun 
dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget * widget,struct snd_kcontrol * kcontrol,const char * ctrl_name)352*4882a593Smuzhiyun static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
353*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol, const char *ctrl_name)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data;
356*4882a593Smuzhiyun 	struct soc_mixer_control *mc;
357*4882a593Smuzhiyun 	struct soc_enum *e;
358*4882a593Smuzhiyun 	const char *name;
359*4882a593Smuzhiyun 	int ret;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	data = kzalloc(sizeof(*data), GFP_KERNEL);
362*4882a593Smuzhiyun 	if (!data)
363*4882a593Smuzhiyun 		return -ENOMEM;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	INIT_LIST_HEAD(&data->paths);
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	switch (widget->id) {
368*4882a593Smuzhiyun 	case snd_soc_dapm_switch:
369*4882a593Smuzhiyun 	case snd_soc_dapm_mixer:
370*4882a593Smuzhiyun 	case snd_soc_dapm_mixer_named_ctl:
371*4882a593Smuzhiyun 		mc = (struct soc_mixer_control *)kcontrol->private_value;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 		if (mc->autodisable && snd_soc_volsw_is_stereo(mc))
374*4882a593Smuzhiyun 			dev_warn(widget->dapm->dev,
375*4882a593Smuzhiyun 				 "ASoC: Unsupported stereo autodisable control '%s'\n",
376*4882a593Smuzhiyun 				 ctrl_name);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 		if (mc->autodisable) {
379*4882a593Smuzhiyun 			struct snd_soc_dapm_widget template;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 			name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
382*4882a593Smuzhiyun 					 "Autodisable");
383*4882a593Smuzhiyun 			if (!name) {
384*4882a593Smuzhiyun 				ret = -ENOMEM;
385*4882a593Smuzhiyun 				goto err_data;
386*4882a593Smuzhiyun 			}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 			memset(&template, 0, sizeof(template));
389*4882a593Smuzhiyun 			template.reg = mc->reg;
390*4882a593Smuzhiyun 			template.mask = (1 << fls(mc->max)) - 1;
391*4882a593Smuzhiyun 			template.shift = mc->shift;
392*4882a593Smuzhiyun 			if (mc->invert)
393*4882a593Smuzhiyun 				template.off_val = mc->max;
394*4882a593Smuzhiyun 			else
395*4882a593Smuzhiyun 				template.off_val = 0;
396*4882a593Smuzhiyun 			template.on_val = template.off_val;
397*4882a593Smuzhiyun 			template.id = snd_soc_dapm_kcontrol;
398*4882a593Smuzhiyun 			template.name = name;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 			data->value = template.on_val;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 			data->widget =
403*4882a593Smuzhiyun 				snd_soc_dapm_new_control_unlocked(widget->dapm,
404*4882a593Smuzhiyun 				&template);
405*4882a593Smuzhiyun 			kfree(name);
406*4882a593Smuzhiyun 			if (IS_ERR(data->widget)) {
407*4882a593Smuzhiyun 				ret = PTR_ERR(data->widget);
408*4882a593Smuzhiyun 				goto err_data;
409*4882a593Smuzhiyun 			}
410*4882a593Smuzhiyun 		}
411*4882a593Smuzhiyun 		break;
412*4882a593Smuzhiyun 	case snd_soc_dapm_demux:
413*4882a593Smuzhiyun 	case snd_soc_dapm_mux:
414*4882a593Smuzhiyun 		e = (struct soc_enum *)kcontrol->private_value;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 		if (e->autodisable) {
417*4882a593Smuzhiyun 			struct snd_soc_dapm_widget template;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 			name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
420*4882a593Smuzhiyun 					 "Autodisable");
421*4882a593Smuzhiyun 			if (!name) {
422*4882a593Smuzhiyun 				ret = -ENOMEM;
423*4882a593Smuzhiyun 				goto err_data;
424*4882a593Smuzhiyun 			}
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 			memset(&template, 0, sizeof(template));
427*4882a593Smuzhiyun 			template.reg = e->reg;
428*4882a593Smuzhiyun 			template.mask = e->mask;
429*4882a593Smuzhiyun 			template.shift = e->shift_l;
430*4882a593Smuzhiyun 			template.off_val = snd_soc_enum_item_to_val(e, 0);
431*4882a593Smuzhiyun 			template.on_val = template.off_val;
432*4882a593Smuzhiyun 			template.id = snd_soc_dapm_kcontrol;
433*4882a593Smuzhiyun 			template.name = name;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 			data->value = template.on_val;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 			data->widget = snd_soc_dapm_new_control_unlocked(
438*4882a593Smuzhiyun 						widget->dapm, &template);
439*4882a593Smuzhiyun 			kfree(name);
440*4882a593Smuzhiyun 			if (IS_ERR(data->widget)) {
441*4882a593Smuzhiyun 				ret = PTR_ERR(data->widget);
442*4882a593Smuzhiyun 				goto err_data;
443*4882a593Smuzhiyun 			}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 			snd_soc_dapm_add_path(widget->dapm, data->widget,
446*4882a593Smuzhiyun 					      widget, NULL, NULL);
447*4882a593Smuzhiyun 		} else if (e->reg != SND_SOC_NOPM) {
448*4882a593Smuzhiyun 			data->value = soc_dapm_read(widget->dapm, e->reg) &
449*4882a593Smuzhiyun 				      (e->mask << e->shift_l);
450*4882a593Smuzhiyun 		}
451*4882a593Smuzhiyun 		break;
452*4882a593Smuzhiyun 	default:
453*4882a593Smuzhiyun 		break;
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	kcontrol->private_data = data;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	return 0;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun err_data:
461*4882a593Smuzhiyun 	kfree(data);
462*4882a593Smuzhiyun 	return ret;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
dapm_kcontrol_free(struct snd_kcontrol * kctl)465*4882a593Smuzhiyun static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	list_del(&data->paths);
470*4882a593Smuzhiyun 	kfree(data->wlist);
471*4882a593Smuzhiyun 	kfree(data);
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
dapm_kcontrol_get_wlist(const struct snd_kcontrol * kcontrol)474*4882a593Smuzhiyun static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
475*4882a593Smuzhiyun 	const struct snd_kcontrol *kcontrol)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	return data->wlist;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun 
dapm_kcontrol_add_widget(struct snd_kcontrol * kcontrol,struct snd_soc_dapm_widget * widget)482*4882a593Smuzhiyun static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
483*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *widget)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
486*4882a593Smuzhiyun 	struct snd_soc_dapm_widget_list *new_wlist;
487*4882a593Smuzhiyun 	unsigned int n;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	if (data->wlist)
490*4882a593Smuzhiyun 		n = data->wlist->num_widgets + 1;
491*4882a593Smuzhiyun 	else
492*4882a593Smuzhiyun 		n = 1;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	new_wlist = krealloc(data->wlist,
495*4882a593Smuzhiyun 			     struct_size(new_wlist, widgets, n),
496*4882a593Smuzhiyun 			     GFP_KERNEL);
497*4882a593Smuzhiyun 	if (!new_wlist)
498*4882a593Smuzhiyun 		return -ENOMEM;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	new_wlist->widgets[n - 1] = widget;
501*4882a593Smuzhiyun 	new_wlist->num_widgets = n;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	data->wlist = new_wlist;
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	return 0;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
dapm_kcontrol_add_path(const struct snd_kcontrol * kcontrol,struct snd_soc_dapm_path * path)508*4882a593Smuzhiyun static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
509*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	list_add_tail(&path->list_kcontrol, &data->paths);
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
dapm_kcontrol_is_powered(const struct snd_kcontrol * kcontrol)516*4882a593Smuzhiyun static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	if (!data->widget)
521*4882a593Smuzhiyun 		return true;
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	return data->widget->power;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
dapm_kcontrol_get_path_list(const struct snd_kcontrol * kcontrol)526*4882a593Smuzhiyun static struct list_head *dapm_kcontrol_get_path_list(
527*4882a593Smuzhiyun 	const struct snd_kcontrol *kcontrol)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	return &data->paths;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun #define dapm_kcontrol_for_each_path(path, kcontrol) \
535*4882a593Smuzhiyun 	list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
536*4882a593Smuzhiyun 		list_kcontrol)
537*4882a593Smuzhiyun 
dapm_kcontrol_get_value(const struct snd_kcontrol * kcontrol)538*4882a593Smuzhiyun unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	return data->value;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
545*4882a593Smuzhiyun 
dapm_kcontrol_set_value(const struct snd_kcontrol * kcontrol,unsigned int value)546*4882a593Smuzhiyun static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
547*4882a593Smuzhiyun 	unsigned int value)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	if (data->value == value)
552*4882a593Smuzhiyun 		return false;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (data->widget) {
555*4882a593Smuzhiyun 		switch (dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->id) {
556*4882a593Smuzhiyun 		case snd_soc_dapm_switch:
557*4882a593Smuzhiyun 		case snd_soc_dapm_mixer:
558*4882a593Smuzhiyun 		case snd_soc_dapm_mixer_named_ctl:
559*4882a593Smuzhiyun 			data->widget->on_val = value & data->widget->mask;
560*4882a593Smuzhiyun 			break;
561*4882a593Smuzhiyun 		case snd_soc_dapm_demux:
562*4882a593Smuzhiyun 		case snd_soc_dapm_mux:
563*4882a593Smuzhiyun 			data->widget->on_val = value >> data->widget->shift;
564*4882a593Smuzhiyun 			break;
565*4882a593Smuzhiyun 		default:
566*4882a593Smuzhiyun 			data->widget->on_val = value;
567*4882a593Smuzhiyun 			break;
568*4882a593Smuzhiyun 		}
569*4882a593Smuzhiyun 	}
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	data->value = value;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	return true;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun /**
577*4882a593Smuzhiyun  * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
578*4882a593Smuzhiyun  *   kcontrol
579*4882a593Smuzhiyun  * @kcontrol: The kcontrol
580*4882a593Smuzhiyun  */
snd_soc_dapm_kcontrol_widget(struct snd_kcontrol * kcontrol)581*4882a593Smuzhiyun struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
582*4882a593Smuzhiyun 				struct snd_kcontrol *kcontrol)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun 	return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun /**
589*4882a593Smuzhiyun  * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
590*4882a593Smuzhiyun  *  kcontrol
591*4882a593Smuzhiyun  * @kcontrol: The kcontrol
592*4882a593Smuzhiyun  *
593*4882a593Smuzhiyun  * Note: This function must only be used on kcontrols that are known to have
594*4882a593Smuzhiyun  * been registered for a CODEC. Otherwise the behaviour is undefined.
595*4882a593Smuzhiyun  */
snd_soc_dapm_kcontrol_dapm(struct snd_kcontrol * kcontrol)596*4882a593Smuzhiyun struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
597*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
602*4882a593Smuzhiyun 
dapm_reset(struct snd_soc_card * card)603*4882a593Smuzhiyun static void dapm_reset(struct snd_soc_card *card)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	lockdep_assert_held(&card->dapm_mutex);
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 	memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	for_each_card_widgets(card, w) {
612*4882a593Smuzhiyun 		w->new_power = w->power;
613*4882a593Smuzhiyun 		w->power_checked = false;
614*4882a593Smuzhiyun 	}
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
soc_dapm_prefix(struct snd_soc_dapm_context * dapm)617*4882a593Smuzhiyun static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	if (!dapm->component)
620*4882a593Smuzhiyun 		return NULL;
621*4882a593Smuzhiyun 	return dapm->component->name_prefix;
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun 
soc_dapm_read(struct snd_soc_dapm_context * dapm,int reg)624*4882a593Smuzhiyun static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun 	if (!dapm->component)
627*4882a593Smuzhiyun 		return -EIO;
628*4882a593Smuzhiyun 	return  snd_soc_component_read(dapm->component, reg);
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun 
soc_dapm_update_bits(struct snd_soc_dapm_context * dapm,int reg,unsigned int mask,unsigned int value)631*4882a593Smuzhiyun static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
632*4882a593Smuzhiyun 	int reg, unsigned int mask, unsigned int value)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun 	if (!dapm->component)
635*4882a593Smuzhiyun 		return -EIO;
636*4882a593Smuzhiyun 	return snd_soc_component_update_bits(dapm->component, reg,
637*4882a593Smuzhiyun 					     mask, value);
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun 
soc_dapm_test_bits(struct snd_soc_dapm_context * dapm,int reg,unsigned int mask,unsigned int value)640*4882a593Smuzhiyun static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
641*4882a593Smuzhiyun 	int reg, unsigned int mask, unsigned int value)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	if (!dapm->component)
644*4882a593Smuzhiyun 		return -EIO;
645*4882a593Smuzhiyun 	return snd_soc_component_test_bits(dapm->component, reg, mask, value);
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
soc_dapm_async_complete(struct snd_soc_dapm_context * dapm)648*4882a593Smuzhiyun static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun 	if (dapm->component)
651*4882a593Smuzhiyun 		snd_soc_component_async_complete(dapm->component);
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun static struct snd_soc_dapm_widget *
dapm_wcache_lookup(struct snd_soc_dapm_wcache * wcache,const char * name)655*4882a593Smuzhiyun dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
656*4882a593Smuzhiyun {
657*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = wcache->widget;
658*4882a593Smuzhiyun 	struct list_head *wlist;
659*4882a593Smuzhiyun 	const int depth = 2;
660*4882a593Smuzhiyun 	int i = 0;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	if (w) {
663*4882a593Smuzhiyun 		wlist = &w->dapm->card->widgets;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 		list_for_each_entry_from(w, wlist, list) {
666*4882a593Smuzhiyun 			if (!strcmp(name, w->name))
667*4882a593Smuzhiyun 				return w;
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 			if (++i == depth)
670*4882a593Smuzhiyun 				break;
671*4882a593Smuzhiyun 		}
672*4882a593Smuzhiyun 	}
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	return NULL;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
dapm_wcache_update(struct snd_soc_dapm_wcache * wcache,struct snd_soc_dapm_widget * w)677*4882a593Smuzhiyun static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
678*4882a593Smuzhiyun 				      struct snd_soc_dapm_widget *w)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	wcache->widget = w;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun /**
684*4882a593Smuzhiyun  * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
685*4882a593Smuzhiyun  * @dapm: The DAPM context for which to set the level
686*4882a593Smuzhiyun  * @level: The level to set
687*4882a593Smuzhiyun  *
688*4882a593Smuzhiyun  * Forces the DAPM bias level to a specific state. It will call the bias level
689*4882a593Smuzhiyun  * callback of DAPM context with the specified level. This will even happen if
690*4882a593Smuzhiyun  * the context is already at the same level. Furthermore it will not go through
691*4882a593Smuzhiyun  * the normal bias level sequencing, meaning any intermediate states between the
692*4882a593Smuzhiyun  * current and the target state will not be entered.
693*4882a593Smuzhiyun  *
694*4882a593Smuzhiyun  * Note that the change in bias level is only temporary and the next time
695*4882a593Smuzhiyun  * snd_soc_dapm_sync() is called the state will be set to the level as
696*4882a593Smuzhiyun  * determined by the DAPM core. The function is mainly intended to be used to
697*4882a593Smuzhiyun  * used during probe or resume from suspend to power up the device so
698*4882a593Smuzhiyun  * initialization can be done, before the DAPM core takes over.
699*4882a593Smuzhiyun  */
snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context * dapm,enum snd_soc_bias_level level)700*4882a593Smuzhiyun int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
701*4882a593Smuzhiyun 	enum snd_soc_bias_level level)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun 	int ret = 0;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	if (dapm->component)
706*4882a593Smuzhiyun 		ret = snd_soc_component_set_bias_level(dapm->component, level);
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	if (ret == 0)
709*4882a593Smuzhiyun 		dapm->bias_level = level;
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	return ret;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun /**
716*4882a593Smuzhiyun  * snd_soc_dapm_set_bias_level - set the bias level for the system
717*4882a593Smuzhiyun  * @dapm: DAPM context
718*4882a593Smuzhiyun  * @level: level to configure
719*4882a593Smuzhiyun  *
720*4882a593Smuzhiyun  * Configure the bias (power) levels for the SoC audio device.
721*4882a593Smuzhiyun  *
722*4882a593Smuzhiyun  * Returns 0 for success else error.
723*4882a593Smuzhiyun  */
snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context * dapm,enum snd_soc_bias_level level)724*4882a593Smuzhiyun static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
725*4882a593Smuzhiyun 				       enum snd_soc_bias_level level)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
728*4882a593Smuzhiyun 	int ret = 0;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	trace_snd_soc_bias_level_start(card, level);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	ret = snd_soc_card_set_bias_level(card, dapm, level);
733*4882a593Smuzhiyun 	if (ret != 0)
734*4882a593Smuzhiyun 		goto out;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	if (!card || dapm != &card->dapm)
737*4882a593Smuzhiyun 		ret = snd_soc_dapm_force_bias_level(dapm, level);
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	if (ret != 0)
740*4882a593Smuzhiyun 		goto out;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	ret = snd_soc_card_set_bias_level_post(card, dapm, level);
743*4882a593Smuzhiyun out:
744*4882a593Smuzhiyun 	trace_snd_soc_bias_level_done(card, level);
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	return ret;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun /* connect mux widget to its interconnecting audio paths */
dapm_connect_mux(struct snd_soc_dapm_context * dapm,struct snd_soc_dapm_path * path,const char * control_name,struct snd_soc_dapm_widget * w)750*4882a593Smuzhiyun static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
751*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path, const char *control_name,
752*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun 	const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
755*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
756*4882a593Smuzhiyun 	unsigned int val, item;
757*4882a593Smuzhiyun 	int i;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	if (e->reg != SND_SOC_NOPM) {
760*4882a593Smuzhiyun 		val = soc_dapm_read(dapm, e->reg);
761*4882a593Smuzhiyun 		val = (val >> e->shift_l) & e->mask;
762*4882a593Smuzhiyun 		item = snd_soc_enum_val_to_item(e, val);
763*4882a593Smuzhiyun 	} else {
764*4882a593Smuzhiyun 		/* since a virtual mux has no backing registers to
765*4882a593Smuzhiyun 		 * decide which path to connect, it will try to match
766*4882a593Smuzhiyun 		 * with the first enumeration.  This is to ensure
767*4882a593Smuzhiyun 		 * that the default mux choice (the first) will be
768*4882a593Smuzhiyun 		 * correctly powered up during initialization.
769*4882a593Smuzhiyun 		 */
770*4882a593Smuzhiyun 		item = 0;
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	i = match_string(e->texts, e->items, control_name);
774*4882a593Smuzhiyun 	if (i < 0)
775*4882a593Smuzhiyun 		return -ENODEV;
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	path->name = e->texts[i];
778*4882a593Smuzhiyun 	path->connect = (i == item);
779*4882a593Smuzhiyun 	return 0;
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun /* set up initial codec paths */
dapm_set_mixer_path_status(struct snd_soc_dapm_path * p,int i,int nth_path)784*4882a593Smuzhiyun static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
785*4882a593Smuzhiyun 				       int nth_path)
786*4882a593Smuzhiyun {
787*4882a593Smuzhiyun 	struct soc_mixer_control *mc = (struct soc_mixer_control *)
788*4882a593Smuzhiyun 		p->sink->kcontrol_news[i].private_value;
789*4882a593Smuzhiyun 	unsigned int reg = mc->reg;
790*4882a593Smuzhiyun 	unsigned int shift = mc->shift;
791*4882a593Smuzhiyun 	unsigned int max = mc->max;
792*4882a593Smuzhiyun 	unsigned int mask = (1 << fls(max)) - 1;
793*4882a593Smuzhiyun 	unsigned int invert = mc->invert;
794*4882a593Smuzhiyun 	unsigned int val;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	if (reg != SND_SOC_NOPM) {
797*4882a593Smuzhiyun 		val = soc_dapm_read(p->sink->dapm, reg);
798*4882a593Smuzhiyun 		/*
799*4882a593Smuzhiyun 		 * The nth_path argument allows this function to know
800*4882a593Smuzhiyun 		 * which path of a kcontrol it is setting the initial
801*4882a593Smuzhiyun 		 * status for. Ideally this would support any number
802*4882a593Smuzhiyun 		 * of paths and channels. But since kcontrols only come
803*4882a593Smuzhiyun 		 * in mono and stereo variants, we are limited to 2
804*4882a593Smuzhiyun 		 * channels.
805*4882a593Smuzhiyun 		 *
806*4882a593Smuzhiyun 		 * The following code assumes for stereo controls the
807*4882a593Smuzhiyun 		 * first path is the left channel, and all remaining
808*4882a593Smuzhiyun 		 * paths are the right channel.
809*4882a593Smuzhiyun 		 */
810*4882a593Smuzhiyun 		if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
811*4882a593Smuzhiyun 			if (reg != mc->rreg)
812*4882a593Smuzhiyun 				val = soc_dapm_read(p->sink->dapm, mc->rreg);
813*4882a593Smuzhiyun 			val = (val >> mc->rshift) & mask;
814*4882a593Smuzhiyun 		} else {
815*4882a593Smuzhiyun 			val = (val >> shift) & mask;
816*4882a593Smuzhiyun 		}
817*4882a593Smuzhiyun 		if (invert)
818*4882a593Smuzhiyun 			val = max - val;
819*4882a593Smuzhiyun 		p->connect = !!val;
820*4882a593Smuzhiyun 	} else {
821*4882a593Smuzhiyun 		/* since a virtual mixer has no backing registers to
822*4882a593Smuzhiyun 		 * decide which path to connect, it will try to match
823*4882a593Smuzhiyun 		 * with initial state.  This is to ensure
824*4882a593Smuzhiyun 		 * that the default mixer choice will be
825*4882a593Smuzhiyun 		 * correctly powered up during initialization.
826*4882a593Smuzhiyun 		 */
827*4882a593Smuzhiyun 		p->connect = invert;
828*4882a593Smuzhiyun 	}
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun /* connect mixer widget to its interconnecting audio paths */
dapm_connect_mixer(struct snd_soc_dapm_context * dapm,struct snd_soc_dapm_path * path,const char * control_name)832*4882a593Smuzhiyun static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
833*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path, const char *control_name)
834*4882a593Smuzhiyun {
835*4882a593Smuzhiyun 	int i, nth_path = 0;
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	/* search for mixer kcontrol */
838*4882a593Smuzhiyun 	for (i = 0; i < path->sink->num_kcontrols; i++) {
839*4882a593Smuzhiyun 		if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
840*4882a593Smuzhiyun 			path->name = path->sink->kcontrol_news[i].name;
841*4882a593Smuzhiyun 			dapm_set_mixer_path_status(path, i, nth_path++);
842*4882a593Smuzhiyun 			return 0;
843*4882a593Smuzhiyun 		}
844*4882a593Smuzhiyun 	}
845*4882a593Smuzhiyun 	return -ENODEV;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun 
dapm_is_shared_kcontrol(struct snd_soc_dapm_context * dapm,struct snd_soc_dapm_widget * kcontrolw,const struct snd_kcontrol_new * kcontrol_new,struct snd_kcontrol ** kcontrol)848*4882a593Smuzhiyun static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
849*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *kcontrolw,
850*4882a593Smuzhiyun 	const struct snd_kcontrol_new *kcontrol_new,
851*4882a593Smuzhiyun 	struct snd_kcontrol **kcontrol)
852*4882a593Smuzhiyun {
853*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
854*4882a593Smuzhiyun 	int i;
855*4882a593Smuzhiyun 
856*4882a593Smuzhiyun 	*kcontrol = NULL;
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 	for_each_card_widgets(dapm->card, w) {
859*4882a593Smuzhiyun 		if (w == kcontrolw || w->dapm != kcontrolw->dapm)
860*4882a593Smuzhiyun 			continue;
861*4882a593Smuzhiyun 		for (i = 0; i < w->num_kcontrols; i++) {
862*4882a593Smuzhiyun 			if (&w->kcontrol_news[i] == kcontrol_new) {
863*4882a593Smuzhiyun 				if (w->kcontrols)
864*4882a593Smuzhiyun 					*kcontrol = w->kcontrols[i];
865*4882a593Smuzhiyun 				return 1;
866*4882a593Smuzhiyun 			}
867*4882a593Smuzhiyun 		}
868*4882a593Smuzhiyun 	}
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun 	return 0;
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun /*
874*4882a593Smuzhiyun  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
875*4882a593Smuzhiyun  * create it. Either way, add the widget into the control's widget list
876*4882a593Smuzhiyun  */
dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget * w,int kci)877*4882a593Smuzhiyun static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
878*4882a593Smuzhiyun 	int kci)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = w->dapm;
881*4882a593Smuzhiyun 	struct snd_card *card = dapm->card->snd_card;
882*4882a593Smuzhiyun 	const char *prefix;
883*4882a593Smuzhiyun 	size_t prefix_len;
884*4882a593Smuzhiyun 	int shared;
885*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol;
886*4882a593Smuzhiyun 	bool wname_in_long_name, kcname_in_long_name;
887*4882a593Smuzhiyun 	char *long_name = NULL;
888*4882a593Smuzhiyun 	const char *name;
889*4882a593Smuzhiyun 	int ret = 0;
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 	prefix = soc_dapm_prefix(dapm);
892*4882a593Smuzhiyun 	if (prefix)
893*4882a593Smuzhiyun 		prefix_len = strlen(prefix) + 1;
894*4882a593Smuzhiyun 	else
895*4882a593Smuzhiyun 		prefix_len = 0;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
898*4882a593Smuzhiyun 					 &kcontrol);
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	if (!kcontrol) {
901*4882a593Smuzhiyun 		if (shared) {
902*4882a593Smuzhiyun 			wname_in_long_name = false;
903*4882a593Smuzhiyun 			kcname_in_long_name = true;
904*4882a593Smuzhiyun 		} else {
905*4882a593Smuzhiyun 			switch (w->id) {
906*4882a593Smuzhiyun 			case snd_soc_dapm_switch:
907*4882a593Smuzhiyun 			case snd_soc_dapm_mixer:
908*4882a593Smuzhiyun 			case snd_soc_dapm_pga:
909*4882a593Smuzhiyun 			case snd_soc_dapm_effect:
910*4882a593Smuzhiyun 			case snd_soc_dapm_out_drv:
911*4882a593Smuzhiyun 				wname_in_long_name = true;
912*4882a593Smuzhiyun 				kcname_in_long_name = true;
913*4882a593Smuzhiyun 				break;
914*4882a593Smuzhiyun 			case snd_soc_dapm_mixer_named_ctl:
915*4882a593Smuzhiyun 				wname_in_long_name = false;
916*4882a593Smuzhiyun 				kcname_in_long_name = true;
917*4882a593Smuzhiyun 				break;
918*4882a593Smuzhiyun 			case snd_soc_dapm_demux:
919*4882a593Smuzhiyun 			case snd_soc_dapm_mux:
920*4882a593Smuzhiyun 				wname_in_long_name = true;
921*4882a593Smuzhiyun 				kcname_in_long_name = false;
922*4882a593Smuzhiyun 				break;
923*4882a593Smuzhiyun 			default:
924*4882a593Smuzhiyun 				return -EINVAL;
925*4882a593Smuzhiyun 			}
926*4882a593Smuzhiyun 		}
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 		if (wname_in_long_name && kcname_in_long_name) {
929*4882a593Smuzhiyun 			/*
930*4882a593Smuzhiyun 			 * The control will get a prefix from the control
931*4882a593Smuzhiyun 			 * creation process but we're also using the same
932*4882a593Smuzhiyun 			 * prefix for widgets so cut the prefix off the
933*4882a593Smuzhiyun 			 * front of the widget name.
934*4882a593Smuzhiyun 			 */
935*4882a593Smuzhiyun 			long_name = kasprintf(GFP_KERNEL, "%s %s",
936*4882a593Smuzhiyun 				 w->name + prefix_len,
937*4882a593Smuzhiyun 				 w->kcontrol_news[kci].name);
938*4882a593Smuzhiyun 			if (long_name == NULL)
939*4882a593Smuzhiyun 				return -ENOMEM;
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 			name = long_name;
942*4882a593Smuzhiyun 		} else if (wname_in_long_name) {
943*4882a593Smuzhiyun 			long_name = NULL;
944*4882a593Smuzhiyun 			name = w->name + prefix_len;
945*4882a593Smuzhiyun 		} else {
946*4882a593Smuzhiyun 			long_name = NULL;
947*4882a593Smuzhiyun 			name = w->kcontrol_news[kci].name;
948*4882a593Smuzhiyun 		}
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 		kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
951*4882a593Smuzhiyun 					prefix);
952*4882a593Smuzhiyun 		if (!kcontrol) {
953*4882a593Smuzhiyun 			ret = -ENOMEM;
954*4882a593Smuzhiyun 			goto exit_free;
955*4882a593Smuzhiyun 		}
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 		kcontrol->private_free = dapm_kcontrol_free;
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 		ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
960*4882a593Smuzhiyun 		if (ret) {
961*4882a593Smuzhiyun 			snd_ctl_free_one(kcontrol);
962*4882a593Smuzhiyun 			goto exit_free;
963*4882a593Smuzhiyun 		}
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 		ret = snd_ctl_add(card, kcontrol);
966*4882a593Smuzhiyun 		if (ret < 0) {
967*4882a593Smuzhiyun 			dev_err(dapm->dev,
968*4882a593Smuzhiyun 				"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
969*4882a593Smuzhiyun 				w->name, name, ret);
970*4882a593Smuzhiyun 			goto exit_free;
971*4882a593Smuzhiyun 		}
972*4882a593Smuzhiyun 	}
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	ret = dapm_kcontrol_add_widget(kcontrol, w);
975*4882a593Smuzhiyun 	if (ret == 0)
976*4882a593Smuzhiyun 		w->kcontrols[kci] = kcontrol;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun exit_free:
979*4882a593Smuzhiyun 	kfree(long_name);
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	return ret;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun /* create new dapm mixer control */
dapm_new_mixer(struct snd_soc_dapm_widget * w)985*4882a593Smuzhiyun static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun 	int i, ret;
988*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
989*4882a593Smuzhiyun 	struct dapm_kcontrol_data *data;
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 	/* add kcontrol */
992*4882a593Smuzhiyun 	for (i = 0; i < w->num_kcontrols; i++) {
993*4882a593Smuzhiyun 		/* match name */
994*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_source_path(w, path) {
995*4882a593Smuzhiyun 			/* mixer/mux paths name must match control name */
996*4882a593Smuzhiyun 			if (path->name != (char *)w->kcontrol_news[i].name)
997*4882a593Smuzhiyun 				continue;
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 			if (!w->kcontrols[i]) {
1000*4882a593Smuzhiyun 				ret = dapm_create_or_share_kcontrol(w, i);
1001*4882a593Smuzhiyun 				if (ret < 0)
1002*4882a593Smuzhiyun 					return ret;
1003*4882a593Smuzhiyun 			}
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 			dapm_kcontrol_add_path(w->kcontrols[i], path);
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 			data = snd_kcontrol_chip(w->kcontrols[i]);
1008*4882a593Smuzhiyun 			if (data->widget)
1009*4882a593Smuzhiyun 				snd_soc_dapm_add_path(data->widget->dapm,
1010*4882a593Smuzhiyun 						      data->widget,
1011*4882a593Smuzhiyun 						      path->source,
1012*4882a593Smuzhiyun 						      NULL, NULL);
1013*4882a593Smuzhiyun 		}
1014*4882a593Smuzhiyun 	}
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	return 0;
1017*4882a593Smuzhiyun }
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun /* create new dapm mux control */
dapm_new_mux(struct snd_soc_dapm_widget * w)1020*4882a593Smuzhiyun static int dapm_new_mux(struct snd_soc_dapm_widget *w)
1021*4882a593Smuzhiyun {
1022*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = w->dapm;
1023*4882a593Smuzhiyun 	enum snd_soc_dapm_direction dir;
1024*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
1025*4882a593Smuzhiyun 	const char *type;
1026*4882a593Smuzhiyun 	int ret;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	switch (w->id) {
1029*4882a593Smuzhiyun 	case snd_soc_dapm_mux:
1030*4882a593Smuzhiyun 		dir = SND_SOC_DAPM_DIR_OUT;
1031*4882a593Smuzhiyun 		type = "mux";
1032*4882a593Smuzhiyun 		break;
1033*4882a593Smuzhiyun 	case snd_soc_dapm_demux:
1034*4882a593Smuzhiyun 		dir = SND_SOC_DAPM_DIR_IN;
1035*4882a593Smuzhiyun 		type = "demux";
1036*4882a593Smuzhiyun 		break;
1037*4882a593Smuzhiyun 	default:
1038*4882a593Smuzhiyun 		return -EINVAL;
1039*4882a593Smuzhiyun 	}
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	if (w->num_kcontrols != 1) {
1042*4882a593Smuzhiyun 		dev_err(dapm->dev,
1043*4882a593Smuzhiyun 			"ASoC: %s %s has incorrect number of controls\n", type,
1044*4882a593Smuzhiyun 			w->name);
1045*4882a593Smuzhiyun 		return -EINVAL;
1046*4882a593Smuzhiyun 	}
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	if (list_empty(&w->edges[dir])) {
1049*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
1050*4882a593Smuzhiyun 		return -EINVAL;
1051*4882a593Smuzhiyun 	}
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 	ret = dapm_create_or_share_kcontrol(w, 0);
1054*4882a593Smuzhiyun 	if (ret < 0)
1055*4882a593Smuzhiyun 		return ret;
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_path(w, dir, path) {
1058*4882a593Smuzhiyun 		if (path->name)
1059*4882a593Smuzhiyun 			dapm_kcontrol_add_path(w->kcontrols[0], path);
1060*4882a593Smuzhiyun 	}
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	return 0;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun /* create new dapm volume control */
dapm_new_pga(struct snd_soc_dapm_widget * w)1066*4882a593Smuzhiyun static int dapm_new_pga(struct snd_soc_dapm_widget *w)
1067*4882a593Smuzhiyun {
1068*4882a593Smuzhiyun 	int i, ret;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	for (i = 0; i < w->num_kcontrols; i++) {
1071*4882a593Smuzhiyun 		ret = dapm_create_or_share_kcontrol(w, i);
1072*4882a593Smuzhiyun 		if (ret < 0)
1073*4882a593Smuzhiyun 			return ret;
1074*4882a593Smuzhiyun 	}
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	return 0;
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun /* create new dapm dai link control */
dapm_new_dai_link(struct snd_soc_dapm_widget * w)1080*4882a593Smuzhiyun static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
1081*4882a593Smuzhiyun {
1082*4882a593Smuzhiyun 	int i, ret;
1083*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol;
1084*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = w->dapm;
1085*4882a593Smuzhiyun 	struct snd_card *card = dapm->card->snd_card;
1086*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = w->priv;
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	/* create control for links with > 1 config */
1089*4882a593Smuzhiyun 	if (rtd->dai_link->num_params <= 1)
1090*4882a593Smuzhiyun 		return 0;
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	/* add kcontrol */
1093*4882a593Smuzhiyun 	for (i = 0; i < w->num_kcontrols; i++) {
1094*4882a593Smuzhiyun 		kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
1095*4882a593Smuzhiyun 					w->name, NULL);
1096*4882a593Smuzhiyun 		ret = snd_ctl_add(card, kcontrol);
1097*4882a593Smuzhiyun 		if (ret < 0) {
1098*4882a593Smuzhiyun 			dev_err(dapm->dev,
1099*4882a593Smuzhiyun 				"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1100*4882a593Smuzhiyun 				w->name, w->kcontrol_news[i].name, ret);
1101*4882a593Smuzhiyun 			return ret;
1102*4882a593Smuzhiyun 		}
1103*4882a593Smuzhiyun 		kcontrol->private_data = w;
1104*4882a593Smuzhiyun 		w->kcontrols[i] = kcontrol;
1105*4882a593Smuzhiyun 	}
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	return 0;
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun 
1110*4882a593Smuzhiyun /* We implement power down on suspend by checking the power state of
1111*4882a593Smuzhiyun  * the ALSA card - when we are suspending the ALSA state for the card
1112*4882a593Smuzhiyun  * is set to D3.
1113*4882a593Smuzhiyun  */
snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget * widget)1114*4882a593Smuzhiyun static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun 	int level = snd_power_get_state(widget->dapm->card->snd_card);
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	switch (level) {
1119*4882a593Smuzhiyun 	case SNDRV_CTL_POWER_D3hot:
1120*4882a593Smuzhiyun 	case SNDRV_CTL_POWER_D3cold:
1121*4882a593Smuzhiyun 		if (widget->ignore_suspend)
1122*4882a593Smuzhiyun 			dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
1123*4882a593Smuzhiyun 				widget->name);
1124*4882a593Smuzhiyun 		return widget->ignore_suspend;
1125*4882a593Smuzhiyun 	default:
1126*4882a593Smuzhiyun 		return 1;
1127*4882a593Smuzhiyun 	}
1128*4882a593Smuzhiyun }
1129*4882a593Smuzhiyun 
dapm_widget_list_free(struct snd_soc_dapm_widget_list ** list)1130*4882a593Smuzhiyun static void dapm_widget_list_free(struct snd_soc_dapm_widget_list **list)
1131*4882a593Smuzhiyun {
1132*4882a593Smuzhiyun 	kfree(*list);
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun 
dapm_widget_list_create(struct snd_soc_dapm_widget_list ** list,struct list_head * widgets)1135*4882a593Smuzhiyun static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1136*4882a593Smuzhiyun 	struct list_head *widgets)
1137*4882a593Smuzhiyun {
1138*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
1139*4882a593Smuzhiyun 	struct list_head *it;
1140*4882a593Smuzhiyun 	unsigned int size = 0;
1141*4882a593Smuzhiyun 	unsigned int i = 0;
1142*4882a593Smuzhiyun 
1143*4882a593Smuzhiyun 	list_for_each(it, widgets)
1144*4882a593Smuzhiyun 		size++;
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	*list = kzalloc(struct_size(*list, widgets, size), GFP_KERNEL);
1147*4882a593Smuzhiyun 	if (*list == NULL)
1148*4882a593Smuzhiyun 		return -ENOMEM;
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	list_for_each_entry(w, widgets, work_list)
1151*4882a593Smuzhiyun 		(*list)->widgets[i++] = w;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	(*list)->num_widgets = i;
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	return 0;
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun /*
1159*4882a593Smuzhiyun  * Recursively reset the cached number of inputs or outputs for the specified
1160*4882a593Smuzhiyun  * widget and all widgets that can be reached via incoming or outcoming paths
1161*4882a593Smuzhiyun  * from the widget.
1162*4882a593Smuzhiyun  */
invalidate_paths_ep(struct snd_soc_dapm_widget * widget,enum snd_soc_dapm_direction dir)1163*4882a593Smuzhiyun static void invalidate_paths_ep(struct snd_soc_dapm_widget *widget,
1164*4882a593Smuzhiyun 	enum snd_soc_dapm_direction dir)
1165*4882a593Smuzhiyun {
1166*4882a593Smuzhiyun 	enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
1167*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	widget->endpoints[dir] = -1;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
1172*4882a593Smuzhiyun 		if (path->weak || path->is_supply)
1173*4882a593Smuzhiyun 			continue;
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 		if (path->walking)
1176*4882a593Smuzhiyun 			return;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 		if (path->connect) {
1179*4882a593Smuzhiyun 			path->walking = 1;
1180*4882a593Smuzhiyun 			invalidate_paths_ep(path->node[dir], dir);
1181*4882a593Smuzhiyun 			path->walking = 0;
1182*4882a593Smuzhiyun 		}
1183*4882a593Smuzhiyun 	}
1184*4882a593Smuzhiyun }
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun /*
1187*4882a593Smuzhiyun  * Common implementation for is_connected_output_ep() and
1188*4882a593Smuzhiyun  * is_connected_input_ep(). The function is inlined since the combined size of
1189*4882a593Smuzhiyun  * the two specialized functions is only marginally larger then the size of the
1190*4882a593Smuzhiyun  * generic function and at the same time the fast path of the specialized
1191*4882a593Smuzhiyun  * functions is significantly smaller than the generic function.
1192*4882a593Smuzhiyun  */
is_connected_ep(struct snd_soc_dapm_widget * widget,struct list_head * list,enum snd_soc_dapm_direction dir,int (* fn)(struct snd_soc_dapm_widget *,struct list_head *,bool (* custom_stop_condition)(struct snd_soc_dapm_widget *,enum snd_soc_dapm_direction)),bool (* custom_stop_condition)(struct snd_soc_dapm_widget *,enum snd_soc_dapm_direction))1193*4882a593Smuzhiyun static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
1194*4882a593Smuzhiyun 	struct list_head *list, enum snd_soc_dapm_direction dir,
1195*4882a593Smuzhiyun 	int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
1196*4882a593Smuzhiyun 		  bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1197*4882a593Smuzhiyun 						enum snd_soc_dapm_direction)),
1198*4882a593Smuzhiyun 	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1199*4882a593Smuzhiyun 				      enum snd_soc_dapm_direction))
1200*4882a593Smuzhiyun {
1201*4882a593Smuzhiyun 	enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
1202*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
1203*4882a593Smuzhiyun 	int con = 0;
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun 	if (widget->endpoints[dir] >= 0)
1206*4882a593Smuzhiyun 		return widget->endpoints[dir];
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	DAPM_UPDATE_STAT(widget, path_checks);
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	/* do we need to add this widget to the list ? */
1211*4882a593Smuzhiyun 	if (list)
1212*4882a593Smuzhiyun 		list_add_tail(&widget->work_list, list);
1213*4882a593Smuzhiyun 
1214*4882a593Smuzhiyun 	if (custom_stop_condition && custom_stop_condition(widget, dir)) {
1215*4882a593Smuzhiyun 		list = NULL;
1216*4882a593Smuzhiyun 		custom_stop_condition = NULL;
1217*4882a593Smuzhiyun 	}
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
1220*4882a593Smuzhiyun 		widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
1221*4882a593Smuzhiyun 		return widget->endpoints[dir];
1222*4882a593Smuzhiyun 	}
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
1225*4882a593Smuzhiyun 		DAPM_UPDATE_STAT(widget, neighbour_checks);
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 		if (path->weak || path->is_supply)
1228*4882a593Smuzhiyun 			continue;
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 		if (path->walking)
1231*4882a593Smuzhiyun 			return 1;
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 		trace_snd_soc_dapm_path(widget, dir, path);
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 		if (path->connect) {
1236*4882a593Smuzhiyun 			path->walking = 1;
1237*4882a593Smuzhiyun 			con += fn(path->node[dir], list, custom_stop_condition);
1238*4882a593Smuzhiyun 			path->walking = 0;
1239*4882a593Smuzhiyun 		}
1240*4882a593Smuzhiyun 	}
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	widget->endpoints[dir] = con;
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	return con;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun /*
1248*4882a593Smuzhiyun  * Recursively check for a completed path to an active or physically connected
1249*4882a593Smuzhiyun  * output widget. Returns number of complete paths.
1250*4882a593Smuzhiyun  *
1251*4882a593Smuzhiyun  * Optionally, can be supplied with a function acting as a stopping condition.
1252*4882a593Smuzhiyun  * This function takes the dapm widget currently being examined and the walk
1253*4882a593Smuzhiyun  * direction as an arguments, it should return true if widgets from that point
1254*4882a593Smuzhiyun  * in the graph onwards should not be added to the widget list.
1255*4882a593Smuzhiyun  */
is_connected_output_ep(struct snd_soc_dapm_widget * widget,struct list_head * list,bool (* custom_stop_condition)(struct snd_soc_dapm_widget * i,enum snd_soc_dapm_direction))1256*4882a593Smuzhiyun static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
1257*4882a593Smuzhiyun 	struct list_head *list,
1258*4882a593Smuzhiyun 	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1259*4882a593Smuzhiyun 				      enum snd_soc_dapm_direction))
1260*4882a593Smuzhiyun {
1261*4882a593Smuzhiyun 	return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
1262*4882a593Smuzhiyun 			is_connected_output_ep, custom_stop_condition);
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun /*
1266*4882a593Smuzhiyun  * Recursively check for a completed path to an active or physically connected
1267*4882a593Smuzhiyun  * input widget. Returns number of complete paths.
1268*4882a593Smuzhiyun  *
1269*4882a593Smuzhiyun  * Optionally, can be supplied with a function acting as a stopping condition.
1270*4882a593Smuzhiyun  * This function takes the dapm widget currently being examined and the walk
1271*4882a593Smuzhiyun  * direction as an arguments, it should return true if the walk should be
1272*4882a593Smuzhiyun  * stopped and false otherwise.
1273*4882a593Smuzhiyun  */
is_connected_input_ep(struct snd_soc_dapm_widget * widget,struct list_head * list,bool (* custom_stop_condition)(struct snd_soc_dapm_widget * i,enum snd_soc_dapm_direction))1274*4882a593Smuzhiyun static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
1275*4882a593Smuzhiyun 	struct list_head *list,
1276*4882a593Smuzhiyun 	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1277*4882a593Smuzhiyun 				      enum snd_soc_dapm_direction))
1278*4882a593Smuzhiyun {
1279*4882a593Smuzhiyun 	return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
1280*4882a593Smuzhiyun 			is_connected_input_ep, custom_stop_condition);
1281*4882a593Smuzhiyun }
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun /**
1284*4882a593Smuzhiyun  * snd_soc_dapm_dai_get_connected_widgets - query audio path and it's widgets.
1285*4882a593Smuzhiyun  * @dai: the soc DAI.
1286*4882a593Smuzhiyun  * @stream: stream direction.
1287*4882a593Smuzhiyun  * @list: list of active widgets for this stream.
1288*4882a593Smuzhiyun  * @custom_stop_condition: (optional) a function meant to stop the widget graph
1289*4882a593Smuzhiyun  *                         walk based on custom logic.
1290*4882a593Smuzhiyun  *
1291*4882a593Smuzhiyun  * Queries DAPM graph as to whether a valid audio stream path exists for
1292*4882a593Smuzhiyun  * the initial stream specified by name. This takes into account
1293*4882a593Smuzhiyun  * current mixer and mux kcontrol settings. Creates list of valid widgets.
1294*4882a593Smuzhiyun  *
1295*4882a593Smuzhiyun  * Optionally, can be supplied with a function acting as a stopping condition.
1296*4882a593Smuzhiyun  * This function takes the dapm widget currently being examined and the walk
1297*4882a593Smuzhiyun  * direction as an arguments, it should return true if the walk should be
1298*4882a593Smuzhiyun  * stopped and false otherwise.
1299*4882a593Smuzhiyun  *
1300*4882a593Smuzhiyun  * Returns the number of valid paths or negative error.
1301*4882a593Smuzhiyun  */
snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai * dai,int stream,struct snd_soc_dapm_widget_list ** list,bool (* custom_stop_condition)(struct snd_soc_dapm_widget *,enum snd_soc_dapm_direction))1302*4882a593Smuzhiyun int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1303*4882a593Smuzhiyun 	struct snd_soc_dapm_widget_list **list,
1304*4882a593Smuzhiyun 	bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1305*4882a593Smuzhiyun 				      enum snd_soc_dapm_direction))
1306*4882a593Smuzhiyun {
1307*4882a593Smuzhiyun 	struct snd_soc_card *card = dai->component->card;
1308*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
1309*4882a593Smuzhiyun 	LIST_HEAD(widgets);
1310*4882a593Smuzhiyun 	int paths;
1311*4882a593Smuzhiyun 	int ret;
1312*4882a593Smuzhiyun 
1313*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1316*4882a593Smuzhiyun 		w = dai->playback_widget;
1317*4882a593Smuzhiyun 		invalidate_paths_ep(w, SND_SOC_DAPM_DIR_OUT);
1318*4882a593Smuzhiyun 		paths = is_connected_output_ep(w, &widgets,
1319*4882a593Smuzhiyun 				custom_stop_condition);
1320*4882a593Smuzhiyun 	} else {
1321*4882a593Smuzhiyun 		w = dai->capture_widget;
1322*4882a593Smuzhiyun 		invalidate_paths_ep(w, SND_SOC_DAPM_DIR_IN);
1323*4882a593Smuzhiyun 		paths = is_connected_input_ep(w, &widgets,
1324*4882a593Smuzhiyun 				custom_stop_condition);
1325*4882a593Smuzhiyun 	}
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	/* Drop starting point */
1328*4882a593Smuzhiyun 	list_del(widgets.next);
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	ret = dapm_widget_list_create(list, &widgets);
1331*4882a593Smuzhiyun 	if (ret)
1332*4882a593Smuzhiyun 		paths = ret;
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	trace_snd_soc_dapm_connected(paths, stream);
1335*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	return paths;
1338*4882a593Smuzhiyun }
1339*4882a593Smuzhiyun 
snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list ** list)1340*4882a593Smuzhiyun void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list)
1341*4882a593Smuzhiyun {
1342*4882a593Smuzhiyun 	dapm_widget_list_free(list);
1343*4882a593Smuzhiyun }
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun /*
1346*4882a593Smuzhiyun  * Handler for regulator supply widget.
1347*4882a593Smuzhiyun  */
dapm_regulator_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)1348*4882a593Smuzhiyun int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1349*4882a593Smuzhiyun 		   struct snd_kcontrol *kcontrol, int event)
1350*4882a593Smuzhiyun {
1351*4882a593Smuzhiyun 	int ret;
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	soc_dapm_async_complete(w->dapm);
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun 	if (SND_SOC_DAPM_EVENT_ON(event)) {
1356*4882a593Smuzhiyun 		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
1357*4882a593Smuzhiyun 			ret = regulator_allow_bypass(w->regulator, false);
1358*4882a593Smuzhiyun 			if (ret != 0)
1359*4882a593Smuzhiyun 				dev_warn(w->dapm->dev,
1360*4882a593Smuzhiyun 					 "ASoC: Failed to unbypass %s: %d\n",
1361*4882a593Smuzhiyun 					 w->name, ret);
1362*4882a593Smuzhiyun 		}
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 		return regulator_enable(w->regulator);
1365*4882a593Smuzhiyun 	} else {
1366*4882a593Smuzhiyun 		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
1367*4882a593Smuzhiyun 			ret = regulator_allow_bypass(w->regulator, true);
1368*4882a593Smuzhiyun 			if (ret != 0)
1369*4882a593Smuzhiyun 				dev_warn(w->dapm->dev,
1370*4882a593Smuzhiyun 					 "ASoC: Failed to bypass %s: %d\n",
1371*4882a593Smuzhiyun 					 w->name, ret);
1372*4882a593Smuzhiyun 		}
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 		return regulator_disable_deferred(w->regulator, w->shift);
1375*4882a593Smuzhiyun 	}
1376*4882a593Smuzhiyun }
1377*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dapm_regulator_event);
1378*4882a593Smuzhiyun 
1379*4882a593Smuzhiyun /*
1380*4882a593Smuzhiyun  * Handler for pinctrl widget.
1381*4882a593Smuzhiyun  */
dapm_pinctrl_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)1382*4882a593Smuzhiyun int dapm_pinctrl_event(struct snd_soc_dapm_widget *w,
1383*4882a593Smuzhiyun 		       struct snd_kcontrol *kcontrol, int event)
1384*4882a593Smuzhiyun {
1385*4882a593Smuzhiyun 	struct snd_soc_dapm_pinctrl_priv *priv = w->priv;
1386*4882a593Smuzhiyun 	struct pinctrl *p = w->pinctrl;
1387*4882a593Smuzhiyun 	struct pinctrl_state *s;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	if (!p || !priv)
1390*4882a593Smuzhiyun 		return -EIO;
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 	if (SND_SOC_DAPM_EVENT_ON(event))
1393*4882a593Smuzhiyun 		s = pinctrl_lookup_state(p, priv->active_state);
1394*4882a593Smuzhiyun 	else
1395*4882a593Smuzhiyun 		s = pinctrl_lookup_state(p, priv->sleep_state);
1396*4882a593Smuzhiyun 
1397*4882a593Smuzhiyun 	if (IS_ERR(s))
1398*4882a593Smuzhiyun 		return PTR_ERR(s);
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	return pinctrl_select_state(p, s);
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dapm_pinctrl_event);
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun /*
1405*4882a593Smuzhiyun  * Handler for clock supply widget.
1406*4882a593Smuzhiyun  */
dapm_clock_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)1407*4882a593Smuzhiyun int dapm_clock_event(struct snd_soc_dapm_widget *w,
1408*4882a593Smuzhiyun 		   struct snd_kcontrol *kcontrol, int event)
1409*4882a593Smuzhiyun {
1410*4882a593Smuzhiyun 	if (!w->clk)
1411*4882a593Smuzhiyun 		return -EIO;
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	soc_dapm_async_complete(w->dapm);
1414*4882a593Smuzhiyun 
1415*4882a593Smuzhiyun 	if (SND_SOC_DAPM_EVENT_ON(event)) {
1416*4882a593Smuzhiyun 		return clk_prepare_enable(w->clk);
1417*4882a593Smuzhiyun 	} else {
1418*4882a593Smuzhiyun 		clk_disable_unprepare(w->clk);
1419*4882a593Smuzhiyun 		return 0;
1420*4882a593Smuzhiyun 	}
1421*4882a593Smuzhiyun 
1422*4882a593Smuzhiyun 	return 0;
1423*4882a593Smuzhiyun }
1424*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(dapm_clock_event);
1425*4882a593Smuzhiyun 
dapm_widget_power_check(struct snd_soc_dapm_widget * w)1426*4882a593Smuzhiyun static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1427*4882a593Smuzhiyun {
1428*4882a593Smuzhiyun 	if (w->power_checked)
1429*4882a593Smuzhiyun 		return w->new_power;
1430*4882a593Smuzhiyun 
1431*4882a593Smuzhiyun 	if (w->force)
1432*4882a593Smuzhiyun 		w->new_power = 1;
1433*4882a593Smuzhiyun 	else
1434*4882a593Smuzhiyun 		w->new_power = w->power_check(w);
1435*4882a593Smuzhiyun 
1436*4882a593Smuzhiyun 	w->power_checked = true;
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 	return w->new_power;
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun /* Generic check to see if a widget should be powered. */
dapm_generic_check_power(struct snd_soc_dapm_widget * w)1442*4882a593Smuzhiyun static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1443*4882a593Smuzhiyun {
1444*4882a593Smuzhiyun 	int in, out;
1445*4882a593Smuzhiyun 
1446*4882a593Smuzhiyun 	DAPM_UPDATE_STAT(w, power_checks);
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	in = is_connected_input_ep(w, NULL, NULL);
1449*4882a593Smuzhiyun 	out = is_connected_output_ep(w, NULL, NULL);
1450*4882a593Smuzhiyun 	return out != 0 && in != 0;
1451*4882a593Smuzhiyun }
1452*4882a593Smuzhiyun 
1453*4882a593Smuzhiyun /* Check to see if a power supply is needed */
dapm_supply_check_power(struct snd_soc_dapm_widget * w)1454*4882a593Smuzhiyun static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1455*4882a593Smuzhiyun {
1456*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	DAPM_UPDATE_STAT(w, power_checks);
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	/* Check if one of our outputs is connected */
1461*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_sink_path(w, path) {
1462*4882a593Smuzhiyun 		DAPM_UPDATE_STAT(w, neighbour_checks);
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 		if (path->weak)
1465*4882a593Smuzhiyun 			continue;
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun 		if (path->connected &&
1468*4882a593Smuzhiyun 		    !path->connected(path->source, path->sink))
1469*4882a593Smuzhiyun 			continue;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 		if (dapm_widget_power_check(path->sink))
1472*4882a593Smuzhiyun 			return 1;
1473*4882a593Smuzhiyun 	}
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	return 0;
1476*4882a593Smuzhiyun }
1477*4882a593Smuzhiyun 
dapm_always_on_check_power(struct snd_soc_dapm_widget * w)1478*4882a593Smuzhiyun static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1479*4882a593Smuzhiyun {
1480*4882a593Smuzhiyun 	return w->connected;
1481*4882a593Smuzhiyun }
1482*4882a593Smuzhiyun 
dapm_seq_compare(struct snd_soc_dapm_widget * a,struct snd_soc_dapm_widget * b,bool power_up)1483*4882a593Smuzhiyun static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1484*4882a593Smuzhiyun 			    struct snd_soc_dapm_widget *b,
1485*4882a593Smuzhiyun 			    bool power_up)
1486*4882a593Smuzhiyun {
1487*4882a593Smuzhiyun 	int *sort;
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun 	BUILD_BUG_ON(ARRAY_SIZE(dapm_up_seq) != SND_SOC_DAPM_TYPE_COUNT);
1490*4882a593Smuzhiyun 	BUILD_BUG_ON(ARRAY_SIZE(dapm_down_seq) != SND_SOC_DAPM_TYPE_COUNT);
1491*4882a593Smuzhiyun 
1492*4882a593Smuzhiyun 	if (power_up)
1493*4882a593Smuzhiyun 		sort = dapm_up_seq;
1494*4882a593Smuzhiyun 	else
1495*4882a593Smuzhiyun 		sort = dapm_down_seq;
1496*4882a593Smuzhiyun 
1497*4882a593Smuzhiyun 	WARN_ONCE(sort[a->id] == 0, "offset a->id %d not initialized\n", a->id);
1498*4882a593Smuzhiyun 	WARN_ONCE(sort[b->id] == 0, "offset b->id %d not initialized\n", b->id);
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun 	if (sort[a->id] != sort[b->id])
1501*4882a593Smuzhiyun 		return sort[a->id] - sort[b->id];
1502*4882a593Smuzhiyun 	if (a->subseq != b->subseq) {
1503*4882a593Smuzhiyun 		if (power_up)
1504*4882a593Smuzhiyun 			return a->subseq - b->subseq;
1505*4882a593Smuzhiyun 		else
1506*4882a593Smuzhiyun 			return b->subseq - a->subseq;
1507*4882a593Smuzhiyun 	}
1508*4882a593Smuzhiyun 	if (a->reg != b->reg)
1509*4882a593Smuzhiyun 		return a->reg - b->reg;
1510*4882a593Smuzhiyun 	if (a->dapm != b->dapm)
1511*4882a593Smuzhiyun 		return (unsigned long)a->dapm - (unsigned long)b->dapm;
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	return 0;
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun /* Insert a widget in order into a DAPM power sequence. */
dapm_seq_insert(struct snd_soc_dapm_widget * new_widget,struct list_head * list,bool power_up)1517*4882a593Smuzhiyun static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1518*4882a593Smuzhiyun 			    struct list_head *list,
1519*4882a593Smuzhiyun 			    bool power_up)
1520*4882a593Smuzhiyun {
1521*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	list_for_each_entry(w, list, power_list)
1524*4882a593Smuzhiyun 		if (dapm_seq_compare(new_widget, w, power_up) < 0) {
1525*4882a593Smuzhiyun 			list_add_tail(&new_widget->power_list, &w->power_list);
1526*4882a593Smuzhiyun 			return;
1527*4882a593Smuzhiyun 		}
1528*4882a593Smuzhiyun 
1529*4882a593Smuzhiyun 	list_add_tail(&new_widget->power_list, list);
1530*4882a593Smuzhiyun }
1531*4882a593Smuzhiyun 
dapm_seq_check_event(struct snd_soc_card * card,struct snd_soc_dapm_widget * w,int event)1532*4882a593Smuzhiyun static void dapm_seq_check_event(struct snd_soc_card *card,
1533*4882a593Smuzhiyun 				 struct snd_soc_dapm_widget *w, int event)
1534*4882a593Smuzhiyun {
1535*4882a593Smuzhiyun 	const char *ev_name;
1536*4882a593Smuzhiyun 	int power, ret;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	switch (event) {
1539*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMU:
1540*4882a593Smuzhiyun 		ev_name = "PRE_PMU";
1541*4882a593Smuzhiyun 		power = 1;
1542*4882a593Smuzhiyun 		break;
1543*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
1544*4882a593Smuzhiyun 		ev_name = "POST_PMU";
1545*4882a593Smuzhiyun 		power = 1;
1546*4882a593Smuzhiyun 		break;
1547*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
1548*4882a593Smuzhiyun 		ev_name = "PRE_PMD";
1549*4882a593Smuzhiyun 		power = 0;
1550*4882a593Smuzhiyun 		break;
1551*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMD:
1552*4882a593Smuzhiyun 		ev_name = "POST_PMD";
1553*4882a593Smuzhiyun 		power = 0;
1554*4882a593Smuzhiyun 		break;
1555*4882a593Smuzhiyun 	case SND_SOC_DAPM_WILL_PMU:
1556*4882a593Smuzhiyun 		ev_name = "WILL_PMU";
1557*4882a593Smuzhiyun 		power = 1;
1558*4882a593Smuzhiyun 		break;
1559*4882a593Smuzhiyun 	case SND_SOC_DAPM_WILL_PMD:
1560*4882a593Smuzhiyun 		ev_name = "WILL_PMD";
1561*4882a593Smuzhiyun 		power = 0;
1562*4882a593Smuzhiyun 		break;
1563*4882a593Smuzhiyun 	default:
1564*4882a593Smuzhiyun 		WARN(1, "Unknown event %d\n", event);
1565*4882a593Smuzhiyun 		return;
1566*4882a593Smuzhiyun 	}
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 	if (w->new_power != power)
1569*4882a593Smuzhiyun 		return;
1570*4882a593Smuzhiyun 
1571*4882a593Smuzhiyun 	if (w->event && (w->event_flags & event)) {
1572*4882a593Smuzhiyun 		pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
1573*4882a593Smuzhiyun 			w->name, ev_name);
1574*4882a593Smuzhiyun 		soc_dapm_async_complete(w->dapm);
1575*4882a593Smuzhiyun 		trace_snd_soc_dapm_widget_event_start(w, event);
1576*4882a593Smuzhiyun 		ret = w->event(w, NULL, event);
1577*4882a593Smuzhiyun 		trace_snd_soc_dapm_widget_event_done(w, event);
1578*4882a593Smuzhiyun 		if (ret < 0)
1579*4882a593Smuzhiyun 			dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
1580*4882a593Smuzhiyun 			       ev_name, w->name, ret);
1581*4882a593Smuzhiyun 	}
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun /* Apply the coalesced changes from a DAPM sequence */
dapm_seq_run_coalesced(struct snd_soc_card * card,struct list_head * pending)1585*4882a593Smuzhiyun static void dapm_seq_run_coalesced(struct snd_soc_card *card,
1586*4882a593Smuzhiyun 				   struct list_head *pending)
1587*4882a593Smuzhiyun {
1588*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm;
1589*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
1590*4882a593Smuzhiyun 	int reg;
1591*4882a593Smuzhiyun 	unsigned int value = 0;
1592*4882a593Smuzhiyun 	unsigned int mask = 0;
1593*4882a593Smuzhiyun 
1594*4882a593Smuzhiyun 	w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1595*4882a593Smuzhiyun 	reg = w->reg;
1596*4882a593Smuzhiyun 	dapm = w->dapm;
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun 	list_for_each_entry(w, pending, power_list) {
1599*4882a593Smuzhiyun 		WARN_ON(reg != w->reg || dapm != w->dapm);
1600*4882a593Smuzhiyun 		w->power = w->new_power;
1601*4882a593Smuzhiyun 
1602*4882a593Smuzhiyun 		mask |= w->mask << w->shift;
1603*4882a593Smuzhiyun 		if (w->power)
1604*4882a593Smuzhiyun 			value |= w->on_val << w->shift;
1605*4882a593Smuzhiyun 		else
1606*4882a593Smuzhiyun 			value |= w->off_val << w->shift;
1607*4882a593Smuzhiyun 
1608*4882a593Smuzhiyun 		pop_dbg(dapm->dev, card->pop_time,
1609*4882a593Smuzhiyun 			"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1610*4882a593Smuzhiyun 			w->name, reg, value, mask);
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 		/* Check for events */
1613*4882a593Smuzhiyun 		dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1614*4882a593Smuzhiyun 		dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
1615*4882a593Smuzhiyun 	}
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	if (reg >= 0) {
1618*4882a593Smuzhiyun 		/* Any widget will do, they should all be updating the
1619*4882a593Smuzhiyun 		 * same register.
1620*4882a593Smuzhiyun 		 */
1621*4882a593Smuzhiyun 
1622*4882a593Smuzhiyun 		pop_dbg(dapm->dev, card->pop_time,
1623*4882a593Smuzhiyun 			"pop test : Applying 0x%x/0x%x to %x in %dms\n",
1624*4882a593Smuzhiyun 			value, mask, reg, card->pop_time);
1625*4882a593Smuzhiyun 		pop_wait(card->pop_time);
1626*4882a593Smuzhiyun 		soc_dapm_update_bits(dapm, reg, mask, value);
1627*4882a593Smuzhiyun 	}
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 	list_for_each_entry(w, pending, power_list) {
1630*4882a593Smuzhiyun 		dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1631*4882a593Smuzhiyun 		dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
1632*4882a593Smuzhiyun 	}
1633*4882a593Smuzhiyun }
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun /* Apply a DAPM power sequence.
1636*4882a593Smuzhiyun  *
1637*4882a593Smuzhiyun  * We walk over a pre-sorted list of widgets to apply power to.  In
1638*4882a593Smuzhiyun  * order to minimise the number of writes to the device required
1639*4882a593Smuzhiyun  * multiple widgets will be updated in a single write where possible.
1640*4882a593Smuzhiyun  * Currently anything that requires more than a single write is not
1641*4882a593Smuzhiyun  * handled.
1642*4882a593Smuzhiyun  */
dapm_seq_run(struct snd_soc_card * card,struct list_head * list,int event,bool power_up)1643*4882a593Smuzhiyun static void dapm_seq_run(struct snd_soc_card *card,
1644*4882a593Smuzhiyun 	struct list_head *list, int event, bool power_up)
1645*4882a593Smuzhiyun {
1646*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w, *n;
1647*4882a593Smuzhiyun 	struct snd_soc_dapm_context *d;
1648*4882a593Smuzhiyun 	LIST_HEAD(pending);
1649*4882a593Smuzhiyun 	int cur_sort = -1;
1650*4882a593Smuzhiyun 	int cur_subseq = -1;
1651*4882a593Smuzhiyun 	int cur_reg = SND_SOC_NOPM;
1652*4882a593Smuzhiyun 	struct snd_soc_dapm_context *cur_dapm = NULL;
1653*4882a593Smuzhiyun 	int ret, i;
1654*4882a593Smuzhiyun 	int *sort;
1655*4882a593Smuzhiyun 
1656*4882a593Smuzhiyun 	if (power_up)
1657*4882a593Smuzhiyun 		sort = dapm_up_seq;
1658*4882a593Smuzhiyun 	else
1659*4882a593Smuzhiyun 		sort = dapm_down_seq;
1660*4882a593Smuzhiyun 
1661*4882a593Smuzhiyun 	list_for_each_entry_safe(w, n, list, power_list) {
1662*4882a593Smuzhiyun 		ret = 0;
1663*4882a593Smuzhiyun 
1664*4882a593Smuzhiyun 		/* Do we need to apply any queued changes? */
1665*4882a593Smuzhiyun 		if (sort[w->id] != cur_sort || w->reg != cur_reg ||
1666*4882a593Smuzhiyun 		    w->dapm != cur_dapm || w->subseq != cur_subseq) {
1667*4882a593Smuzhiyun 			if (!list_empty(&pending))
1668*4882a593Smuzhiyun 				dapm_seq_run_coalesced(card, &pending);
1669*4882a593Smuzhiyun 
1670*4882a593Smuzhiyun 			if (cur_dapm && cur_dapm->component) {
1671*4882a593Smuzhiyun 				for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1672*4882a593Smuzhiyun 					if (sort[i] == cur_sort)
1673*4882a593Smuzhiyun 						snd_soc_component_seq_notifier(
1674*4882a593Smuzhiyun 							cur_dapm->component,
1675*4882a593Smuzhiyun 							i, cur_subseq);
1676*4882a593Smuzhiyun 			}
1677*4882a593Smuzhiyun 
1678*4882a593Smuzhiyun 			if (cur_dapm && w->dapm != cur_dapm)
1679*4882a593Smuzhiyun 				soc_dapm_async_complete(cur_dapm);
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 			INIT_LIST_HEAD(&pending);
1682*4882a593Smuzhiyun 			cur_sort = -1;
1683*4882a593Smuzhiyun 			cur_subseq = INT_MIN;
1684*4882a593Smuzhiyun 			cur_reg = SND_SOC_NOPM;
1685*4882a593Smuzhiyun 			cur_dapm = NULL;
1686*4882a593Smuzhiyun 		}
1687*4882a593Smuzhiyun 
1688*4882a593Smuzhiyun 		switch (w->id) {
1689*4882a593Smuzhiyun 		case snd_soc_dapm_pre:
1690*4882a593Smuzhiyun 			if (!w->event)
1691*4882a593Smuzhiyun 				continue;
1692*4882a593Smuzhiyun 
1693*4882a593Smuzhiyun 			if (event == SND_SOC_DAPM_STREAM_START)
1694*4882a593Smuzhiyun 				ret = w->event(w,
1695*4882a593Smuzhiyun 					       NULL, SND_SOC_DAPM_PRE_PMU);
1696*4882a593Smuzhiyun 			else if (event == SND_SOC_DAPM_STREAM_STOP)
1697*4882a593Smuzhiyun 				ret = w->event(w,
1698*4882a593Smuzhiyun 					       NULL, SND_SOC_DAPM_PRE_PMD);
1699*4882a593Smuzhiyun 			break;
1700*4882a593Smuzhiyun 
1701*4882a593Smuzhiyun 		case snd_soc_dapm_post:
1702*4882a593Smuzhiyun 			if (!w->event)
1703*4882a593Smuzhiyun 				continue;
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun 			if (event == SND_SOC_DAPM_STREAM_START)
1706*4882a593Smuzhiyun 				ret = w->event(w,
1707*4882a593Smuzhiyun 					       NULL, SND_SOC_DAPM_POST_PMU);
1708*4882a593Smuzhiyun 			else if (event == SND_SOC_DAPM_STREAM_STOP)
1709*4882a593Smuzhiyun 				ret = w->event(w,
1710*4882a593Smuzhiyun 					       NULL, SND_SOC_DAPM_POST_PMD);
1711*4882a593Smuzhiyun 			break;
1712*4882a593Smuzhiyun 
1713*4882a593Smuzhiyun 		default:
1714*4882a593Smuzhiyun 			/* Queue it up for application */
1715*4882a593Smuzhiyun 			cur_sort = sort[w->id];
1716*4882a593Smuzhiyun 			cur_subseq = w->subseq;
1717*4882a593Smuzhiyun 			cur_reg = w->reg;
1718*4882a593Smuzhiyun 			cur_dapm = w->dapm;
1719*4882a593Smuzhiyun 			list_move(&w->power_list, &pending);
1720*4882a593Smuzhiyun 			break;
1721*4882a593Smuzhiyun 		}
1722*4882a593Smuzhiyun 
1723*4882a593Smuzhiyun 		if (ret < 0)
1724*4882a593Smuzhiyun 			dev_err(w->dapm->dev,
1725*4882a593Smuzhiyun 				"ASoC: Failed to apply widget power: %d\n", ret);
1726*4882a593Smuzhiyun 	}
1727*4882a593Smuzhiyun 
1728*4882a593Smuzhiyun 	if (!list_empty(&pending))
1729*4882a593Smuzhiyun 		dapm_seq_run_coalesced(card, &pending);
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun 	if (cur_dapm && cur_dapm->component) {
1732*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1733*4882a593Smuzhiyun 			if (sort[i] == cur_sort)
1734*4882a593Smuzhiyun 				snd_soc_component_seq_notifier(
1735*4882a593Smuzhiyun 					cur_dapm->component,
1736*4882a593Smuzhiyun 					i, cur_subseq);
1737*4882a593Smuzhiyun 	}
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	for_each_card_dapms(card, d)
1740*4882a593Smuzhiyun 		soc_dapm_async_complete(d);
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun 
dapm_widget_update(struct snd_soc_card * card)1743*4882a593Smuzhiyun static void dapm_widget_update(struct snd_soc_card *card)
1744*4882a593Smuzhiyun {
1745*4882a593Smuzhiyun 	struct snd_soc_dapm_update *update = card->update;
1746*4882a593Smuzhiyun 	struct snd_soc_dapm_widget_list *wlist;
1747*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = NULL;
1748*4882a593Smuzhiyun 	unsigned int wi;
1749*4882a593Smuzhiyun 	int ret;
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
1752*4882a593Smuzhiyun 		return;
1753*4882a593Smuzhiyun 
1754*4882a593Smuzhiyun 	wlist = dapm_kcontrol_get_wlist(update->kcontrol);
1755*4882a593Smuzhiyun 
1756*4882a593Smuzhiyun 	for_each_dapm_widgets(wlist, wi, w) {
1757*4882a593Smuzhiyun 		if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1758*4882a593Smuzhiyun 			ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1759*4882a593Smuzhiyun 			if (ret != 0)
1760*4882a593Smuzhiyun 				dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
1761*4882a593Smuzhiyun 					   w->name, ret);
1762*4882a593Smuzhiyun 		}
1763*4882a593Smuzhiyun 	}
1764*4882a593Smuzhiyun 
1765*4882a593Smuzhiyun 	if (!w)
1766*4882a593Smuzhiyun 		return;
1767*4882a593Smuzhiyun 
1768*4882a593Smuzhiyun 	ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1769*4882a593Smuzhiyun 		update->val);
1770*4882a593Smuzhiyun 	if (ret < 0)
1771*4882a593Smuzhiyun 		dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
1772*4882a593Smuzhiyun 			w->name, ret);
1773*4882a593Smuzhiyun 
1774*4882a593Smuzhiyun 	if (update->has_second_set) {
1775*4882a593Smuzhiyun 		ret = soc_dapm_update_bits(w->dapm, update->reg2,
1776*4882a593Smuzhiyun 					   update->mask2, update->val2);
1777*4882a593Smuzhiyun 		if (ret < 0)
1778*4882a593Smuzhiyun 			dev_err(w->dapm->dev,
1779*4882a593Smuzhiyun 				"ASoC: %s DAPM update failed: %d\n",
1780*4882a593Smuzhiyun 				w->name, ret);
1781*4882a593Smuzhiyun 	}
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun 	for_each_dapm_widgets(wlist, wi, w) {
1784*4882a593Smuzhiyun 		if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1785*4882a593Smuzhiyun 			ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1786*4882a593Smuzhiyun 			if (ret != 0)
1787*4882a593Smuzhiyun 				dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
1788*4882a593Smuzhiyun 					   w->name, ret);
1789*4882a593Smuzhiyun 		}
1790*4882a593Smuzhiyun 	}
1791*4882a593Smuzhiyun }
1792*4882a593Smuzhiyun 
1793*4882a593Smuzhiyun /* Async callback run prior to DAPM sequences - brings to _PREPARE if
1794*4882a593Smuzhiyun  * they're changing state.
1795*4882a593Smuzhiyun  */
dapm_pre_sequence_async(void * data,async_cookie_t cookie)1796*4882a593Smuzhiyun static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1797*4882a593Smuzhiyun {
1798*4882a593Smuzhiyun 	struct snd_soc_dapm_context *d = data;
1799*4882a593Smuzhiyun 	int ret;
1800*4882a593Smuzhiyun 
1801*4882a593Smuzhiyun 	/* If we're off and we're not supposed to go into STANDBY */
1802*4882a593Smuzhiyun 	if (d->bias_level == SND_SOC_BIAS_OFF &&
1803*4882a593Smuzhiyun 	    d->target_bias_level != SND_SOC_BIAS_OFF) {
1804*4882a593Smuzhiyun 		if (d->dev && cookie)
1805*4882a593Smuzhiyun 			pm_runtime_get_sync(d->dev);
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun 		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1808*4882a593Smuzhiyun 		if (ret != 0)
1809*4882a593Smuzhiyun 			dev_err(d->dev,
1810*4882a593Smuzhiyun 				"ASoC: Failed to turn on bias: %d\n", ret);
1811*4882a593Smuzhiyun 	}
1812*4882a593Smuzhiyun 
1813*4882a593Smuzhiyun 	/* Prepare for a transition to ON or away from ON */
1814*4882a593Smuzhiyun 	if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1815*4882a593Smuzhiyun 	     d->bias_level != SND_SOC_BIAS_ON) ||
1816*4882a593Smuzhiyun 	    (d->target_bias_level != SND_SOC_BIAS_ON &&
1817*4882a593Smuzhiyun 	     d->bias_level == SND_SOC_BIAS_ON)) {
1818*4882a593Smuzhiyun 		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1819*4882a593Smuzhiyun 		if (ret != 0)
1820*4882a593Smuzhiyun 			dev_err(d->dev,
1821*4882a593Smuzhiyun 				"ASoC: Failed to prepare bias: %d\n", ret);
1822*4882a593Smuzhiyun 	}
1823*4882a593Smuzhiyun }
1824*4882a593Smuzhiyun 
1825*4882a593Smuzhiyun /* Async callback run prior to DAPM sequences - brings to their final
1826*4882a593Smuzhiyun  * state.
1827*4882a593Smuzhiyun  */
dapm_post_sequence_async(void * data,async_cookie_t cookie)1828*4882a593Smuzhiyun static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1829*4882a593Smuzhiyun {
1830*4882a593Smuzhiyun 	struct snd_soc_dapm_context *d = data;
1831*4882a593Smuzhiyun 	int ret;
1832*4882a593Smuzhiyun 
1833*4882a593Smuzhiyun 	/* If we just powered the last thing off drop to standby bias */
1834*4882a593Smuzhiyun 	if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1835*4882a593Smuzhiyun 	    (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1836*4882a593Smuzhiyun 	     d->target_bias_level == SND_SOC_BIAS_OFF)) {
1837*4882a593Smuzhiyun 		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1838*4882a593Smuzhiyun 		if (ret != 0)
1839*4882a593Smuzhiyun 			dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
1840*4882a593Smuzhiyun 				ret);
1841*4882a593Smuzhiyun 	}
1842*4882a593Smuzhiyun 
1843*4882a593Smuzhiyun 	/* If we're in standby and can support bias off then do that */
1844*4882a593Smuzhiyun 	if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1845*4882a593Smuzhiyun 	    d->target_bias_level == SND_SOC_BIAS_OFF) {
1846*4882a593Smuzhiyun 		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1847*4882a593Smuzhiyun 		if (ret != 0)
1848*4882a593Smuzhiyun 			dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1849*4882a593Smuzhiyun 				ret);
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun 		if (d->dev && cookie)
1852*4882a593Smuzhiyun 			pm_runtime_put(d->dev);
1853*4882a593Smuzhiyun 	}
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun 	/* If we just powered up then move to active bias */
1856*4882a593Smuzhiyun 	if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1857*4882a593Smuzhiyun 	    d->target_bias_level == SND_SOC_BIAS_ON) {
1858*4882a593Smuzhiyun 		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1859*4882a593Smuzhiyun 		if (ret != 0)
1860*4882a593Smuzhiyun 			dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
1861*4882a593Smuzhiyun 				ret);
1862*4882a593Smuzhiyun 	}
1863*4882a593Smuzhiyun }
1864*4882a593Smuzhiyun 
dapm_widget_set_peer_power(struct snd_soc_dapm_widget * peer,bool power,bool connect)1865*4882a593Smuzhiyun static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1866*4882a593Smuzhiyun 				       bool power, bool connect)
1867*4882a593Smuzhiyun {
1868*4882a593Smuzhiyun 	/* If a connection is being made or broken then that update
1869*4882a593Smuzhiyun 	 * will have marked the peer dirty, otherwise the widgets are
1870*4882a593Smuzhiyun 	 * not connected and this update has no impact. */
1871*4882a593Smuzhiyun 	if (!connect)
1872*4882a593Smuzhiyun 		return;
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	/* If the peer is already in the state we're moving to then we
1875*4882a593Smuzhiyun 	 * won't have an impact on it. */
1876*4882a593Smuzhiyun 	if (power != peer->power)
1877*4882a593Smuzhiyun 		dapm_mark_dirty(peer, "peer state change");
1878*4882a593Smuzhiyun }
1879*4882a593Smuzhiyun 
dapm_widget_set_power(struct snd_soc_dapm_widget * w,bool power,struct list_head * up_list,struct list_head * down_list)1880*4882a593Smuzhiyun static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1881*4882a593Smuzhiyun 				  struct list_head *up_list,
1882*4882a593Smuzhiyun 				  struct list_head *down_list)
1883*4882a593Smuzhiyun {
1884*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
1885*4882a593Smuzhiyun 
1886*4882a593Smuzhiyun 	if (w->power == power)
1887*4882a593Smuzhiyun 		return;
1888*4882a593Smuzhiyun 
1889*4882a593Smuzhiyun 	trace_snd_soc_dapm_widget_power(w, power);
1890*4882a593Smuzhiyun 
1891*4882a593Smuzhiyun 	/* If we changed our power state perhaps our neigbours changed
1892*4882a593Smuzhiyun 	 * also.
1893*4882a593Smuzhiyun 	 */
1894*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_source_path(w, path)
1895*4882a593Smuzhiyun 		dapm_widget_set_peer_power(path->source, power, path->connect);
1896*4882a593Smuzhiyun 
1897*4882a593Smuzhiyun 	/* Supplies can't affect their outputs, only their inputs */
1898*4882a593Smuzhiyun 	if (!w->is_supply) {
1899*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_sink_path(w, path)
1900*4882a593Smuzhiyun 			dapm_widget_set_peer_power(path->sink, power,
1901*4882a593Smuzhiyun 						   path->connect);
1902*4882a593Smuzhiyun 	}
1903*4882a593Smuzhiyun 
1904*4882a593Smuzhiyun 	if (power)
1905*4882a593Smuzhiyun 		dapm_seq_insert(w, up_list, true);
1906*4882a593Smuzhiyun 	else
1907*4882a593Smuzhiyun 		dapm_seq_insert(w, down_list, false);
1908*4882a593Smuzhiyun }
1909*4882a593Smuzhiyun 
dapm_power_one_widget(struct snd_soc_dapm_widget * w,struct list_head * up_list,struct list_head * down_list)1910*4882a593Smuzhiyun static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1911*4882a593Smuzhiyun 				  struct list_head *up_list,
1912*4882a593Smuzhiyun 				  struct list_head *down_list)
1913*4882a593Smuzhiyun {
1914*4882a593Smuzhiyun 	int power;
1915*4882a593Smuzhiyun 
1916*4882a593Smuzhiyun 	switch (w->id) {
1917*4882a593Smuzhiyun 	case snd_soc_dapm_pre:
1918*4882a593Smuzhiyun 		dapm_seq_insert(w, down_list, false);
1919*4882a593Smuzhiyun 		break;
1920*4882a593Smuzhiyun 	case snd_soc_dapm_post:
1921*4882a593Smuzhiyun 		dapm_seq_insert(w, up_list, true);
1922*4882a593Smuzhiyun 		break;
1923*4882a593Smuzhiyun 
1924*4882a593Smuzhiyun 	default:
1925*4882a593Smuzhiyun 		power = dapm_widget_power_check(w);
1926*4882a593Smuzhiyun 
1927*4882a593Smuzhiyun 		dapm_widget_set_power(w, power, up_list, down_list);
1928*4882a593Smuzhiyun 		break;
1929*4882a593Smuzhiyun 	}
1930*4882a593Smuzhiyun }
1931*4882a593Smuzhiyun 
dapm_idle_bias_off(struct snd_soc_dapm_context * dapm)1932*4882a593Smuzhiyun static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1933*4882a593Smuzhiyun {
1934*4882a593Smuzhiyun 	if (dapm->idle_bias_off)
1935*4882a593Smuzhiyun 		return true;
1936*4882a593Smuzhiyun 
1937*4882a593Smuzhiyun 	switch (snd_power_get_state(dapm->card->snd_card)) {
1938*4882a593Smuzhiyun 	case SNDRV_CTL_POWER_D3hot:
1939*4882a593Smuzhiyun 	case SNDRV_CTL_POWER_D3cold:
1940*4882a593Smuzhiyun 		return dapm->suspend_bias_off;
1941*4882a593Smuzhiyun 	default:
1942*4882a593Smuzhiyun 		break;
1943*4882a593Smuzhiyun 	}
1944*4882a593Smuzhiyun 
1945*4882a593Smuzhiyun 	return false;
1946*4882a593Smuzhiyun }
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun /*
1949*4882a593Smuzhiyun  * Scan each dapm widget for complete audio path.
1950*4882a593Smuzhiyun  * A complete path is a route that has valid endpoints i.e.:-
1951*4882a593Smuzhiyun  *
1952*4882a593Smuzhiyun  *  o DAC to output pin.
1953*4882a593Smuzhiyun  *  o Input pin to ADC.
1954*4882a593Smuzhiyun  *  o Input pin to Output pin (bypass, sidetone)
1955*4882a593Smuzhiyun  *  o DAC to ADC (loopback).
1956*4882a593Smuzhiyun  */
dapm_power_widgets(struct snd_soc_card * card,int event)1957*4882a593Smuzhiyun static int dapm_power_widgets(struct snd_soc_card *card, int event)
1958*4882a593Smuzhiyun {
1959*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
1960*4882a593Smuzhiyun 	struct snd_soc_dapm_context *d;
1961*4882a593Smuzhiyun 	LIST_HEAD(up_list);
1962*4882a593Smuzhiyun 	LIST_HEAD(down_list);
1963*4882a593Smuzhiyun 	ASYNC_DOMAIN_EXCLUSIVE(async_domain);
1964*4882a593Smuzhiyun 	enum snd_soc_bias_level bias;
1965*4882a593Smuzhiyun 	int ret;
1966*4882a593Smuzhiyun 
1967*4882a593Smuzhiyun 	lockdep_assert_held(&card->dapm_mutex);
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun 	trace_snd_soc_dapm_start(card);
1970*4882a593Smuzhiyun 
1971*4882a593Smuzhiyun 	for_each_card_dapms(card, d) {
1972*4882a593Smuzhiyun 		if (dapm_idle_bias_off(d))
1973*4882a593Smuzhiyun 			d->target_bias_level = SND_SOC_BIAS_OFF;
1974*4882a593Smuzhiyun 		else
1975*4882a593Smuzhiyun 			d->target_bias_level = SND_SOC_BIAS_STANDBY;
1976*4882a593Smuzhiyun 	}
1977*4882a593Smuzhiyun 
1978*4882a593Smuzhiyun 	dapm_reset(card);
1979*4882a593Smuzhiyun 
1980*4882a593Smuzhiyun 	/* Check which widgets we need to power and store them in
1981*4882a593Smuzhiyun 	 * lists indicating if they should be powered up or down.  We
1982*4882a593Smuzhiyun 	 * only check widgets that have been flagged as dirty but note
1983*4882a593Smuzhiyun 	 * that new widgets may be added to the dirty list while we
1984*4882a593Smuzhiyun 	 * iterate.
1985*4882a593Smuzhiyun 	 */
1986*4882a593Smuzhiyun 	list_for_each_entry(w, &card->dapm_dirty, dirty) {
1987*4882a593Smuzhiyun 		dapm_power_one_widget(w, &up_list, &down_list);
1988*4882a593Smuzhiyun 	}
1989*4882a593Smuzhiyun 
1990*4882a593Smuzhiyun 	for_each_card_widgets(card, w) {
1991*4882a593Smuzhiyun 		switch (w->id) {
1992*4882a593Smuzhiyun 		case snd_soc_dapm_pre:
1993*4882a593Smuzhiyun 		case snd_soc_dapm_post:
1994*4882a593Smuzhiyun 			/* These widgets always need to be powered */
1995*4882a593Smuzhiyun 			break;
1996*4882a593Smuzhiyun 		default:
1997*4882a593Smuzhiyun 			list_del_init(&w->dirty);
1998*4882a593Smuzhiyun 			break;
1999*4882a593Smuzhiyun 		}
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun 		if (w->new_power) {
2002*4882a593Smuzhiyun 			d = w->dapm;
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun 			/* Supplies and micbiases only bring the
2005*4882a593Smuzhiyun 			 * context up to STANDBY as unless something
2006*4882a593Smuzhiyun 			 * else is active and passing audio they
2007*4882a593Smuzhiyun 			 * generally don't require full power.  Signal
2008*4882a593Smuzhiyun 			 * generators are virtual pins and have no
2009*4882a593Smuzhiyun 			 * power impact themselves.
2010*4882a593Smuzhiyun 			 */
2011*4882a593Smuzhiyun 			switch (w->id) {
2012*4882a593Smuzhiyun 			case snd_soc_dapm_siggen:
2013*4882a593Smuzhiyun 			case snd_soc_dapm_vmid:
2014*4882a593Smuzhiyun 				break;
2015*4882a593Smuzhiyun 			case snd_soc_dapm_supply:
2016*4882a593Smuzhiyun 			case snd_soc_dapm_regulator_supply:
2017*4882a593Smuzhiyun 			case snd_soc_dapm_pinctrl:
2018*4882a593Smuzhiyun 			case snd_soc_dapm_clock_supply:
2019*4882a593Smuzhiyun 			case snd_soc_dapm_micbias:
2020*4882a593Smuzhiyun 				if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
2021*4882a593Smuzhiyun 					d->target_bias_level = SND_SOC_BIAS_STANDBY;
2022*4882a593Smuzhiyun 				break;
2023*4882a593Smuzhiyun 			default:
2024*4882a593Smuzhiyun 				d->target_bias_level = SND_SOC_BIAS_ON;
2025*4882a593Smuzhiyun 				break;
2026*4882a593Smuzhiyun 			}
2027*4882a593Smuzhiyun 		}
2028*4882a593Smuzhiyun 
2029*4882a593Smuzhiyun 	}
2030*4882a593Smuzhiyun 
2031*4882a593Smuzhiyun 	/* Force all contexts in the card to the same bias state if
2032*4882a593Smuzhiyun 	 * they're not ground referenced.
2033*4882a593Smuzhiyun 	 */
2034*4882a593Smuzhiyun 	bias = SND_SOC_BIAS_OFF;
2035*4882a593Smuzhiyun 	for_each_card_dapms(card, d)
2036*4882a593Smuzhiyun 		if (d->target_bias_level > bias)
2037*4882a593Smuzhiyun 			bias = d->target_bias_level;
2038*4882a593Smuzhiyun 	for_each_card_dapms(card, d)
2039*4882a593Smuzhiyun 		if (!dapm_idle_bias_off(d))
2040*4882a593Smuzhiyun 			d->target_bias_level = bias;
2041*4882a593Smuzhiyun 
2042*4882a593Smuzhiyun 	trace_snd_soc_dapm_walk_done(card);
2043*4882a593Smuzhiyun 
2044*4882a593Smuzhiyun 	/* Run card bias changes at first */
2045*4882a593Smuzhiyun 	dapm_pre_sequence_async(&card->dapm, 0);
2046*4882a593Smuzhiyun 	/* Run other bias changes in parallel */
2047*4882a593Smuzhiyun 	for_each_card_dapms(card, d) {
2048*4882a593Smuzhiyun 		if (d != &card->dapm && d->bias_level != d->target_bias_level)
2049*4882a593Smuzhiyun 			async_schedule_domain(dapm_pre_sequence_async, d,
2050*4882a593Smuzhiyun 						&async_domain);
2051*4882a593Smuzhiyun 	}
2052*4882a593Smuzhiyun 	async_synchronize_full_domain(&async_domain);
2053*4882a593Smuzhiyun 
2054*4882a593Smuzhiyun 	list_for_each_entry(w, &down_list, power_list) {
2055*4882a593Smuzhiyun 		dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
2056*4882a593Smuzhiyun 	}
2057*4882a593Smuzhiyun 
2058*4882a593Smuzhiyun 	list_for_each_entry(w, &up_list, power_list) {
2059*4882a593Smuzhiyun 		dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
2060*4882a593Smuzhiyun 	}
2061*4882a593Smuzhiyun 
2062*4882a593Smuzhiyun 	/* Power down widgets first; try to avoid amplifying pops. */
2063*4882a593Smuzhiyun 	dapm_seq_run(card, &down_list, event, false);
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 	dapm_widget_update(card);
2066*4882a593Smuzhiyun 
2067*4882a593Smuzhiyun 	/* Now power up. */
2068*4882a593Smuzhiyun 	dapm_seq_run(card, &up_list, event, true);
2069*4882a593Smuzhiyun 
2070*4882a593Smuzhiyun 	/* Run all the bias changes in parallel */
2071*4882a593Smuzhiyun 	for_each_card_dapms(card, d) {
2072*4882a593Smuzhiyun 		if (d != &card->dapm && d->bias_level != d->target_bias_level)
2073*4882a593Smuzhiyun 			async_schedule_domain(dapm_post_sequence_async, d,
2074*4882a593Smuzhiyun 						&async_domain);
2075*4882a593Smuzhiyun 	}
2076*4882a593Smuzhiyun 	async_synchronize_full_domain(&async_domain);
2077*4882a593Smuzhiyun 	/* Run card bias changes at last */
2078*4882a593Smuzhiyun 	dapm_post_sequence_async(&card->dapm, 0);
2079*4882a593Smuzhiyun 
2080*4882a593Smuzhiyun 	/* do we need to notify any clients that DAPM event is complete */
2081*4882a593Smuzhiyun 	for_each_card_dapms(card, d) {
2082*4882a593Smuzhiyun 		if (!d->component)
2083*4882a593Smuzhiyun 			continue;
2084*4882a593Smuzhiyun 
2085*4882a593Smuzhiyun 		ret = snd_soc_component_stream_event(d->component, event);
2086*4882a593Smuzhiyun 		if (ret < 0)
2087*4882a593Smuzhiyun 			return ret;
2088*4882a593Smuzhiyun 	}
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun 	pop_dbg(card->dev, card->pop_time,
2091*4882a593Smuzhiyun 		"DAPM sequencing finished, waiting %dms\n", card->pop_time);
2092*4882a593Smuzhiyun 	pop_wait(card->pop_time);
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun 	trace_snd_soc_dapm_done(card);
2095*4882a593Smuzhiyun 
2096*4882a593Smuzhiyun 	return 0;
2097*4882a593Smuzhiyun }
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
dapm_widget_power_read_file(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2100*4882a593Smuzhiyun static ssize_t dapm_widget_power_read_file(struct file *file,
2101*4882a593Smuzhiyun 					   char __user *user_buf,
2102*4882a593Smuzhiyun 					   size_t count, loff_t *ppos)
2103*4882a593Smuzhiyun {
2104*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = file->private_data;
2105*4882a593Smuzhiyun 	struct snd_soc_card *card = w->dapm->card;
2106*4882a593Smuzhiyun 	enum snd_soc_dapm_direction dir, rdir;
2107*4882a593Smuzhiyun 	char *buf;
2108*4882a593Smuzhiyun 	int in, out;
2109*4882a593Smuzhiyun 	ssize_t ret;
2110*4882a593Smuzhiyun 	struct snd_soc_dapm_path *p = NULL;
2111*4882a593Smuzhiyun 
2112*4882a593Smuzhiyun 	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
2113*4882a593Smuzhiyun 	if (!buf)
2114*4882a593Smuzhiyun 		return -ENOMEM;
2115*4882a593Smuzhiyun 
2116*4882a593Smuzhiyun 	mutex_lock(&card->dapm_mutex);
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	/* Supply widgets are not handled by is_connected_{input,output}_ep() */
2119*4882a593Smuzhiyun 	if (w->is_supply) {
2120*4882a593Smuzhiyun 		in = 0;
2121*4882a593Smuzhiyun 		out = 0;
2122*4882a593Smuzhiyun 	} else {
2123*4882a593Smuzhiyun 		in = is_connected_input_ep(w, NULL, NULL);
2124*4882a593Smuzhiyun 		out = is_connected_output_ep(w, NULL, NULL);
2125*4882a593Smuzhiyun 	}
2126*4882a593Smuzhiyun 
2127*4882a593Smuzhiyun 	ret = scnprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
2128*4882a593Smuzhiyun 		       w->name, w->power ? "On" : "Off",
2129*4882a593Smuzhiyun 		       w->force ? " (forced)" : "", in, out);
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun 	if (w->reg >= 0)
2132*4882a593Smuzhiyun 		ret += scnprintf(buf + ret, PAGE_SIZE - ret,
2133*4882a593Smuzhiyun 				" - R%d(0x%x) mask 0x%x",
2134*4882a593Smuzhiyun 				w->reg, w->reg, w->mask << w->shift);
2135*4882a593Smuzhiyun 
2136*4882a593Smuzhiyun 	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
2137*4882a593Smuzhiyun 
2138*4882a593Smuzhiyun 	if (w->sname)
2139*4882a593Smuzhiyun 		ret += scnprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
2140*4882a593Smuzhiyun 				w->sname,
2141*4882a593Smuzhiyun 				w->active ? "active" : "inactive");
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun 	snd_soc_dapm_for_each_direction(dir) {
2144*4882a593Smuzhiyun 		rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
2145*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_path(w, dir, p) {
2146*4882a593Smuzhiyun 			if (p->connected && !p->connected(p->source, p->sink))
2147*4882a593Smuzhiyun 				continue;
2148*4882a593Smuzhiyun 
2149*4882a593Smuzhiyun 			if (!p->connect)
2150*4882a593Smuzhiyun 				continue;
2151*4882a593Smuzhiyun 
2152*4882a593Smuzhiyun 			ret += scnprintf(buf + ret, PAGE_SIZE - ret,
2153*4882a593Smuzhiyun 					" %s  \"%s\" \"%s\"\n",
2154*4882a593Smuzhiyun 					(rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
2155*4882a593Smuzhiyun 					p->name ? p->name : "static",
2156*4882a593Smuzhiyun 					p->node[rdir]->name);
2157*4882a593Smuzhiyun 		}
2158*4882a593Smuzhiyun 	}
2159*4882a593Smuzhiyun 
2160*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
2163*4882a593Smuzhiyun 
2164*4882a593Smuzhiyun 	kfree(buf);
2165*4882a593Smuzhiyun 	return ret;
2166*4882a593Smuzhiyun }
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun static const struct file_operations dapm_widget_power_fops = {
2169*4882a593Smuzhiyun 	.open = simple_open,
2170*4882a593Smuzhiyun 	.read = dapm_widget_power_read_file,
2171*4882a593Smuzhiyun 	.llseek = default_llseek,
2172*4882a593Smuzhiyun };
2173*4882a593Smuzhiyun 
dapm_bias_read_file(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)2174*4882a593Smuzhiyun static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
2175*4882a593Smuzhiyun 				   size_t count, loff_t *ppos)
2176*4882a593Smuzhiyun {
2177*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = file->private_data;
2178*4882a593Smuzhiyun 	char *level;
2179*4882a593Smuzhiyun 
2180*4882a593Smuzhiyun 	switch (dapm->bias_level) {
2181*4882a593Smuzhiyun 	case SND_SOC_BIAS_ON:
2182*4882a593Smuzhiyun 		level = "On\n";
2183*4882a593Smuzhiyun 		break;
2184*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
2185*4882a593Smuzhiyun 		level = "Prepare\n";
2186*4882a593Smuzhiyun 		break;
2187*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
2188*4882a593Smuzhiyun 		level = "Standby\n";
2189*4882a593Smuzhiyun 		break;
2190*4882a593Smuzhiyun 	case SND_SOC_BIAS_OFF:
2191*4882a593Smuzhiyun 		level = "Off\n";
2192*4882a593Smuzhiyun 		break;
2193*4882a593Smuzhiyun 	default:
2194*4882a593Smuzhiyun 		WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
2195*4882a593Smuzhiyun 		level = "Unknown\n";
2196*4882a593Smuzhiyun 		break;
2197*4882a593Smuzhiyun 	}
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun 	return simple_read_from_buffer(user_buf, count, ppos, level,
2200*4882a593Smuzhiyun 				       strlen(level));
2201*4882a593Smuzhiyun }
2202*4882a593Smuzhiyun 
2203*4882a593Smuzhiyun static const struct file_operations dapm_bias_fops = {
2204*4882a593Smuzhiyun 	.open = simple_open,
2205*4882a593Smuzhiyun 	.read = dapm_bias_read_file,
2206*4882a593Smuzhiyun 	.llseek = default_llseek,
2207*4882a593Smuzhiyun };
2208*4882a593Smuzhiyun 
snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context * dapm,struct dentry * parent)2209*4882a593Smuzhiyun void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2210*4882a593Smuzhiyun 	struct dentry *parent)
2211*4882a593Smuzhiyun {
2212*4882a593Smuzhiyun 	if (!parent || IS_ERR(parent))
2213*4882a593Smuzhiyun 		return;
2214*4882a593Smuzhiyun 
2215*4882a593Smuzhiyun 	dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2216*4882a593Smuzhiyun 
2217*4882a593Smuzhiyun 	debugfs_create_file("bias_level", 0444, dapm->debugfs_dapm, dapm,
2218*4882a593Smuzhiyun 			    &dapm_bias_fops);
2219*4882a593Smuzhiyun }
2220*4882a593Smuzhiyun 
dapm_debugfs_add_widget(struct snd_soc_dapm_widget * w)2221*4882a593Smuzhiyun static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2222*4882a593Smuzhiyun {
2223*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = w->dapm;
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 	if (!dapm->debugfs_dapm || !w->name)
2226*4882a593Smuzhiyun 		return;
2227*4882a593Smuzhiyun 
2228*4882a593Smuzhiyun 	debugfs_create_file(w->name, 0444, dapm->debugfs_dapm, w,
2229*4882a593Smuzhiyun 			    &dapm_widget_power_fops);
2230*4882a593Smuzhiyun }
2231*4882a593Smuzhiyun 
dapm_debugfs_cleanup(struct snd_soc_dapm_context * dapm)2232*4882a593Smuzhiyun static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2233*4882a593Smuzhiyun {
2234*4882a593Smuzhiyun 	debugfs_remove_recursive(dapm->debugfs_dapm);
2235*4882a593Smuzhiyun 	dapm->debugfs_dapm = NULL;
2236*4882a593Smuzhiyun }
2237*4882a593Smuzhiyun 
2238*4882a593Smuzhiyun #else
snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context * dapm,struct dentry * parent)2239*4882a593Smuzhiyun void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2240*4882a593Smuzhiyun 	struct dentry *parent)
2241*4882a593Smuzhiyun {
2242*4882a593Smuzhiyun }
2243*4882a593Smuzhiyun 
dapm_debugfs_add_widget(struct snd_soc_dapm_widget * w)2244*4882a593Smuzhiyun static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2245*4882a593Smuzhiyun {
2246*4882a593Smuzhiyun }
2247*4882a593Smuzhiyun 
dapm_debugfs_cleanup(struct snd_soc_dapm_context * dapm)2248*4882a593Smuzhiyun static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2249*4882a593Smuzhiyun {
2250*4882a593Smuzhiyun }
2251*4882a593Smuzhiyun 
2252*4882a593Smuzhiyun #endif
2253*4882a593Smuzhiyun 
2254*4882a593Smuzhiyun /*
2255*4882a593Smuzhiyun  * soc_dapm_connect_path() - Connects or disconnects a path
2256*4882a593Smuzhiyun  * @path: The path to update
2257*4882a593Smuzhiyun  * @connect: The new connect state of the path. True if the path is connected,
2258*4882a593Smuzhiyun  *  false if it is disconnected.
2259*4882a593Smuzhiyun  * @reason: The reason why the path changed (for debugging only)
2260*4882a593Smuzhiyun  */
soc_dapm_connect_path(struct snd_soc_dapm_path * path,bool connect,const char * reason)2261*4882a593Smuzhiyun static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2262*4882a593Smuzhiyun 	bool connect, const char *reason)
2263*4882a593Smuzhiyun {
2264*4882a593Smuzhiyun 	if (path->connect == connect)
2265*4882a593Smuzhiyun 		return;
2266*4882a593Smuzhiyun 
2267*4882a593Smuzhiyun 	path->connect = connect;
2268*4882a593Smuzhiyun 	dapm_mark_dirty(path->source, reason);
2269*4882a593Smuzhiyun 	dapm_mark_dirty(path->sink, reason);
2270*4882a593Smuzhiyun 	dapm_path_invalidate(path);
2271*4882a593Smuzhiyun }
2272*4882a593Smuzhiyun 
2273*4882a593Smuzhiyun /* test and update the power status of a mux widget */
soc_dapm_mux_update_power(struct snd_soc_card * card,struct snd_kcontrol * kcontrol,int mux,struct soc_enum * e)2274*4882a593Smuzhiyun static int soc_dapm_mux_update_power(struct snd_soc_card *card,
2275*4882a593Smuzhiyun 				 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
2276*4882a593Smuzhiyun {
2277*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
2278*4882a593Smuzhiyun 	int found = 0;
2279*4882a593Smuzhiyun 	bool connect;
2280*4882a593Smuzhiyun 
2281*4882a593Smuzhiyun 	lockdep_assert_held(&card->dapm_mutex);
2282*4882a593Smuzhiyun 
2283*4882a593Smuzhiyun 	/* find dapm widget path assoc with kcontrol */
2284*4882a593Smuzhiyun 	dapm_kcontrol_for_each_path(path, kcontrol) {
2285*4882a593Smuzhiyun 		found = 1;
2286*4882a593Smuzhiyun 		/* we now need to match the string in the enum to the path */
2287*4882a593Smuzhiyun 		if (e && !(strcmp(path->name, e->texts[mux])))
2288*4882a593Smuzhiyun 			connect = true;
2289*4882a593Smuzhiyun 		else
2290*4882a593Smuzhiyun 			connect = false;
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 		soc_dapm_connect_path(path, connect, "mux update");
2293*4882a593Smuzhiyun 	}
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun 	if (found)
2296*4882a593Smuzhiyun 		dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2297*4882a593Smuzhiyun 
2298*4882a593Smuzhiyun 	return found;
2299*4882a593Smuzhiyun }
2300*4882a593Smuzhiyun 
snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context * dapm,struct snd_kcontrol * kcontrol,int mux,struct soc_enum * e,struct snd_soc_dapm_update * update)2301*4882a593Smuzhiyun int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
2302*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2303*4882a593Smuzhiyun 	struct snd_soc_dapm_update *update)
2304*4882a593Smuzhiyun {
2305*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
2306*4882a593Smuzhiyun 	int ret;
2307*4882a593Smuzhiyun 
2308*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2309*4882a593Smuzhiyun 	card->update = update;
2310*4882a593Smuzhiyun 	ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
2311*4882a593Smuzhiyun 	card->update = NULL;
2312*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
2313*4882a593Smuzhiyun 	if (ret > 0)
2314*4882a593Smuzhiyun 		snd_soc_dpcm_runtime_update(card);
2315*4882a593Smuzhiyun 	return ret;
2316*4882a593Smuzhiyun }
2317*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
2318*4882a593Smuzhiyun 
2319*4882a593Smuzhiyun /* test and update the power status of a mixer or switch widget */
soc_dapm_mixer_update_power(struct snd_soc_card * card,struct snd_kcontrol * kcontrol,int connect,int rconnect)2320*4882a593Smuzhiyun static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
2321*4882a593Smuzhiyun 				       struct snd_kcontrol *kcontrol,
2322*4882a593Smuzhiyun 				       int connect, int rconnect)
2323*4882a593Smuzhiyun {
2324*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
2325*4882a593Smuzhiyun 	int found = 0;
2326*4882a593Smuzhiyun 
2327*4882a593Smuzhiyun 	lockdep_assert_held(&card->dapm_mutex);
2328*4882a593Smuzhiyun 
2329*4882a593Smuzhiyun 	/* find dapm widget path assoc with kcontrol */
2330*4882a593Smuzhiyun 	dapm_kcontrol_for_each_path(path, kcontrol) {
2331*4882a593Smuzhiyun 		/*
2332*4882a593Smuzhiyun 		 * Ideally this function should support any number of
2333*4882a593Smuzhiyun 		 * paths and channels. But since kcontrols only come
2334*4882a593Smuzhiyun 		 * in mono and stereo variants, we are limited to 2
2335*4882a593Smuzhiyun 		 * channels.
2336*4882a593Smuzhiyun 		 *
2337*4882a593Smuzhiyun 		 * The following code assumes for stereo controls the
2338*4882a593Smuzhiyun 		 * first path (when 'found == 0') is the left channel,
2339*4882a593Smuzhiyun 		 * and all remaining paths (when 'found == 1') are the
2340*4882a593Smuzhiyun 		 * right channel.
2341*4882a593Smuzhiyun 		 *
2342*4882a593Smuzhiyun 		 * A stereo control is signified by a valid 'rconnect'
2343*4882a593Smuzhiyun 		 * value, either 0 for unconnected, or >= 0 for connected.
2344*4882a593Smuzhiyun 		 * This is chosen instead of using snd_soc_volsw_is_stereo,
2345*4882a593Smuzhiyun 		 * so that the behavior of snd_soc_dapm_mixer_update_power
2346*4882a593Smuzhiyun 		 * doesn't change even when the kcontrol passed in is
2347*4882a593Smuzhiyun 		 * stereo.
2348*4882a593Smuzhiyun 		 *
2349*4882a593Smuzhiyun 		 * It passes 'connect' as the path connect status for
2350*4882a593Smuzhiyun 		 * the left channel, and 'rconnect' for the right
2351*4882a593Smuzhiyun 		 * channel.
2352*4882a593Smuzhiyun 		 */
2353*4882a593Smuzhiyun 		if (found && rconnect >= 0)
2354*4882a593Smuzhiyun 			soc_dapm_connect_path(path, rconnect, "mixer update");
2355*4882a593Smuzhiyun 		else
2356*4882a593Smuzhiyun 			soc_dapm_connect_path(path, connect, "mixer update");
2357*4882a593Smuzhiyun 		found = 1;
2358*4882a593Smuzhiyun 	}
2359*4882a593Smuzhiyun 
2360*4882a593Smuzhiyun 	if (found)
2361*4882a593Smuzhiyun 		dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2362*4882a593Smuzhiyun 
2363*4882a593Smuzhiyun 	return found;
2364*4882a593Smuzhiyun }
2365*4882a593Smuzhiyun 
snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context * dapm,struct snd_kcontrol * kcontrol,int connect,struct snd_soc_dapm_update * update)2366*4882a593Smuzhiyun int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
2367*4882a593Smuzhiyun 	struct snd_kcontrol *kcontrol, int connect,
2368*4882a593Smuzhiyun 	struct snd_soc_dapm_update *update)
2369*4882a593Smuzhiyun {
2370*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
2371*4882a593Smuzhiyun 	int ret;
2372*4882a593Smuzhiyun 
2373*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2374*4882a593Smuzhiyun 	card->update = update;
2375*4882a593Smuzhiyun 	ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
2376*4882a593Smuzhiyun 	card->update = NULL;
2377*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
2378*4882a593Smuzhiyun 	if (ret > 0)
2379*4882a593Smuzhiyun 		snd_soc_dpcm_runtime_update(card);
2380*4882a593Smuzhiyun 	return ret;
2381*4882a593Smuzhiyun }
2382*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
2383*4882a593Smuzhiyun 
dapm_widget_show_component(struct snd_soc_component * cmpnt,char * buf)2384*4882a593Smuzhiyun static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
2385*4882a593Smuzhiyun 	char *buf)
2386*4882a593Smuzhiyun {
2387*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
2388*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
2389*4882a593Smuzhiyun 	int count = 0;
2390*4882a593Smuzhiyun 	char *state = "not set";
2391*4882a593Smuzhiyun 
2392*4882a593Smuzhiyun 	/* card won't be set for the dummy component, as a spot fix
2393*4882a593Smuzhiyun 	 * we're checking for that case specifically here but in future
2394*4882a593Smuzhiyun 	 * we will ensure that the dummy component looks like others.
2395*4882a593Smuzhiyun 	 */
2396*4882a593Smuzhiyun 	if (!cmpnt->card)
2397*4882a593Smuzhiyun 		return 0;
2398*4882a593Smuzhiyun 
2399*4882a593Smuzhiyun 	for_each_card_widgets(cmpnt->card, w) {
2400*4882a593Smuzhiyun 		if (w->dapm != dapm)
2401*4882a593Smuzhiyun 			continue;
2402*4882a593Smuzhiyun 
2403*4882a593Smuzhiyun 		/* only display widgets that burn power */
2404*4882a593Smuzhiyun 		switch (w->id) {
2405*4882a593Smuzhiyun 		case snd_soc_dapm_hp:
2406*4882a593Smuzhiyun 		case snd_soc_dapm_mic:
2407*4882a593Smuzhiyun 		case snd_soc_dapm_spk:
2408*4882a593Smuzhiyun 		case snd_soc_dapm_line:
2409*4882a593Smuzhiyun 		case snd_soc_dapm_micbias:
2410*4882a593Smuzhiyun 		case snd_soc_dapm_dac:
2411*4882a593Smuzhiyun 		case snd_soc_dapm_adc:
2412*4882a593Smuzhiyun 		case snd_soc_dapm_pga:
2413*4882a593Smuzhiyun 		case snd_soc_dapm_effect:
2414*4882a593Smuzhiyun 		case snd_soc_dapm_out_drv:
2415*4882a593Smuzhiyun 		case snd_soc_dapm_mixer:
2416*4882a593Smuzhiyun 		case snd_soc_dapm_mixer_named_ctl:
2417*4882a593Smuzhiyun 		case snd_soc_dapm_supply:
2418*4882a593Smuzhiyun 		case snd_soc_dapm_regulator_supply:
2419*4882a593Smuzhiyun 		case snd_soc_dapm_pinctrl:
2420*4882a593Smuzhiyun 		case snd_soc_dapm_clock_supply:
2421*4882a593Smuzhiyun 			if (w->name)
2422*4882a593Smuzhiyun 				count += sprintf(buf + count, "%s: %s\n",
2423*4882a593Smuzhiyun 					w->name, w->power ? "On":"Off");
2424*4882a593Smuzhiyun 		break;
2425*4882a593Smuzhiyun 		default:
2426*4882a593Smuzhiyun 		break;
2427*4882a593Smuzhiyun 		}
2428*4882a593Smuzhiyun 	}
2429*4882a593Smuzhiyun 
2430*4882a593Smuzhiyun 	switch (snd_soc_dapm_get_bias_level(dapm)) {
2431*4882a593Smuzhiyun 	case SND_SOC_BIAS_ON:
2432*4882a593Smuzhiyun 		state = "On";
2433*4882a593Smuzhiyun 		break;
2434*4882a593Smuzhiyun 	case SND_SOC_BIAS_PREPARE:
2435*4882a593Smuzhiyun 		state = "Prepare";
2436*4882a593Smuzhiyun 		break;
2437*4882a593Smuzhiyun 	case SND_SOC_BIAS_STANDBY:
2438*4882a593Smuzhiyun 		state = "Standby";
2439*4882a593Smuzhiyun 		break;
2440*4882a593Smuzhiyun 	case SND_SOC_BIAS_OFF:
2441*4882a593Smuzhiyun 		state = "Off";
2442*4882a593Smuzhiyun 		break;
2443*4882a593Smuzhiyun 	}
2444*4882a593Smuzhiyun 	count += sprintf(buf + count, "PM State: %s\n", state);
2445*4882a593Smuzhiyun 
2446*4882a593Smuzhiyun 	return count;
2447*4882a593Smuzhiyun }
2448*4882a593Smuzhiyun 
2449*4882a593Smuzhiyun /* show dapm widget status in sys fs */
dapm_widget_show(struct device * dev,struct device_attribute * attr,char * buf)2450*4882a593Smuzhiyun static ssize_t dapm_widget_show(struct device *dev,
2451*4882a593Smuzhiyun 	struct device_attribute *attr, char *buf)
2452*4882a593Smuzhiyun {
2453*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2454*4882a593Smuzhiyun 	struct snd_soc_dai *codec_dai;
2455*4882a593Smuzhiyun 	int i, count = 0;
2456*4882a593Smuzhiyun 
2457*4882a593Smuzhiyun 	mutex_lock(&rtd->card->dapm_mutex);
2458*4882a593Smuzhiyun 
2459*4882a593Smuzhiyun 	for_each_rtd_codec_dais(rtd, i, codec_dai) {
2460*4882a593Smuzhiyun 		struct snd_soc_component *cmpnt = codec_dai->component;
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 		count += dapm_widget_show_component(cmpnt, buf + count);
2463*4882a593Smuzhiyun 	}
2464*4882a593Smuzhiyun 
2465*4882a593Smuzhiyun 	mutex_unlock(&rtd->card->dapm_mutex);
2466*4882a593Smuzhiyun 
2467*4882a593Smuzhiyun 	return count;
2468*4882a593Smuzhiyun }
2469*4882a593Smuzhiyun 
2470*4882a593Smuzhiyun static DEVICE_ATTR_RO(dapm_widget);
2471*4882a593Smuzhiyun 
2472*4882a593Smuzhiyun struct attribute *soc_dapm_dev_attrs[] = {
2473*4882a593Smuzhiyun 	&dev_attr_dapm_widget.attr,
2474*4882a593Smuzhiyun 	NULL
2475*4882a593Smuzhiyun };
2476*4882a593Smuzhiyun 
dapm_free_path(struct snd_soc_dapm_path * path)2477*4882a593Smuzhiyun static void dapm_free_path(struct snd_soc_dapm_path *path)
2478*4882a593Smuzhiyun {
2479*4882a593Smuzhiyun 	list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
2480*4882a593Smuzhiyun 	list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
2481*4882a593Smuzhiyun 	list_del(&path->list_kcontrol);
2482*4882a593Smuzhiyun 	list_del(&path->list);
2483*4882a593Smuzhiyun 	kfree(path);
2484*4882a593Smuzhiyun }
2485*4882a593Smuzhiyun 
snd_soc_dapm_free_widget(struct snd_soc_dapm_widget * w)2486*4882a593Smuzhiyun void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2487*4882a593Smuzhiyun {
2488*4882a593Smuzhiyun 	struct snd_soc_dapm_path *p, *next_p;
2489*4882a593Smuzhiyun 	enum snd_soc_dapm_direction dir;
2490*4882a593Smuzhiyun 
2491*4882a593Smuzhiyun 	list_del(&w->list);
2492*4882a593Smuzhiyun 	list_del(&w->dirty);
2493*4882a593Smuzhiyun 	/*
2494*4882a593Smuzhiyun 	 * remove source and sink paths associated to this widget.
2495*4882a593Smuzhiyun 	 * While removing the path, remove reference to it from both
2496*4882a593Smuzhiyun 	 * source and sink widgets so that path is removed only once.
2497*4882a593Smuzhiyun 	 */
2498*4882a593Smuzhiyun 	snd_soc_dapm_for_each_direction(dir) {
2499*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
2500*4882a593Smuzhiyun 			dapm_free_path(p);
2501*4882a593Smuzhiyun 	}
2502*4882a593Smuzhiyun 
2503*4882a593Smuzhiyun 	kfree(w->kcontrols);
2504*4882a593Smuzhiyun 	kfree_const(w->name);
2505*4882a593Smuzhiyun 	kfree_const(w->sname);
2506*4882a593Smuzhiyun 	kfree(w);
2507*4882a593Smuzhiyun }
2508*4882a593Smuzhiyun 
snd_soc_dapm_reset_cache(struct snd_soc_dapm_context * dapm)2509*4882a593Smuzhiyun void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
2510*4882a593Smuzhiyun {
2511*4882a593Smuzhiyun 	dapm->path_sink_cache.widget = NULL;
2512*4882a593Smuzhiyun 	dapm->path_source_cache.widget = NULL;
2513*4882a593Smuzhiyun }
2514*4882a593Smuzhiyun 
2515*4882a593Smuzhiyun /* free all dapm widgets and resources */
dapm_free_widgets(struct snd_soc_dapm_context * dapm)2516*4882a593Smuzhiyun static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
2517*4882a593Smuzhiyun {
2518*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w, *next_w;
2519*4882a593Smuzhiyun 
2520*4882a593Smuzhiyun 	for_each_card_widgets_safe(dapm->card, w, next_w) {
2521*4882a593Smuzhiyun 		if (w->dapm != dapm)
2522*4882a593Smuzhiyun 			continue;
2523*4882a593Smuzhiyun 		snd_soc_dapm_free_widget(w);
2524*4882a593Smuzhiyun 	}
2525*4882a593Smuzhiyun 	snd_soc_dapm_reset_cache(dapm);
2526*4882a593Smuzhiyun }
2527*4882a593Smuzhiyun 
dapm_find_widget(struct snd_soc_dapm_context * dapm,const char * pin,bool search_other_contexts)2528*4882a593Smuzhiyun static struct snd_soc_dapm_widget *dapm_find_widget(
2529*4882a593Smuzhiyun 			struct snd_soc_dapm_context *dapm, const char *pin,
2530*4882a593Smuzhiyun 			bool search_other_contexts)
2531*4882a593Smuzhiyun {
2532*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
2533*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *fallback = NULL;
2534*4882a593Smuzhiyun 	char prefixed_pin[80];
2535*4882a593Smuzhiyun 	const char *pin_name;
2536*4882a593Smuzhiyun 	const char *prefix = soc_dapm_prefix(dapm);
2537*4882a593Smuzhiyun 
2538*4882a593Smuzhiyun 	if (prefix) {
2539*4882a593Smuzhiyun 		snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s",
2540*4882a593Smuzhiyun 			 prefix, pin);
2541*4882a593Smuzhiyun 		pin_name = prefixed_pin;
2542*4882a593Smuzhiyun 	} else {
2543*4882a593Smuzhiyun 		pin_name = pin;
2544*4882a593Smuzhiyun 	}
2545*4882a593Smuzhiyun 
2546*4882a593Smuzhiyun 	for_each_card_widgets(dapm->card, w) {
2547*4882a593Smuzhiyun 		if (!strcmp(w->name, pin_name)) {
2548*4882a593Smuzhiyun 			if (w->dapm == dapm)
2549*4882a593Smuzhiyun 				return w;
2550*4882a593Smuzhiyun 			else
2551*4882a593Smuzhiyun 				fallback = w;
2552*4882a593Smuzhiyun 		}
2553*4882a593Smuzhiyun 	}
2554*4882a593Smuzhiyun 
2555*4882a593Smuzhiyun 	if (search_other_contexts)
2556*4882a593Smuzhiyun 		return fallback;
2557*4882a593Smuzhiyun 
2558*4882a593Smuzhiyun 	return NULL;
2559*4882a593Smuzhiyun }
2560*4882a593Smuzhiyun 
2561*4882a593Smuzhiyun /*
2562*4882a593Smuzhiyun  * set the DAPM pin status:
2563*4882a593Smuzhiyun  * returns 1 when the value has been updated, 0 when unchanged, or a negative
2564*4882a593Smuzhiyun  * error code; called from kcontrol put callback
2565*4882a593Smuzhiyun  */
__snd_soc_dapm_set_pin(struct snd_soc_dapm_context * dapm,const char * pin,int status)2566*4882a593Smuzhiyun static int __snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
2567*4882a593Smuzhiyun 				  const char *pin, int status)
2568*4882a593Smuzhiyun {
2569*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
2570*4882a593Smuzhiyun 	int ret = 0;
2571*4882a593Smuzhiyun 
2572*4882a593Smuzhiyun 	dapm_assert_locked(dapm);
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun 	if (!w) {
2575*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
2576*4882a593Smuzhiyun 		return -EINVAL;
2577*4882a593Smuzhiyun 	}
2578*4882a593Smuzhiyun 
2579*4882a593Smuzhiyun 	if (w->connected != status) {
2580*4882a593Smuzhiyun 		dapm_mark_dirty(w, "pin configuration");
2581*4882a593Smuzhiyun 		dapm_widget_invalidate_input_paths(w);
2582*4882a593Smuzhiyun 		dapm_widget_invalidate_output_paths(w);
2583*4882a593Smuzhiyun 		ret = 1;
2584*4882a593Smuzhiyun 	}
2585*4882a593Smuzhiyun 
2586*4882a593Smuzhiyun 	w->connected = status;
2587*4882a593Smuzhiyun 	if (status == 0)
2588*4882a593Smuzhiyun 		w->force = 0;
2589*4882a593Smuzhiyun 
2590*4882a593Smuzhiyun 	return ret;
2591*4882a593Smuzhiyun }
2592*4882a593Smuzhiyun 
2593*4882a593Smuzhiyun /*
2594*4882a593Smuzhiyun  * similar as __snd_soc_dapm_set_pin(), but returns 0 when successful;
2595*4882a593Smuzhiyun  * called from several API functions below
2596*4882a593Smuzhiyun  */
snd_soc_dapm_set_pin(struct snd_soc_dapm_context * dapm,const char * pin,int status)2597*4882a593Smuzhiyun static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
2598*4882a593Smuzhiyun 				const char *pin, int status)
2599*4882a593Smuzhiyun {
2600*4882a593Smuzhiyun 	int ret = __snd_soc_dapm_set_pin(dapm, pin, status);
2601*4882a593Smuzhiyun 
2602*4882a593Smuzhiyun 	return ret < 0 ? ret : 0;
2603*4882a593Smuzhiyun }
2604*4882a593Smuzhiyun 
2605*4882a593Smuzhiyun /**
2606*4882a593Smuzhiyun  * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2607*4882a593Smuzhiyun  * @dapm: DAPM context
2608*4882a593Smuzhiyun  *
2609*4882a593Smuzhiyun  * Walks all dapm audio paths and powers widgets according to their
2610*4882a593Smuzhiyun  * stream or path usage.
2611*4882a593Smuzhiyun  *
2612*4882a593Smuzhiyun  * Requires external locking.
2613*4882a593Smuzhiyun  *
2614*4882a593Smuzhiyun  * Returns 0 for success.
2615*4882a593Smuzhiyun  */
snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context * dapm)2616*4882a593Smuzhiyun int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2617*4882a593Smuzhiyun {
2618*4882a593Smuzhiyun 	/*
2619*4882a593Smuzhiyun 	 * Suppress early reports (eg, jacks syncing their state) to avoid
2620*4882a593Smuzhiyun 	 * silly DAPM runs during card startup.
2621*4882a593Smuzhiyun 	 */
2622*4882a593Smuzhiyun 	if (!dapm->card || !dapm->card->instantiated)
2623*4882a593Smuzhiyun 		return 0;
2624*4882a593Smuzhiyun 
2625*4882a593Smuzhiyun 	return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2626*4882a593Smuzhiyun }
2627*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2628*4882a593Smuzhiyun 
2629*4882a593Smuzhiyun /**
2630*4882a593Smuzhiyun  * snd_soc_dapm_sync - scan and power dapm paths
2631*4882a593Smuzhiyun  * @dapm: DAPM context
2632*4882a593Smuzhiyun  *
2633*4882a593Smuzhiyun  * Walks all dapm audio paths and powers widgets according to their
2634*4882a593Smuzhiyun  * stream or path usage.
2635*4882a593Smuzhiyun  *
2636*4882a593Smuzhiyun  * Returns 0 for success.
2637*4882a593Smuzhiyun  */
snd_soc_dapm_sync(struct snd_soc_dapm_context * dapm)2638*4882a593Smuzhiyun int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
2639*4882a593Smuzhiyun {
2640*4882a593Smuzhiyun 	int ret;
2641*4882a593Smuzhiyun 
2642*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2643*4882a593Smuzhiyun 	ret = snd_soc_dapm_sync_unlocked(dapm);
2644*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
2645*4882a593Smuzhiyun 	return ret;
2646*4882a593Smuzhiyun }
2647*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
2648*4882a593Smuzhiyun 
dapm_update_dai_chan(struct snd_soc_dapm_path * p,struct snd_soc_dapm_widget * w,int channels)2649*4882a593Smuzhiyun static int dapm_update_dai_chan(struct snd_soc_dapm_path *p,
2650*4882a593Smuzhiyun 				struct snd_soc_dapm_widget *w,
2651*4882a593Smuzhiyun 				int channels)
2652*4882a593Smuzhiyun {
2653*4882a593Smuzhiyun 	switch (w->id) {
2654*4882a593Smuzhiyun 	case snd_soc_dapm_aif_out:
2655*4882a593Smuzhiyun 	case snd_soc_dapm_aif_in:
2656*4882a593Smuzhiyun 		break;
2657*4882a593Smuzhiyun 	default:
2658*4882a593Smuzhiyun 		return 0;
2659*4882a593Smuzhiyun 	}
2660*4882a593Smuzhiyun 
2661*4882a593Smuzhiyun 	dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n",
2662*4882a593Smuzhiyun 		w->channel < channels ? "Connecting" : "Disconnecting",
2663*4882a593Smuzhiyun 		p->source->name, p->sink->name);
2664*4882a593Smuzhiyun 
2665*4882a593Smuzhiyun 	if (w->channel < channels)
2666*4882a593Smuzhiyun 		soc_dapm_connect_path(p, true, "dai update");
2667*4882a593Smuzhiyun 	else
2668*4882a593Smuzhiyun 		soc_dapm_connect_path(p, false, "dai update");
2669*4882a593Smuzhiyun 
2670*4882a593Smuzhiyun 	return 0;
2671*4882a593Smuzhiyun }
2672*4882a593Smuzhiyun 
dapm_update_dai_unlocked(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)2673*4882a593Smuzhiyun static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream,
2674*4882a593Smuzhiyun 				    struct snd_pcm_hw_params *params,
2675*4882a593Smuzhiyun 				    struct snd_soc_dai *dai)
2676*4882a593Smuzhiyun {
2677*4882a593Smuzhiyun 	int dir = substream->stream;
2678*4882a593Smuzhiyun 	int channels = params_channels(params);
2679*4882a593Smuzhiyun 	struct snd_soc_dapm_path *p;
2680*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
2681*4882a593Smuzhiyun 	int ret;
2682*4882a593Smuzhiyun 
2683*4882a593Smuzhiyun 	w = snd_soc_dai_get_widget(dai, dir);
2684*4882a593Smuzhiyun 
2685*4882a593Smuzhiyun 	if (!w)
2686*4882a593Smuzhiyun 		return 0;
2687*4882a593Smuzhiyun 
2688*4882a593Smuzhiyun 	dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name,
2689*4882a593Smuzhiyun 		dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
2690*4882a593Smuzhiyun 
2691*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_sink_path(w, p) {
2692*4882a593Smuzhiyun 		ret = dapm_update_dai_chan(p, p->sink, channels);
2693*4882a593Smuzhiyun 		if (ret < 0)
2694*4882a593Smuzhiyun 			return ret;
2695*4882a593Smuzhiyun 	}
2696*4882a593Smuzhiyun 
2697*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_source_path(w, p) {
2698*4882a593Smuzhiyun 		ret = dapm_update_dai_chan(p, p->source, channels);
2699*4882a593Smuzhiyun 		if (ret < 0)
2700*4882a593Smuzhiyun 			return ret;
2701*4882a593Smuzhiyun 	}
2702*4882a593Smuzhiyun 
2703*4882a593Smuzhiyun 	return 0;
2704*4882a593Smuzhiyun }
2705*4882a593Smuzhiyun 
snd_soc_dapm_update_dai(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)2706*4882a593Smuzhiyun int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
2707*4882a593Smuzhiyun 			    struct snd_pcm_hw_params *params,
2708*4882a593Smuzhiyun 			    struct snd_soc_dai *dai)
2709*4882a593Smuzhiyun {
2710*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2711*4882a593Smuzhiyun 	int ret;
2712*4882a593Smuzhiyun 
2713*4882a593Smuzhiyun 	mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2714*4882a593Smuzhiyun 	ret = dapm_update_dai_unlocked(substream, params, dai);
2715*4882a593Smuzhiyun 	mutex_unlock(&rtd->card->dapm_mutex);
2716*4882a593Smuzhiyun 
2717*4882a593Smuzhiyun 	return ret;
2718*4882a593Smuzhiyun }
2719*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
2720*4882a593Smuzhiyun 
2721*4882a593Smuzhiyun /*
2722*4882a593Smuzhiyun  * dapm_update_widget_flags() - Re-compute widget sink and source flags
2723*4882a593Smuzhiyun  * @w: The widget for which to update the flags
2724*4882a593Smuzhiyun  *
2725*4882a593Smuzhiyun  * Some widgets have a dynamic category which depends on which neighbors they
2726*4882a593Smuzhiyun  * are connected to. This function update the category for these widgets.
2727*4882a593Smuzhiyun  *
2728*4882a593Smuzhiyun  * This function must be called whenever a path is added or removed to a widget.
2729*4882a593Smuzhiyun  */
dapm_update_widget_flags(struct snd_soc_dapm_widget * w)2730*4882a593Smuzhiyun static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2731*4882a593Smuzhiyun {
2732*4882a593Smuzhiyun 	enum snd_soc_dapm_direction dir;
2733*4882a593Smuzhiyun 	struct snd_soc_dapm_path *p;
2734*4882a593Smuzhiyun 	unsigned int ep;
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun 	switch (w->id) {
2737*4882a593Smuzhiyun 	case snd_soc_dapm_input:
2738*4882a593Smuzhiyun 		/* On a fully routed card an input is never a source */
2739*4882a593Smuzhiyun 		if (w->dapm->card->fully_routed)
2740*4882a593Smuzhiyun 			return;
2741*4882a593Smuzhiyun 		ep = SND_SOC_DAPM_EP_SOURCE;
2742*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_source_path(w, p) {
2743*4882a593Smuzhiyun 			if (p->source->id == snd_soc_dapm_micbias ||
2744*4882a593Smuzhiyun 				p->source->id == snd_soc_dapm_mic ||
2745*4882a593Smuzhiyun 				p->source->id == snd_soc_dapm_line ||
2746*4882a593Smuzhiyun 				p->source->id == snd_soc_dapm_output) {
2747*4882a593Smuzhiyun 					ep = 0;
2748*4882a593Smuzhiyun 					break;
2749*4882a593Smuzhiyun 			}
2750*4882a593Smuzhiyun 		}
2751*4882a593Smuzhiyun 		break;
2752*4882a593Smuzhiyun 	case snd_soc_dapm_output:
2753*4882a593Smuzhiyun 		/* On a fully routed card a output is never a sink */
2754*4882a593Smuzhiyun 		if (w->dapm->card->fully_routed)
2755*4882a593Smuzhiyun 			return;
2756*4882a593Smuzhiyun 		ep = SND_SOC_DAPM_EP_SINK;
2757*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_sink_path(w, p) {
2758*4882a593Smuzhiyun 			if (p->sink->id == snd_soc_dapm_spk ||
2759*4882a593Smuzhiyun 				p->sink->id == snd_soc_dapm_hp ||
2760*4882a593Smuzhiyun 				p->sink->id == snd_soc_dapm_line ||
2761*4882a593Smuzhiyun 				p->sink->id == snd_soc_dapm_input) {
2762*4882a593Smuzhiyun 					ep = 0;
2763*4882a593Smuzhiyun 					break;
2764*4882a593Smuzhiyun 			}
2765*4882a593Smuzhiyun 		}
2766*4882a593Smuzhiyun 		break;
2767*4882a593Smuzhiyun 	case snd_soc_dapm_line:
2768*4882a593Smuzhiyun 		ep = 0;
2769*4882a593Smuzhiyun 		snd_soc_dapm_for_each_direction(dir) {
2770*4882a593Smuzhiyun 			if (!list_empty(&w->edges[dir]))
2771*4882a593Smuzhiyun 				ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
2772*4882a593Smuzhiyun 		}
2773*4882a593Smuzhiyun 		break;
2774*4882a593Smuzhiyun 	default:
2775*4882a593Smuzhiyun 		return;
2776*4882a593Smuzhiyun 	}
2777*4882a593Smuzhiyun 
2778*4882a593Smuzhiyun 	w->is_ep = ep;
2779*4882a593Smuzhiyun }
2780*4882a593Smuzhiyun 
snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context * dapm,struct snd_soc_dapm_widget * source,struct snd_soc_dapm_widget * sink,const char * control)2781*4882a593Smuzhiyun static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2782*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2783*4882a593Smuzhiyun 	const char *control)
2784*4882a593Smuzhiyun {
2785*4882a593Smuzhiyun 	bool dynamic_source = false;
2786*4882a593Smuzhiyun 	bool dynamic_sink = false;
2787*4882a593Smuzhiyun 
2788*4882a593Smuzhiyun 	if (!control)
2789*4882a593Smuzhiyun 		return 0;
2790*4882a593Smuzhiyun 
2791*4882a593Smuzhiyun 	switch (source->id) {
2792*4882a593Smuzhiyun 	case snd_soc_dapm_demux:
2793*4882a593Smuzhiyun 		dynamic_source = true;
2794*4882a593Smuzhiyun 		break;
2795*4882a593Smuzhiyun 	default:
2796*4882a593Smuzhiyun 		break;
2797*4882a593Smuzhiyun 	}
2798*4882a593Smuzhiyun 
2799*4882a593Smuzhiyun 	switch (sink->id) {
2800*4882a593Smuzhiyun 	case snd_soc_dapm_mux:
2801*4882a593Smuzhiyun 	case snd_soc_dapm_switch:
2802*4882a593Smuzhiyun 	case snd_soc_dapm_mixer:
2803*4882a593Smuzhiyun 	case snd_soc_dapm_mixer_named_ctl:
2804*4882a593Smuzhiyun 		dynamic_sink = true;
2805*4882a593Smuzhiyun 		break;
2806*4882a593Smuzhiyun 	default:
2807*4882a593Smuzhiyun 		break;
2808*4882a593Smuzhiyun 	}
2809*4882a593Smuzhiyun 
2810*4882a593Smuzhiyun 	if (dynamic_source && dynamic_sink) {
2811*4882a593Smuzhiyun 		dev_err(dapm->dev,
2812*4882a593Smuzhiyun 			"Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2813*4882a593Smuzhiyun 			source->name, control, sink->name);
2814*4882a593Smuzhiyun 		return -EINVAL;
2815*4882a593Smuzhiyun 	} else if (!dynamic_source && !dynamic_sink) {
2816*4882a593Smuzhiyun 		dev_err(dapm->dev,
2817*4882a593Smuzhiyun 			"Control not supported for path %s -> [%s] -> %s\n",
2818*4882a593Smuzhiyun 			source->name, control, sink->name);
2819*4882a593Smuzhiyun 		return -EINVAL;
2820*4882a593Smuzhiyun 	}
2821*4882a593Smuzhiyun 
2822*4882a593Smuzhiyun 	return 0;
2823*4882a593Smuzhiyun }
2824*4882a593Smuzhiyun 
snd_soc_dapm_add_path(struct snd_soc_dapm_context * dapm,struct snd_soc_dapm_widget * wsource,struct snd_soc_dapm_widget * wsink,const char * control,int (* connected)(struct snd_soc_dapm_widget * source,struct snd_soc_dapm_widget * sink))2825*4882a593Smuzhiyun static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2826*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2827*4882a593Smuzhiyun 	const char *control,
2828*4882a593Smuzhiyun 	int (*connected)(struct snd_soc_dapm_widget *source,
2829*4882a593Smuzhiyun 			 struct snd_soc_dapm_widget *sink))
2830*4882a593Smuzhiyun {
2831*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *widgets[2];
2832*4882a593Smuzhiyun 	enum snd_soc_dapm_direction dir;
2833*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
2834*4882a593Smuzhiyun 	int ret;
2835*4882a593Smuzhiyun 
2836*4882a593Smuzhiyun 	if (wsink->is_supply && !wsource->is_supply) {
2837*4882a593Smuzhiyun 		dev_err(dapm->dev,
2838*4882a593Smuzhiyun 			"Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2839*4882a593Smuzhiyun 			wsource->name, wsink->name);
2840*4882a593Smuzhiyun 		return -EINVAL;
2841*4882a593Smuzhiyun 	}
2842*4882a593Smuzhiyun 
2843*4882a593Smuzhiyun 	if (connected && !wsource->is_supply) {
2844*4882a593Smuzhiyun 		dev_err(dapm->dev,
2845*4882a593Smuzhiyun 			"connected() callback only supported for supply widgets (%s -> %s)\n",
2846*4882a593Smuzhiyun 			wsource->name, wsink->name);
2847*4882a593Smuzhiyun 		return -EINVAL;
2848*4882a593Smuzhiyun 	}
2849*4882a593Smuzhiyun 
2850*4882a593Smuzhiyun 	if (wsource->is_supply && control) {
2851*4882a593Smuzhiyun 		dev_err(dapm->dev,
2852*4882a593Smuzhiyun 			"Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2853*4882a593Smuzhiyun 			wsource->name, control, wsink->name);
2854*4882a593Smuzhiyun 		return -EINVAL;
2855*4882a593Smuzhiyun 	}
2856*4882a593Smuzhiyun 
2857*4882a593Smuzhiyun 	ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2858*4882a593Smuzhiyun 	if (ret)
2859*4882a593Smuzhiyun 		return ret;
2860*4882a593Smuzhiyun 
2861*4882a593Smuzhiyun 	path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2862*4882a593Smuzhiyun 	if (!path)
2863*4882a593Smuzhiyun 		return -ENOMEM;
2864*4882a593Smuzhiyun 
2865*4882a593Smuzhiyun 	path->node[SND_SOC_DAPM_DIR_IN] = wsource;
2866*4882a593Smuzhiyun 	path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
2867*4882a593Smuzhiyun 	widgets[SND_SOC_DAPM_DIR_IN] = wsource;
2868*4882a593Smuzhiyun 	widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun 	path->connected = connected;
2871*4882a593Smuzhiyun 	INIT_LIST_HEAD(&path->list);
2872*4882a593Smuzhiyun 	INIT_LIST_HEAD(&path->list_kcontrol);
2873*4882a593Smuzhiyun 
2874*4882a593Smuzhiyun 	if (wsource->is_supply || wsink->is_supply)
2875*4882a593Smuzhiyun 		path->is_supply = 1;
2876*4882a593Smuzhiyun 
2877*4882a593Smuzhiyun 	/* connect static paths */
2878*4882a593Smuzhiyun 	if (control == NULL) {
2879*4882a593Smuzhiyun 		path->connect = 1;
2880*4882a593Smuzhiyun 	} else {
2881*4882a593Smuzhiyun 		switch (wsource->id) {
2882*4882a593Smuzhiyun 		case snd_soc_dapm_demux:
2883*4882a593Smuzhiyun 			ret = dapm_connect_mux(dapm, path, control, wsource);
2884*4882a593Smuzhiyun 			if (ret)
2885*4882a593Smuzhiyun 				goto err;
2886*4882a593Smuzhiyun 			break;
2887*4882a593Smuzhiyun 		default:
2888*4882a593Smuzhiyun 			break;
2889*4882a593Smuzhiyun 		}
2890*4882a593Smuzhiyun 
2891*4882a593Smuzhiyun 		switch (wsink->id) {
2892*4882a593Smuzhiyun 		case snd_soc_dapm_mux:
2893*4882a593Smuzhiyun 			ret = dapm_connect_mux(dapm, path, control, wsink);
2894*4882a593Smuzhiyun 			if (ret != 0)
2895*4882a593Smuzhiyun 				goto err;
2896*4882a593Smuzhiyun 			break;
2897*4882a593Smuzhiyun 		case snd_soc_dapm_switch:
2898*4882a593Smuzhiyun 		case snd_soc_dapm_mixer:
2899*4882a593Smuzhiyun 		case snd_soc_dapm_mixer_named_ctl:
2900*4882a593Smuzhiyun 			ret = dapm_connect_mixer(dapm, path, control);
2901*4882a593Smuzhiyun 			if (ret != 0)
2902*4882a593Smuzhiyun 				goto err;
2903*4882a593Smuzhiyun 			break;
2904*4882a593Smuzhiyun 		default:
2905*4882a593Smuzhiyun 			break;
2906*4882a593Smuzhiyun 		}
2907*4882a593Smuzhiyun 	}
2908*4882a593Smuzhiyun 
2909*4882a593Smuzhiyun 	list_add(&path->list, &dapm->card->paths);
2910*4882a593Smuzhiyun 	snd_soc_dapm_for_each_direction(dir)
2911*4882a593Smuzhiyun 		list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
2912*4882a593Smuzhiyun 
2913*4882a593Smuzhiyun 	snd_soc_dapm_for_each_direction(dir) {
2914*4882a593Smuzhiyun 		dapm_update_widget_flags(widgets[dir]);
2915*4882a593Smuzhiyun 		dapm_mark_dirty(widgets[dir], "Route added");
2916*4882a593Smuzhiyun 	}
2917*4882a593Smuzhiyun 
2918*4882a593Smuzhiyun 	if (dapm->card->instantiated && path->connect)
2919*4882a593Smuzhiyun 		dapm_path_invalidate(path);
2920*4882a593Smuzhiyun 
2921*4882a593Smuzhiyun 	return 0;
2922*4882a593Smuzhiyun err:
2923*4882a593Smuzhiyun 	kfree(path);
2924*4882a593Smuzhiyun 	return ret;
2925*4882a593Smuzhiyun }
2926*4882a593Smuzhiyun 
snd_soc_dapm_add_route(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_route * route)2927*4882a593Smuzhiyun static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
2928*4882a593Smuzhiyun 				  const struct snd_soc_dapm_route *route)
2929*4882a593Smuzhiyun {
2930*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2931*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2932*4882a593Smuzhiyun 	const char *sink;
2933*4882a593Smuzhiyun 	const char *source;
2934*4882a593Smuzhiyun 	char prefixed_sink[80];
2935*4882a593Smuzhiyun 	char prefixed_source[80];
2936*4882a593Smuzhiyun 	const char *prefix;
2937*4882a593Smuzhiyun 	unsigned int sink_ref = 0;
2938*4882a593Smuzhiyun 	unsigned int source_ref = 0;
2939*4882a593Smuzhiyun 	int ret;
2940*4882a593Smuzhiyun 
2941*4882a593Smuzhiyun 	prefix = soc_dapm_prefix(dapm);
2942*4882a593Smuzhiyun 	if (prefix) {
2943*4882a593Smuzhiyun 		snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2944*4882a593Smuzhiyun 			 prefix, route->sink);
2945*4882a593Smuzhiyun 		sink = prefixed_sink;
2946*4882a593Smuzhiyun 		snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
2947*4882a593Smuzhiyun 			 prefix, route->source);
2948*4882a593Smuzhiyun 		source = prefixed_source;
2949*4882a593Smuzhiyun 	} else {
2950*4882a593Smuzhiyun 		sink = route->sink;
2951*4882a593Smuzhiyun 		source = route->source;
2952*4882a593Smuzhiyun 	}
2953*4882a593Smuzhiyun 
2954*4882a593Smuzhiyun 	wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2955*4882a593Smuzhiyun 	wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2956*4882a593Smuzhiyun 
2957*4882a593Smuzhiyun 	if (wsink && wsource)
2958*4882a593Smuzhiyun 		goto skip_search;
2959*4882a593Smuzhiyun 
2960*4882a593Smuzhiyun 	/*
2961*4882a593Smuzhiyun 	 * find src and dest widgets over all widgets but favor a widget from
2962*4882a593Smuzhiyun 	 * current DAPM context
2963*4882a593Smuzhiyun 	 */
2964*4882a593Smuzhiyun 	for_each_card_widgets(dapm->card, w) {
2965*4882a593Smuzhiyun 		if (!wsink && !(strcmp(w->name, sink))) {
2966*4882a593Smuzhiyun 			wtsink = w;
2967*4882a593Smuzhiyun 			if (w->dapm == dapm) {
2968*4882a593Smuzhiyun 				wsink = w;
2969*4882a593Smuzhiyun 				if (wsource)
2970*4882a593Smuzhiyun 					break;
2971*4882a593Smuzhiyun 			}
2972*4882a593Smuzhiyun 			sink_ref++;
2973*4882a593Smuzhiyun 			if (sink_ref > 1)
2974*4882a593Smuzhiyun 				dev_warn(dapm->dev,
2975*4882a593Smuzhiyun 					"ASoC: sink widget %s overwritten\n",
2976*4882a593Smuzhiyun 					w->name);
2977*4882a593Smuzhiyun 			continue;
2978*4882a593Smuzhiyun 		}
2979*4882a593Smuzhiyun 		if (!wsource && !(strcmp(w->name, source))) {
2980*4882a593Smuzhiyun 			wtsource = w;
2981*4882a593Smuzhiyun 			if (w->dapm == dapm) {
2982*4882a593Smuzhiyun 				wsource = w;
2983*4882a593Smuzhiyun 				if (wsink)
2984*4882a593Smuzhiyun 					break;
2985*4882a593Smuzhiyun 			}
2986*4882a593Smuzhiyun 			source_ref++;
2987*4882a593Smuzhiyun 			if (source_ref > 1)
2988*4882a593Smuzhiyun 				dev_warn(dapm->dev,
2989*4882a593Smuzhiyun 					"ASoC: source widget %s overwritten\n",
2990*4882a593Smuzhiyun 					w->name);
2991*4882a593Smuzhiyun 		}
2992*4882a593Smuzhiyun 	}
2993*4882a593Smuzhiyun 	/* use widget from another DAPM context if not found from this */
2994*4882a593Smuzhiyun 	if (!wsink)
2995*4882a593Smuzhiyun 		wsink = wtsink;
2996*4882a593Smuzhiyun 	if (!wsource)
2997*4882a593Smuzhiyun 		wsource = wtsource;
2998*4882a593Smuzhiyun 
2999*4882a593Smuzhiyun 	if (wsource == NULL) {
3000*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
3001*4882a593Smuzhiyun 			route->source);
3002*4882a593Smuzhiyun 		return -ENODEV;
3003*4882a593Smuzhiyun 	}
3004*4882a593Smuzhiyun 	if (wsink == NULL) {
3005*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
3006*4882a593Smuzhiyun 			route->sink);
3007*4882a593Smuzhiyun 		return -ENODEV;
3008*4882a593Smuzhiyun 	}
3009*4882a593Smuzhiyun 
3010*4882a593Smuzhiyun skip_search:
3011*4882a593Smuzhiyun 	dapm_wcache_update(&dapm->path_sink_cache, wsink);
3012*4882a593Smuzhiyun 	dapm_wcache_update(&dapm->path_source_cache, wsource);
3013*4882a593Smuzhiyun 
3014*4882a593Smuzhiyun 	ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
3015*4882a593Smuzhiyun 		route->connected);
3016*4882a593Smuzhiyun 	if (ret)
3017*4882a593Smuzhiyun 		goto err;
3018*4882a593Smuzhiyun 
3019*4882a593Smuzhiyun 	return 0;
3020*4882a593Smuzhiyun err:
3021*4882a593Smuzhiyun 	dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
3022*4882a593Smuzhiyun 		 source, route->control, sink);
3023*4882a593Smuzhiyun 	return ret;
3024*4882a593Smuzhiyun }
3025*4882a593Smuzhiyun 
snd_soc_dapm_del_route(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_route * route)3026*4882a593Smuzhiyun static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
3027*4882a593Smuzhiyun 				  const struct snd_soc_dapm_route *route)
3028*4882a593Smuzhiyun {
3029*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *wsource, *wsink;
3030*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path, *p;
3031*4882a593Smuzhiyun 	const char *sink;
3032*4882a593Smuzhiyun 	const char *source;
3033*4882a593Smuzhiyun 	char prefixed_sink[80];
3034*4882a593Smuzhiyun 	char prefixed_source[80];
3035*4882a593Smuzhiyun 	const char *prefix;
3036*4882a593Smuzhiyun 
3037*4882a593Smuzhiyun 	if (route->control) {
3038*4882a593Smuzhiyun 		dev_err(dapm->dev,
3039*4882a593Smuzhiyun 			"ASoC: Removal of routes with controls not supported\n");
3040*4882a593Smuzhiyun 		return -EINVAL;
3041*4882a593Smuzhiyun 	}
3042*4882a593Smuzhiyun 
3043*4882a593Smuzhiyun 	prefix = soc_dapm_prefix(dapm);
3044*4882a593Smuzhiyun 	if (prefix) {
3045*4882a593Smuzhiyun 		snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
3046*4882a593Smuzhiyun 			 prefix, route->sink);
3047*4882a593Smuzhiyun 		sink = prefixed_sink;
3048*4882a593Smuzhiyun 		snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
3049*4882a593Smuzhiyun 			 prefix, route->source);
3050*4882a593Smuzhiyun 		source = prefixed_source;
3051*4882a593Smuzhiyun 	} else {
3052*4882a593Smuzhiyun 		sink = route->sink;
3053*4882a593Smuzhiyun 		source = route->source;
3054*4882a593Smuzhiyun 	}
3055*4882a593Smuzhiyun 
3056*4882a593Smuzhiyun 	path = NULL;
3057*4882a593Smuzhiyun 	list_for_each_entry(p, &dapm->card->paths, list) {
3058*4882a593Smuzhiyun 		if (strcmp(p->source->name, source) != 0)
3059*4882a593Smuzhiyun 			continue;
3060*4882a593Smuzhiyun 		if (strcmp(p->sink->name, sink) != 0)
3061*4882a593Smuzhiyun 			continue;
3062*4882a593Smuzhiyun 		path = p;
3063*4882a593Smuzhiyun 		break;
3064*4882a593Smuzhiyun 	}
3065*4882a593Smuzhiyun 
3066*4882a593Smuzhiyun 	if (path) {
3067*4882a593Smuzhiyun 		wsource = path->source;
3068*4882a593Smuzhiyun 		wsink = path->sink;
3069*4882a593Smuzhiyun 
3070*4882a593Smuzhiyun 		dapm_mark_dirty(wsource, "Route removed");
3071*4882a593Smuzhiyun 		dapm_mark_dirty(wsink, "Route removed");
3072*4882a593Smuzhiyun 		if (path->connect)
3073*4882a593Smuzhiyun 			dapm_path_invalidate(path);
3074*4882a593Smuzhiyun 
3075*4882a593Smuzhiyun 		dapm_free_path(path);
3076*4882a593Smuzhiyun 
3077*4882a593Smuzhiyun 		/* Update any path related flags */
3078*4882a593Smuzhiyun 		dapm_update_widget_flags(wsource);
3079*4882a593Smuzhiyun 		dapm_update_widget_flags(wsink);
3080*4882a593Smuzhiyun 	} else {
3081*4882a593Smuzhiyun 		dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
3082*4882a593Smuzhiyun 			 source, sink);
3083*4882a593Smuzhiyun 	}
3084*4882a593Smuzhiyun 
3085*4882a593Smuzhiyun 	return 0;
3086*4882a593Smuzhiyun }
3087*4882a593Smuzhiyun 
3088*4882a593Smuzhiyun /**
3089*4882a593Smuzhiyun  * snd_soc_dapm_add_routes - Add routes between DAPM widgets
3090*4882a593Smuzhiyun  * @dapm: DAPM context
3091*4882a593Smuzhiyun  * @route: audio routes
3092*4882a593Smuzhiyun  * @num: number of routes
3093*4882a593Smuzhiyun  *
3094*4882a593Smuzhiyun  * Connects 2 dapm widgets together via a named audio path. The sink is
3095*4882a593Smuzhiyun  * the widget receiving the audio signal, whilst the source is the sender
3096*4882a593Smuzhiyun  * of the audio signal.
3097*4882a593Smuzhiyun  *
3098*4882a593Smuzhiyun  * Returns 0 for success else error. On error all resources can be freed
3099*4882a593Smuzhiyun  * with a call to snd_soc_card_free().
3100*4882a593Smuzhiyun  */
snd_soc_dapm_add_routes(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_route * route,int num)3101*4882a593Smuzhiyun int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
3102*4882a593Smuzhiyun 			    const struct snd_soc_dapm_route *route, int num)
3103*4882a593Smuzhiyun {
3104*4882a593Smuzhiyun 	int i, r, ret = 0;
3105*4882a593Smuzhiyun 
3106*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3107*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
3108*4882a593Smuzhiyun 		r = snd_soc_dapm_add_route(dapm, route);
3109*4882a593Smuzhiyun 		if (r < 0) {
3110*4882a593Smuzhiyun 			dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
3111*4882a593Smuzhiyun 				route->source,
3112*4882a593Smuzhiyun 				route->control ? route->control : "direct",
3113*4882a593Smuzhiyun 				route->sink);
3114*4882a593Smuzhiyun 			ret = r;
3115*4882a593Smuzhiyun 		}
3116*4882a593Smuzhiyun 		route++;
3117*4882a593Smuzhiyun 	}
3118*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
3119*4882a593Smuzhiyun 
3120*4882a593Smuzhiyun 	return ret;
3121*4882a593Smuzhiyun }
3122*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
3123*4882a593Smuzhiyun 
3124*4882a593Smuzhiyun /**
3125*4882a593Smuzhiyun  * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
3126*4882a593Smuzhiyun  * @dapm: DAPM context
3127*4882a593Smuzhiyun  * @route: audio routes
3128*4882a593Smuzhiyun  * @num: number of routes
3129*4882a593Smuzhiyun  *
3130*4882a593Smuzhiyun  * Removes routes from the DAPM context.
3131*4882a593Smuzhiyun  */
snd_soc_dapm_del_routes(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_route * route,int num)3132*4882a593Smuzhiyun int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
3133*4882a593Smuzhiyun 			    const struct snd_soc_dapm_route *route, int num)
3134*4882a593Smuzhiyun {
3135*4882a593Smuzhiyun 	int i;
3136*4882a593Smuzhiyun 
3137*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3138*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
3139*4882a593Smuzhiyun 		snd_soc_dapm_del_route(dapm, route);
3140*4882a593Smuzhiyun 		route++;
3141*4882a593Smuzhiyun 	}
3142*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
3143*4882a593Smuzhiyun 
3144*4882a593Smuzhiyun 	return 0;
3145*4882a593Smuzhiyun }
3146*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
3147*4882a593Smuzhiyun 
snd_soc_dapm_weak_route(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_route * route)3148*4882a593Smuzhiyun static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
3149*4882a593Smuzhiyun 				   const struct snd_soc_dapm_route *route)
3150*4882a593Smuzhiyun {
3151*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
3152*4882a593Smuzhiyun 							      route->source,
3153*4882a593Smuzhiyun 							      true);
3154*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
3155*4882a593Smuzhiyun 							    route->sink,
3156*4882a593Smuzhiyun 							    true);
3157*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
3158*4882a593Smuzhiyun 	int count = 0;
3159*4882a593Smuzhiyun 
3160*4882a593Smuzhiyun 	if (!source) {
3161*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
3162*4882a593Smuzhiyun 			route->source);
3163*4882a593Smuzhiyun 		return -ENODEV;
3164*4882a593Smuzhiyun 	}
3165*4882a593Smuzhiyun 
3166*4882a593Smuzhiyun 	if (!sink) {
3167*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
3168*4882a593Smuzhiyun 			route->sink);
3169*4882a593Smuzhiyun 		return -ENODEV;
3170*4882a593Smuzhiyun 	}
3171*4882a593Smuzhiyun 
3172*4882a593Smuzhiyun 	if (route->control || route->connected)
3173*4882a593Smuzhiyun 		dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
3174*4882a593Smuzhiyun 			 route->source, route->sink);
3175*4882a593Smuzhiyun 
3176*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_sink_path(source, path) {
3177*4882a593Smuzhiyun 		if (path->sink == sink) {
3178*4882a593Smuzhiyun 			path->weak = 1;
3179*4882a593Smuzhiyun 			count++;
3180*4882a593Smuzhiyun 		}
3181*4882a593Smuzhiyun 	}
3182*4882a593Smuzhiyun 
3183*4882a593Smuzhiyun 	if (count == 0)
3184*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
3185*4882a593Smuzhiyun 			route->source, route->sink);
3186*4882a593Smuzhiyun 	if (count > 1)
3187*4882a593Smuzhiyun 		dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
3188*4882a593Smuzhiyun 			 count, route->source, route->sink);
3189*4882a593Smuzhiyun 
3190*4882a593Smuzhiyun 	return 0;
3191*4882a593Smuzhiyun }
3192*4882a593Smuzhiyun 
3193*4882a593Smuzhiyun /**
3194*4882a593Smuzhiyun  * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
3195*4882a593Smuzhiyun  * @dapm: DAPM context
3196*4882a593Smuzhiyun  * @route: audio routes
3197*4882a593Smuzhiyun  * @num: number of routes
3198*4882a593Smuzhiyun  *
3199*4882a593Smuzhiyun  * Mark existing routes matching those specified in the passed array
3200*4882a593Smuzhiyun  * as being weak, meaning that they are ignored for the purpose of
3201*4882a593Smuzhiyun  * power decisions.  The main intended use case is for sidetone paths
3202*4882a593Smuzhiyun  * which couple audio between other independent paths if they are both
3203*4882a593Smuzhiyun  * active in order to make the combination work better at the user
3204*4882a593Smuzhiyun  * level but which aren't intended to be "used".
3205*4882a593Smuzhiyun  *
3206*4882a593Smuzhiyun  * Note that CODEC drivers should not use this as sidetone type paths
3207*4882a593Smuzhiyun  * can frequently also be used as bypass paths.
3208*4882a593Smuzhiyun  */
snd_soc_dapm_weak_routes(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_route * route,int num)3209*4882a593Smuzhiyun int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
3210*4882a593Smuzhiyun 			     const struct snd_soc_dapm_route *route, int num)
3211*4882a593Smuzhiyun {
3212*4882a593Smuzhiyun 	int i, err;
3213*4882a593Smuzhiyun 	int ret = 0;
3214*4882a593Smuzhiyun 
3215*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
3216*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
3217*4882a593Smuzhiyun 		err = snd_soc_dapm_weak_route(dapm, route);
3218*4882a593Smuzhiyun 		if (err)
3219*4882a593Smuzhiyun 			ret = err;
3220*4882a593Smuzhiyun 		route++;
3221*4882a593Smuzhiyun 	}
3222*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
3223*4882a593Smuzhiyun 
3224*4882a593Smuzhiyun 	return ret;
3225*4882a593Smuzhiyun }
3226*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
3227*4882a593Smuzhiyun 
3228*4882a593Smuzhiyun /**
3229*4882a593Smuzhiyun  * snd_soc_dapm_new_widgets - add new dapm widgets
3230*4882a593Smuzhiyun  * @card: card to be checked for new dapm widgets
3231*4882a593Smuzhiyun  *
3232*4882a593Smuzhiyun  * Checks the codec for any new dapm widgets and creates them if found.
3233*4882a593Smuzhiyun  *
3234*4882a593Smuzhiyun  * Returns 0 for success.
3235*4882a593Smuzhiyun  */
snd_soc_dapm_new_widgets(struct snd_soc_card * card)3236*4882a593Smuzhiyun int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
3237*4882a593Smuzhiyun {
3238*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
3239*4882a593Smuzhiyun 	unsigned int val;
3240*4882a593Smuzhiyun 
3241*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
3242*4882a593Smuzhiyun 
3243*4882a593Smuzhiyun 	for_each_card_widgets(card, w)
3244*4882a593Smuzhiyun 	{
3245*4882a593Smuzhiyun 		if (w->new)
3246*4882a593Smuzhiyun 			continue;
3247*4882a593Smuzhiyun 
3248*4882a593Smuzhiyun 		if (w->num_kcontrols) {
3249*4882a593Smuzhiyun 			w->kcontrols = kcalloc(w->num_kcontrols,
3250*4882a593Smuzhiyun 						sizeof(struct snd_kcontrol *),
3251*4882a593Smuzhiyun 						GFP_KERNEL);
3252*4882a593Smuzhiyun 			if (!w->kcontrols) {
3253*4882a593Smuzhiyun 				mutex_unlock(&card->dapm_mutex);
3254*4882a593Smuzhiyun 				return -ENOMEM;
3255*4882a593Smuzhiyun 			}
3256*4882a593Smuzhiyun 		}
3257*4882a593Smuzhiyun 
3258*4882a593Smuzhiyun 		switch(w->id) {
3259*4882a593Smuzhiyun 		case snd_soc_dapm_switch:
3260*4882a593Smuzhiyun 		case snd_soc_dapm_mixer:
3261*4882a593Smuzhiyun 		case snd_soc_dapm_mixer_named_ctl:
3262*4882a593Smuzhiyun 			dapm_new_mixer(w);
3263*4882a593Smuzhiyun 			break;
3264*4882a593Smuzhiyun 		case snd_soc_dapm_mux:
3265*4882a593Smuzhiyun 		case snd_soc_dapm_demux:
3266*4882a593Smuzhiyun 			dapm_new_mux(w);
3267*4882a593Smuzhiyun 			break;
3268*4882a593Smuzhiyun 		case snd_soc_dapm_pga:
3269*4882a593Smuzhiyun 		case snd_soc_dapm_effect:
3270*4882a593Smuzhiyun 		case snd_soc_dapm_out_drv:
3271*4882a593Smuzhiyun 			dapm_new_pga(w);
3272*4882a593Smuzhiyun 			break;
3273*4882a593Smuzhiyun 		case snd_soc_dapm_dai_link:
3274*4882a593Smuzhiyun 			dapm_new_dai_link(w);
3275*4882a593Smuzhiyun 			break;
3276*4882a593Smuzhiyun 		default:
3277*4882a593Smuzhiyun 			break;
3278*4882a593Smuzhiyun 		}
3279*4882a593Smuzhiyun 
3280*4882a593Smuzhiyun 		/* Read the initial power state from the device */
3281*4882a593Smuzhiyun 		if (w->reg >= 0) {
3282*4882a593Smuzhiyun 			val = soc_dapm_read(w->dapm, w->reg);
3283*4882a593Smuzhiyun 			val = val >> w->shift;
3284*4882a593Smuzhiyun 			val &= w->mask;
3285*4882a593Smuzhiyun 			if (val == w->on_val)
3286*4882a593Smuzhiyun 				w->power = 1;
3287*4882a593Smuzhiyun 		}
3288*4882a593Smuzhiyun 
3289*4882a593Smuzhiyun 		w->new = 1;
3290*4882a593Smuzhiyun 
3291*4882a593Smuzhiyun 		dapm_mark_dirty(w, "new widget");
3292*4882a593Smuzhiyun 		dapm_debugfs_add_widget(w);
3293*4882a593Smuzhiyun 	}
3294*4882a593Smuzhiyun 
3295*4882a593Smuzhiyun 	dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
3296*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
3297*4882a593Smuzhiyun 	return 0;
3298*4882a593Smuzhiyun }
3299*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
3300*4882a593Smuzhiyun 
3301*4882a593Smuzhiyun /**
3302*4882a593Smuzhiyun  * snd_soc_dapm_get_volsw - dapm mixer get callback
3303*4882a593Smuzhiyun  * @kcontrol: mixer control
3304*4882a593Smuzhiyun  * @ucontrol: control element information
3305*4882a593Smuzhiyun  *
3306*4882a593Smuzhiyun  * Callback to get the value of a dapm mixer control.
3307*4882a593Smuzhiyun  *
3308*4882a593Smuzhiyun  * Returns 0 for success.
3309*4882a593Smuzhiyun  */
snd_soc_dapm_get_volsw(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3310*4882a593Smuzhiyun int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
3311*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
3312*4882a593Smuzhiyun {
3313*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3314*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
3315*4882a593Smuzhiyun 	struct soc_mixer_control *mc =
3316*4882a593Smuzhiyun 		(struct soc_mixer_control *)kcontrol->private_value;
3317*4882a593Smuzhiyun 	int reg = mc->reg;
3318*4882a593Smuzhiyun 	unsigned int shift = mc->shift;
3319*4882a593Smuzhiyun 	int max = mc->max;
3320*4882a593Smuzhiyun 	unsigned int width = fls(max);
3321*4882a593Smuzhiyun 	unsigned int mask = (1 << fls(max)) - 1;
3322*4882a593Smuzhiyun 	unsigned int invert = mc->invert;
3323*4882a593Smuzhiyun 	unsigned int reg_val, val, rval = 0;
3324*4882a593Smuzhiyun 
3325*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3326*4882a593Smuzhiyun 	if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
3327*4882a593Smuzhiyun 		reg_val = soc_dapm_read(dapm, reg);
3328*4882a593Smuzhiyun 		val = (reg_val >> shift) & mask;
3329*4882a593Smuzhiyun 
3330*4882a593Smuzhiyun 		if (reg != mc->rreg)
3331*4882a593Smuzhiyun 			reg_val = soc_dapm_read(dapm, mc->rreg);
3332*4882a593Smuzhiyun 
3333*4882a593Smuzhiyun 		if (snd_soc_volsw_is_stereo(mc))
3334*4882a593Smuzhiyun 			rval = (reg_val >> mc->rshift) & mask;
3335*4882a593Smuzhiyun 	} else {
3336*4882a593Smuzhiyun 		reg_val = dapm_kcontrol_get_value(kcontrol);
3337*4882a593Smuzhiyun 		val = reg_val & mask;
3338*4882a593Smuzhiyun 
3339*4882a593Smuzhiyun 		if (snd_soc_volsw_is_stereo(mc))
3340*4882a593Smuzhiyun 			rval = (reg_val >> width) & mask;
3341*4882a593Smuzhiyun 	}
3342*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
3343*4882a593Smuzhiyun 
3344*4882a593Smuzhiyun 	if (invert)
3345*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = max - val;
3346*4882a593Smuzhiyun 	else
3347*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = val;
3348*4882a593Smuzhiyun 
3349*4882a593Smuzhiyun 	if (snd_soc_volsw_is_stereo(mc)) {
3350*4882a593Smuzhiyun 		if (invert)
3351*4882a593Smuzhiyun 			ucontrol->value.integer.value[1] = max - rval;
3352*4882a593Smuzhiyun 		else
3353*4882a593Smuzhiyun 			ucontrol->value.integer.value[1] = rval;
3354*4882a593Smuzhiyun 	}
3355*4882a593Smuzhiyun 
3356*4882a593Smuzhiyun 	return 0;
3357*4882a593Smuzhiyun }
3358*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3359*4882a593Smuzhiyun 
3360*4882a593Smuzhiyun /**
3361*4882a593Smuzhiyun  * snd_soc_dapm_put_volsw - dapm mixer set callback
3362*4882a593Smuzhiyun  * @kcontrol: mixer control
3363*4882a593Smuzhiyun  * @ucontrol: control element information
3364*4882a593Smuzhiyun  *
3365*4882a593Smuzhiyun  * Callback to set the value of a dapm mixer control.
3366*4882a593Smuzhiyun  *
3367*4882a593Smuzhiyun  * Returns 0 for success.
3368*4882a593Smuzhiyun  */
snd_soc_dapm_put_volsw(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3369*4882a593Smuzhiyun int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3370*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
3371*4882a593Smuzhiyun {
3372*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3373*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
3374*4882a593Smuzhiyun 	struct soc_mixer_control *mc =
3375*4882a593Smuzhiyun 		(struct soc_mixer_control *)kcontrol->private_value;
3376*4882a593Smuzhiyun 	int reg = mc->reg;
3377*4882a593Smuzhiyun 	unsigned int shift = mc->shift;
3378*4882a593Smuzhiyun 	int max = mc->max;
3379*4882a593Smuzhiyun 	unsigned int width = fls(max);
3380*4882a593Smuzhiyun 	unsigned int mask = (1 << width) - 1;
3381*4882a593Smuzhiyun 	unsigned int invert = mc->invert;
3382*4882a593Smuzhiyun 	unsigned int val, rval = 0;
3383*4882a593Smuzhiyun 	int connect, rconnect = -1, change, reg_change = 0;
3384*4882a593Smuzhiyun 	struct snd_soc_dapm_update update = {};
3385*4882a593Smuzhiyun 	int ret = 0;
3386*4882a593Smuzhiyun 
3387*4882a593Smuzhiyun 	val = (ucontrol->value.integer.value[0] & mask);
3388*4882a593Smuzhiyun 	connect = !!val;
3389*4882a593Smuzhiyun 
3390*4882a593Smuzhiyun 	if (invert)
3391*4882a593Smuzhiyun 		val = max - val;
3392*4882a593Smuzhiyun 
3393*4882a593Smuzhiyun 	if (snd_soc_volsw_is_stereo(mc)) {
3394*4882a593Smuzhiyun 		rval = (ucontrol->value.integer.value[1] & mask);
3395*4882a593Smuzhiyun 		rconnect = !!rval;
3396*4882a593Smuzhiyun 		if (invert)
3397*4882a593Smuzhiyun 			rval = max - rval;
3398*4882a593Smuzhiyun 	}
3399*4882a593Smuzhiyun 
3400*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3401*4882a593Smuzhiyun 
3402*4882a593Smuzhiyun 	/* This assumes field width < (bits in unsigned int / 2) */
3403*4882a593Smuzhiyun 	if (width > sizeof(unsigned int) * 8 / 2)
3404*4882a593Smuzhiyun 		dev_warn(dapm->dev,
3405*4882a593Smuzhiyun 			 "ASoC: control %s field width limit exceeded\n",
3406*4882a593Smuzhiyun 			 kcontrol->id.name);
3407*4882a593Smuzhiyun 	change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
3408*4882a593Smuzhiyun 
3409*4882a593Smuzhiyun 	if (reg != SND_SOC_NOPM) {
3410*4882a593Smuzhiyun 		val = val << shift;
3411*4882a593Smuzhiyun 		rval = rval << mc->rshift;
3412*4882a593Smuzhiyun 
3413*4882a593Smuzhiyun 		reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
3414*4882a593Smuzhiyun 
3415*4882a593Smuzhiyun 		if (snd_soc_volsw_is_stereo(mc))
3416*4882a593Smuzhiyun 			reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
3417*4882a593Smuzhiyun 							 mask << mc->rshift,
3418*4882a593Smuzhiyun 							 rval);
3419*4882a593Smuzhiyun 	}
3420*4882a593Smuzhiyun 
3421*4882a593Smuzhiyun 	if (change || reg_change) {
3422*4882a593Smuzhiyun 		if (reg_change) {
3423*4882a593Smuzhiyun 			if (snd_soc_volsw_is_stereo(mc)) {
3424*4882a593Smuzhiyun 				update.has_second_set = true;
3425*4882a593Smuzhiyun 				update.reg2 = mc->rreg;
3426*4882a593Smuzhiyun 				update.mask2 = mask << mc->rshift;
3427*4882a593Smuzhiyun 				update.val2 = rval;
3428*4882a593Smuzhiyun 			}
3429*4882a593Smuzhiyun 			update.kcontrol = kcontrol;
3430*4882a593Smuzhiyun 			update.reg = reg;
3431*4882a593Smuzhiyun 			update.mask = mask << shift;
3432*4882a593Smuzhiyun 			update.val = val;
3433*4882a593Smuzhiyun 			card->update = &update;
3434*4882a593Smuzhiyun 		}
3435*4882a593Smuzhiyun 
3436*4882a593Smuzhiyun 		ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
3437*4882a593Smuzhiyun 						  rconnect);
3438*4882a593Smuzhiyun 
3439*4882a593Smuzhiyun 		card->update = NULL;
3440*4882a593Smuzhiyun 	}
3441*4882a593Smuzhiyun 
3442*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
3443*4882a593Smuzhiyun 
3444*4882a593Smuzhiyun 	if (ret > 0)
3445*4882a593Smuzhiyun 		snd_soc_dpcm_runtime_update(card);
3446*4882a593Smuzhiyun 
3447*4882a593Smuzhiyun 	return change;
3448*4882a593Smuzhiyun }
3449*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3450*4882a593Smuzhiyun 
3451*4882a593Smuzhiyun /**
3452*4882a593Smuzhiyun  * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3453*4882a593Smuzhiyun  * @kcontrol: mixer control
3454*4882a593Smuzhiyun  * @ucontrol: control element information
3455*4882a593Smuzhiyun  *
3456*4882a593Smuzhiyun  * Callback to get the value of a dapm enumerated double mixer control.
3457*4882a593Smuzhiyun  *
3458*4882a593Smuzhiyun  * Returns 0 for success.
3459*4882a593Smuzhiyun  */
snd_soc_dapm_get_enum_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3460*4882a593Smuzhiyun int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3461*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
3462*4882a593Smuzhiyun {
3463*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3464*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
3465*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3466*4882a593Smuzhiyun 	unsigned int reg_val, val;
3467*4882a593Smuzhiyun 
3468*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3469*4882a593Smuzhiyun 	if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
3470*4882a593Smuzhiyun 		reg_val = soc_dapm_read(dapm, e->reg);
3471*4882a593Smuzhiyun 	} else {
3472*4882a593Smuzhiyun 		reg_val = dapm_kcontrol_get_value(kcontrol);
3473*4882a593Smuzhiyun 	}
3474*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
3475*4882a593Smuzhiyun 
3476*4882a593Smuzhiyun 	val = (reg_val >> e->shift_l) & e->mask;
3477*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3478*4882a593Smuzhiyun 	if (e->shift_l != e->shift_r) {
3479*4882a593Smuzhiyun 		val = (reg_val >> e->shift_r) & e->mask;
3480*4882a593Smuzhiyun 		val = snd_soc_enum_val_to_item(e, val);
3481*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[1] = val;
3482*4882a593Smuzhiyun 	}
3483*4882a593Smuzhiyun 
3484*4882a593Smuzhiyun 	return 0;
3485*4882a593Smuzhiyun }
3486*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3487*4882a593Smuzhiyun 
3488*4882a593Smuzhiyun /**
3489*4882a593Smuzhiyun  * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3490*4882a593Smuzhiyun  * @kcontrol: mixer control
3491*4882a593Smuzhiyun  * @ucontrol: control element information
3492*4882a593Smuzhiyun  *
3493*4882a593Smuzhiyun  * Callback to set the value of a dapm enumerated double mixer control.
3494*4882a593Smuzhiyun  *
3495*4882a593Smuzhiyun  * Returns 0 for success.
3496*4882a593Smuzhiyun  */
snd_soc_dapm_put_enum_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3497*4882a593Smuzhiyun int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3498*4882a593Smuzhiyun 	struct snd_ctl_elem_value *ucontrol)
3499*4882a593Smuzhiyun {
3500*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3501*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
3502*4882a593Smuzhiyun 	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
3503*4882a593Smuzhiyun 	unsigned int *item = ucontrol->value.enumerated.item;
3504*4882a593Smuzhiyun 	unsigned int val, change, reg_change = 0;
3505*4882a593Smuzhiyun 	unsigned int mask;
3506*4882a593Smuzhiyun 	struct snd_soc_dapm_update update = {};
3507*4882a593Smuzhiyun 	int ret = 0;
3508*4882a593Smuzhiyun 
3509*4882a593Smuzhiyun 	if (item[0] >= e->items)
3510*4882a593Smuzhiyun 		return -EINVAL;
3511*4882a593Smuzhiyun 
3512*4882a593Smuzhiyun 	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
3513*4882a593Smuzhiyun 	mask = e->mask << e->shift_l;
3514*4882a593Smuzhiyun 	if (e->shift_l != e->shift_r) {
3515*4882a593Smuzhiyun 		if (item[1] > e->items)
3516*4882a593Smuzhiyun 			return -EINVAL;
3517*4882a593Smuzhiyun 		val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
3518*4882a593Smuzhiyun 		mask |= e->mask << e->shift_r;
3519*4882a593Smuzhiyun 	}
3520*4882a593Smuzhiyun 
3521*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3522*4882a593Smuzhiyun 
3523*4882a593Smuzhiyun 	change = dapm_kcontrol_set_value(kcontrol, val);
3524*4882a593Smuzhiyun 
3525*4882a593Smuzhiyun 	if (e->reg != SND_SOC_NOPM)
3526*4882a593Smuzhiyun 		reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3527*4882a593Smuzhiyun 
3528*4882a593Smuzhiyun 	if (change || reg_change) {
3529*4882a593Smuzhiyun 		if (reg_change) {
3530*4882a593Smuzhiyun 			update.kcontrol = kcontrol;
3531*4882a593Smuzhiyun 			update.reg = e->reg;
3532*4882a593Smuzhiyun 			update.mask = mask;
3533*4882a593Smuzhiyun 			update.val = val;
3534*4882a593Smuzhiyun 			card->update = &update;
3535*4882a593Smuzhiyun 		}
3536*4882a593Smuzhiyun 
3537*4882a593Smuzhiyun 		ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
3538*4882a593Smuzhiyun 
3539*4882a593Smuzhiyun 		card->update = NULL;
3540*4882a593Smuzhiyun 	}
3541*4882a593Smuzhiyun 
3542*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
3543*4882a593Smuzhiyun 
3544*4882a593Smuzhiyun 	if (ret > 0)
3545*4882a593Smuzhiyun 		snd_soc_dpcm_runtime_update(card);
3546*4882a593Smuzhiyun 
3547*4882a593Smuzhiyun 	return change;
3548*4882a593Smuzhiyun }
3549*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3550*4882a593Smuzhiyun 
3551*4882a593Smuzhiyun /**
3552*4882a593Smuzhiyun  * snd_soc_dapm_info_pin_switch - Info for a pin switch
3553*4882a593Smuzhiyun  *
3554*4882a593Smuzhiyun  * @kcontrol: mixer control
3555*4882a593Smuzhiyun  * @uinfo: control element information
3556*4882a593Smuzhiyun  *
3557*4882a593Smuzhiyun  * Callback to provide information about a pin switch control.
3558*4882a593Smuzhiyun  */
snd_soc_dapm_info_pin_switch(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3559*4882a593Smuzhiyun int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3560*4882a593Smuzhiyun 				 struct snd_ctl_elem_info *uinfo)
3561*4882a593Smuzhiyun {
3562*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3563*4882a593Smuzhiyun 	uinfo->count = 1;
3564*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
3565*4882a593Smuzhiyun 	uinfo->value.integer.max = 1;
3566*4882a593Smuzhiyun 
3567*4882a593Smuzhiyun 	return 0;
3568*4882a593Smuzhiyun }
3569*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3570*4882a593Smuzhiyun 
3571*4882a593Smuzhiyun /**
3572*4882a593Smuzhiyun  * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3573*4882a593Smuzhiyun  *
3574*4882a593Smuzhiyun  * @kcontrol: mixer control
3575*4882a593Smuzhiyun  * @ucontrol: Value
3576*4882a593Smuzhiyun  */
snd_soc_dapm_get_pin_switch(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3577*4882a593Smuzhiyun int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3578*4882a593Smuzhiyun 				struct snd_ctl_elem_value *ucontrol)
3579*4882a593Smuzhiyun {
3580*4882a593Smuzhiyun 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
3581*4882a593Smuzhiyun 	const char *pin = (const char *)kcontrol->private_value;
3582*4882a593Smuzhiyun 
3583*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3584*4882a593Smuzhiyun 
3585*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] =
3586*4882a593Smuzhiyun 		snd_soc_dapm_get_pin_status(&card->dapm, pin);
3587*4882a593Smuzhiyun 
3588*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
3589*4882a593Smuzhiyun 
3590*4882a593Smuzhiyun 	return 0;
3591*4882a593Smuzhiyun }
3592*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3593*4882a593Smuzhiyun 
3594*4882a593Smuzhiyun /**
3595*4882a593Smuzhiyun  * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3596*4882a593Smuzhiyun  *
3597*4882a593Smuzhiyun  * @kcontrol: mixer control
3598*4882a593Smuzhiyun  * @ucontrol: Value
3599*4882a593Smuzhiyun  */
snd_soc_dapm_put_pin_switch(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3600*4882a593Smuzhiyun int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3601*4882a593Smuzhiyun 				struct snd_ctl_elem_value *ucontrol)
3602*4882a593Smuzhiyun {
3603*4882a593Smuzhiyun 	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
3604*4882a593Smuzhiyun 	const char *pin = (const char *)kcontrol->private_value;
3605*4882a593Smuzhiyun 	int ret;
3606*4882a593Smuzhiyun 
3607*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3608*4882a593Smuzhiyun 	ret = __snd_soc_dapm_set_pin(&card->dapm, pin,
3609*4882a593Smuzhiyun 				     !!ucontrol->value.integer.value[0]);
3610*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
3611*4882a593Smuzhiyun 
3612*4882a593Smuzhiyun 	snd_soc_dapm_sync(&card->dapm);
3613*4882a593Smuzhiyun 	return ret;
3614*4882a593Smuzhiyun }
3615*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3616*4882a593Smuzhiyun 
3617*4882a593Smuzhiyun struct snd_soc_dapm_widget *
snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_widget * widget)3618*4882a593Smuzhiyun snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
3619*4882a593Smuzhiyun 			 const struct snd_soc_dapm_widget *widget)
3620*4882a593Smuzhiyun {
3621*4882a593Smuzhiyun 	enum snd_soc_dapm_direction dir;
3622*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
3623*4882a593Smuzhiyun 	const char *prefix;
3624*4882a593Smuzhiyun 	int ret;
3625*4882a593Smuzhiyun 
3626*4882a593Smuzhiyun 	if ((w = dapm_cnew_widget(widget)) == NULL)
3627*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
3628*4882a593Smuzhiyun 
3629*4882a593Smuzhiyun 	switch (w->id) {
3630*4882a593Smuzhiyun 	case snd_soc_dapm_regulator_supply:
3631*4882a593Smuzhiyun 		w->regulator = devm_regulator_get(dapm->dev, w->name);
3632*4882a593Smuzhiyun 		if (IS_ERR(w->regulator)) {
3633*4882a593Smuzhiyun 			ret = PTR_ERR(w->regulator);
3634*4882a593Smuzhiyun 			goto request_failed;
3635*4882a593Smuzhiyun 		}
3636*4882a593Smuzhiyun 
3637*4882a593Smuzhiyun 		if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
3638*4882a593Smuzhiyun 			ret = regulator_allow_bypass(w->regulator, true);
3639*4882a593Smuzhiyun 			if (ret != 0)
3640*4882a593Smuzhiyun 				dev_warn(dapm->dev,
3641*4882a593Smuzhiyun 					 "ASoC: Failed to bypass %s: %d\n",
3642*4882a593Smuzhiyun 					 w->name, ret);
3643*4882a593Smuzhiyun 		}
3644*4882a593Smuzhiyun 		break;
3645*4882a593Smuzhiyun 	case snd_soc_dapm_pinctrl:
3646*4882a593Smuzhiyun 		w->pinctrl = devm_pinctrl_get(dapm->dev);
3647*4882a593Smuzhiyun 		if (IS_ERR(w->pinctrl)) {
3648*4882a593Smuzhiyun 			ret = PTR_ERR(w->pinctrl);
3649*4882a593Smuzhiyun 			goto request_failed;
3650*4882a593Smuzhiyun 		}
3651*4882a593Smuzhiyun 
3652*4882a593Smuzhiyun 		/* set to sleep_state when initializing */
3653*4882a593Smuzhiyun 		dapm_pinctrl_event(w, NULL, SND_SOC_DAPM_POST_PMD);
3654*4882a593Smuzhiyun 		break;
3655*4882a593Smuzhiyun 	case snd_soc_dapm_clock_supply:
3656*4882a593Smuzhiyun 		w->clk = devm_clk_get(dapm->dev, w->name);
3657*4882a593Smuzhiyun 		if (IS_ERR(w->clk)) {
3658*4882a593Smuzhiyun 			ret = PTR_ERR(w->clk);
3659*4882a593Smuzhiyun 			goto request_failed;
3660*4882a593Smuzhiyun 		}
3661*4882a593Smuzhiyun 		break;
3662*4882a593Smuzhiyun 	default:
3663*4882a593Smuzhiyun 		break;
3664*4882a593Smuzhiyun 	}
3665*4882a593Smuzhiyun 
3666*4882a593Smuzhiyun 	prefix = soc_dapm_prefix(dapm);
3667*4882a593Smuzhiyun 	if (prefix)
3668*4882a593Smuzhiyun 		w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
3669*4882a593Smuzhiyun 	else
3670*4882a593Smuzhiyun 		w->name = kstrdup_const(widget->name, GFP_KERNEL);
3671*4882a593Smuzhiyun 	if (w->name == NULL) {
3672*4882a593Smuzhiyun 		kfree_const(w->sname);
3673*4882a593Smuzhiyun 		kfree(w);
3674*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
3675*4882a593Smuzhiyun 	}
3676*4882a593Smuzhiyun 
3677*4882a593Smuzhiyun 	switch (w->id) {
3678*4882a593Smuzhiyun 	case snd_soc_dapm_mic:
3679*4882a593Smuzhiyun 		w->is_ep = SND_SOC_DAPM_EP_SOURCE;
3680*4882a593Smuzhiyun 		w->power_check = dapm_generic_check_power;
3681*4882a593Smuzhiyun 		break;
3682*4882a593Smuzhiyun 	case snd_soc_dapm_input:
3683*4882a593Smuzhiyun 		if (!dapm->card->fully_routed)
3684*4882a593Smuzhiyun 			w->is_ep = SND_SOC_DAPM_EP_SOURCE;
3685*4882a593Smuzhiyun 		w->power_check = dapm_generic_check_power;
3686*4882a593Smuzhiyun 		break;
3687*4882a593Smuzhiyun 	case snd_soc_dapm_spk:
3688*4882a593Smuzhiyun 	case snd_soc_dapm_hp:
3689*4882a593Smuzhiyun 		w->is_ep = SND_SOC_DAPM_EP_SINK;
3690*4882a593Smuzhiyun 		w->power_check = dapm_generic_check_power;
3691*4882a593Smuzhiyun 		break;
3692*4882a593Smuzhiyun 	case snd_soc_dapm_output:
3693*4882a593Smuzhiyun 		if (!dapm->card->fully_routed)
3694*4882a593Smuzhiyun 			w->is_ep = SND_SOC_DAPM_EP_SINK;
3695*4882a593Smuzhiyun 		w->power_check = dapm_generic_check_power;
3696*4882a593Smuzhiyun 		break;
3697*4882a593Smuzhiyun 	case snd_soc_dapm_vmid:
3698*4882a593Smuzhiyun 	case snd_soc_dapm_siggen:
3699*4882a593Smuzhiyun 		w->is_ep = SND_SOC_DAPM_EP_SOURCE;
3700*4882a593Smuzhiyun 		w->power_check = dapm_always_on_check_power;
3701*4882a593Smuzhiyun 		break;
3702*4882a593Smuzhiyun 	case snd_soc_dapm_sink:
3703*4882a593Smuzhiyun 		w->is_ep = SND_SOC_DAPM_EP_SINK;
3704*4882a593Smuzhiyun 		w->power_check = dapm_always_on_check_power;
3705*4882a593Smuzhiyun 		break;
3706*4882a593Smuzhiyun 
3707*4882a593Smuzhiyun 	case snd_soc_dapm_mux:
3708*4882a593Smuzhiyun 	case snd_soc_dapm_demux:
3709*4882a593Smuzhiyun 	case snd_soc_dapm_switch:
3710*4882a593Smuzhiyun 	case snd_soc_dapm_mixer:
3711*4882a593Smuzhiyun 	case snd_soc_dapm_mixer_named_ctl:
3712*4882a593Smuzhiyun 	case snd_soc_dapm_adc:
3713*4882a593Smuzhiyun 	case snd_soc_dapm_aif_out:
3714*4882a593Smuzhiyun 	case snd_soc_dapm_dac:
3715*4882a593Smuzhiyun 	case snd_soc_dapm_aif_in:
3716*4882a593Smuzhiyun 	case snd_soc_dapm_pga:
3717*4882a593Smuzhiyun 	case snd_soc_dapm_buffer:
3718*4882a593Smuzhiyun 	case snd_soc_dapm_scheduler:
3719*4882a593Smuzhiyun 	case snd_soc_dapm_effect:
3720*4882a593Smuzhiyun 	case snd_soc_dapm_src:
3721*4882a593Smuzhiyun 	case snd_soc_dapm_asrc:
3722*4882a593Smuzhiyun 	case snd_soc_dapm_encoder:
3723*4882a593Smuzhiyun 	case snd_soc_dapm_decoder:
3724*4882a593Smuzhiyun 	case snd_soc_dapm_out_drv:
3725*4882a593Smuzhiyun 	case snd_soc_dapm_micbias:
3726*4882a593Smuzhiyun 	case snd_soc_dapm_line:
3727*4882a593Smuzhiyun 	case snd_soc_dapm_dai_link:
3728*4882a593Smuzhiyun 	case snd_soc_dapm_dai_out:
3729*4882a593Smuzhiyun 	case snd_soc_dapm_dai_in:
3730*4882a593Smuzhiyun 		w->power_check = dapm_generic_check_power;
3731*4882a593Smuzhiyun 		break;
3732*4882a593Smuzhiyun 	case snd_soc_dapm_supply:
3733*4882a593Smuzhiyun 	case snd_soc_dapm_regulator_supply:
3734*4882a593Smuzhiyun 	case snd_soc_dapm_pinctrl:
3735*4882a593Smuzhiyun 	case snd_soc_dapm_clock_supply:
3736*4882a593Smuzhiyun 	case snd_soc_dapm_kcontrol:
3737*4882a593Smuzhiyun 		w->is_supply = 1;
3738*4882a593Smuzhiyun 		w->power_check = dapm_supply_check_power;
3739*4882a593Smuzhiyun 		break;
3740*4882a593Smuzhiyun 	default:
3741*4882a593Smuzhiyun 		w->power_check = dapm_always_on_check_power;
3742*4882a593Smuzhiyun 		break;
3743*4882a593Smuzhiyun 	}
3744*4882a593Smuzhiyun 
3745*4882a593Smuzhiyun 	w->dapm = dapm;
3746*4882a593Smuzhiyun 	INIT_LIST_HEAD(&w->list);
3747*4882a593Smuzhiyun 	INIT_LIST_HEAD(&w->dirty);
3748*4882a593Smuzhiyun 	/* see for_each_card_widgets */
3749*4882a593Smuzhiyun 	list_add_tail(&w->list, &dapm->card->widgets);
3750*4882a593Smuzhiyun 
3751*4882a593Smuzhiyun 	snd_soc_dapm_for_each_direction(dir) {
3752*4882a593Smuzhiyun 		INIT_LIST_HEAD(&w->edges[dir]);
3753*4882a593Smuzhiyun 		w->endpoints[dir] = -1;
3754*4882a593Smuzhiyun 	}
3755*4882a593Smuzhiyun 
3756*4882a593Smuzhiyun 	/* machine layer sets up unconnected pins and insertions */
3757*4882a593Smuzhiyun 	w->connected = 1;
3758*4882a593Smuzhiyun 	return w;
3759*4882a593Smuzhiyun 
3760*4882a593Smuzhiyun request_failed:
3761*4882a593Smuzhiyun 	if (ret != -EPROBE_DEFER)
3762*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
3763*4882a593Smuzhiyun 			w->name, ret);
3764*4882a593Smuzhiyun 
3765*4882a593Smuzhiyun 	kfree_const(w->sname);
3766*4882a593Smuzhiyun 	kfree(w);
3767*4882a593Smuzhiyun 	return ERR_PTR(ret);
3768*4882a593Smuzhiyun }
3769*4882a593Smuzhiyun 
3770*4882a593Smuzhiyun /**
3771*4882a593Smuzhiyun  * snd_soc_dapm_new_control - create new dapm control
3772*4882a593Smuzhiyun  * @dapm: DAPM context
3773*4882a593Smuzhiyun  * @widget: widget template
3774*4882a593Smuzhiyun  *
3775*4882a593Smuzhiyun  * Creates new DAPM control based upon a template.
3776*4882a593Smuzhiyun  *
3777*4882a593Smuzhiyun  * Returns a widget pointer on success or an error pointer on failure
3778*4882a593Smuzhiyun  */
3779*4882a593Smuzhiyun struct snd_soc_dapm_widget *
snd_soc_dapm_new_control(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_widget * widget)3780*4882a593Smuzhiyun snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3781*4882a593Smuzhiyun 			 const struct snd_soc_dapm_widget *widget)
3782*4882a593Smuzhiyun {
3783*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
3784*4882a593Smuzhiyun 
3785*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3786*4882a593Smuzhiyun 	w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3787*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
3788*4882a593Smuzhiyun 
3789*4882a593Smuzhiyun 	return w;
3790*4882a593Smuzhiyun }
3791*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
3792*4882a593Smuzhiyun 
3793*4882a593Smuzhiyun /**
3794*4882a593Smuzhiyun  * snd_soc_dapm_new_controls - create new dapm controls
3795*4882a593Smuzhiyun  * @dapm: DAPM context
3796*4882a593Smuzhiyun  * @widget: widget array
3797*4882a593Smuzhiyun  * @num: number of widgets
3798*4882a593Smuzhiyun  *
3799*4882a593Smuzhiyun  * Creates new DAPM controls based upon the templates.
3800*4882a593Smuzhiyun  *
3801*4882a593Smuzhiyun  * Returns 0 for success else error.
3802*4882a593Smuzhiyun  */
snd_soc_dapm_new_controls(struct snd_soc_dapm_context * dapm,const struct snd_soc_dapm_widget * widget,int num)3803*4882a593Smuzhiyun int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
3804*4882a593Smuzhiyun 	const struct snd_soc_dapm_widget *widget,
3805*4882a593Smuzhiyun 	int num)
3806*4882a593Smuzhiyun {
3807*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
3808*4882a593Smuzhiyun 	int i;
3809*4882a593Smuzhiyun 	int ret = 0;
3810*4882a593Smuzhiyun 
3811*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
3812*4882a593Smuzhiyun 	for (i = 0; i < num; i++) {
3813*4882a593Smuzhiyun 		w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3814*4882a593Smuzhiyun 		if (IS_ERR(w)) {
3815*4882a593Smuzhiyun 			ret = PTR_ERR(w);
3816*4882a593Smuzhiyun 			break;
3817*4882a593Smuzhiyun 		}
3818*4882a593Smuzhiyun 		widget++;
3819*4882a593Smuzhiyun 	}
3820*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
3821*4882a593Smuzhiyun 	return ret;
3822*4882a593Smuzhiyun }
3823*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3824*4882a593Smuzhiyun 
3825*4882a593Smuzhiyun static int
snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget * w,struct snd_pcm_substream * substream)3826*4882a593Smuzhiyun snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
3827*4882a593Smuzhiyun 			       struct snd_pcm_substream *substream)
3828*4882a593Smuzhiyun {
3829*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
3830*4882a593Smuzhiyun 	struct snd_soc_dai *source, *sink;
3831*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
3832*4882a593Smuzhiyun 	struct snd_pcm_hw_params *params = NULL;
3833*4882a593Smuzhiyun 	const struct snd_soc_pcm_stream *config = NULL;
3834*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = NULL;
3835*4882a593Smuzhiyun 	unsigned int fmt;
3836*4882a593Smuzhiyun 	int ret = 0;
3837*4882a593Smuzhiyun 
3838*4882a593Smuzhiyun 	params = kzalloc(sizeof(*params), GFP_KERNEL);
3839*4882a593Smuzhiyun 	if (!params)
3840*4882a593Smuzhiyun 		return -ENOMEM;
3841*4882a593Smuzhiyun 
3842*4882a593Smuzhiyun 	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
3843*4882a593Smuzhiyun 	if (!runtime) {
3844*4882a593Smuzhiyun 		ret = -ENOMEM;
3845*4882a593Smuzhiyun 		goto out;
3846*4882a593Smuzhiyun 	}
3847*4882a593Smuzhiyun 
3848*4882a593Smuzhiyun 	substream->runtime = runtime;
3849*4882a593Smuzhiyun 
3850*4882a593Smuzhiyun 	substream->stream = SNDRV_PCM_STREAM_CAPTURE;
3851*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_source_path(w, path) {
3852*4882a593Smuzhiyun 		source = path->source->priv;
3853*4882a593Smuzhiyun 
3854*4882a593Smuzhiyun 		ret = snd_soc_dai_startup(source, substream);
3855*4882a593Smuzhiyun 		if (ret < 0) {
3856*4882a593Smuzhiyun 			dev_err(source->dev,
3857*4882a593Smuzhiyun 				"ASoC: startup() failed: %d\n", ret);
3858*4882a593Smuzhiyun 			goto out;
3859*4882a593Smuzhiyun 		}
3860*4882a593Smuzhiyun 		snd_soc_dai_activate(source, substream->stream);
3861*4882a593Smuzhiyun 	}
3862*4882a593Smuzhiyun 
3863*4882a593Smuzhiyun 	substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
3864*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_sink_path(w, path) {
3865*4882a593Smuzhiyun 		sink = path->sink->priv;
3866*4882a593Smuzhiyun 
3867*4882a593Smuzhiyun 		ret = snd_soc_dai_startup(sink, substream);
3868*4882a593Smuzhiyun 		if (ret < 0) {
3869*4882a593Smuzhiyun 			dev_err(sink->dev,
3870*4882a593Smuzhiyun 				"ASoC: startup() failed: %d\n", ret);
3871*4882a593Smuzhiyun 			goto out;
3872*4882a593Smuzhiyun 		}
3873*4882a593Smuzhiyun 		snd_soc_dai_activate(sink, substream->stream);
3874*4882a593Smuzhiyun 	}
3875*4882a593Smuzhiyun 
3876*4882a593Smuzhiyun 	substream->hw_opened = 1;
3877*4882a593Smuzhiyun 
3878*4882a593Smuzhiyun 	/*
3879*4882a593Smuzhiyun 	 * Note: getting the config after .startup() gives a chance to
3880*4882a593Smuzhiyun 	 * either party on the link to alter the configuration if
3881*4882a593Smuzhiyun 	 * necessary
3882*4882a593Smuzhiyun 	 */
3883*4882a593Smuzhiyun 	config = rtd->dai_link->params + rtd->params_select;
3884*4882a593Smuzhiyun 	if (WARN_ON(!config)) {
3885*4882a593Smuzhiyun 		dev_err(w->dapm->dev, "ASoC: link config missing\n");
3886*4882a593Smuzhiyun 		ret = -EINVAL;
3887*4882a593Smuzhiyun 		goto out;
3888*4882a593Smuzhiyun 	}
3889*4882a593Smuzhiyun 
3890*4882a593Smuzhiyun 	/* Be a little careful as we don't want to overflow the mask array */
3891*4882a593Smuzhiyun 	if (config->formats) {
3892*4882a593Smuzhiyun 		fmt = ffs(config->formats) - 1;
3893*4882a593Smuzhiyun 	} else {
3894*4882a593Smuzhiyun 		dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
3895*4882a593Smuzhiyun 			 config->formats);
3896*4882a593Smuzhiyun 
3897*4882a593Smuzhiyun 		ret = -EINVAL;
3898*4882a593Smuzhiyun 		goto out;
3899*4882a593Smuzhiyun 	}
3900*4882a593Smuzhiyun 
3901*4882a593Smuzhiyun 	snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
3902*4882a593Smuzhiyun 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
3903*4882a593Smuzhiyun 		config->rate_min;
3904*4882a593Smuzhiyun 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
3905*4882a593Smuzhiyun 		config->rate_max;
3906*4882a593Smuzhiyun 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
3907*4882a593Smuzhiyun 		= config->channels_min;
3908*4882a593Smuzhiyun 	hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
3909*4882a593Smuzhiyun 		= config->channels_max;
3910*4882a593Smuzhiyun 
3911*4882a593Smuzhiyun 	substream->stream = SNDRV_PCM_STREAM_CAPTURE;
3912*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_source_path(w, path) {
3913*4882a593Smuzhiyun 		source = path->source->priv;
3914*4882a593Smuzhiyun 
3915*4882a593Smuzhiyun 		ret = snd_soc_dai_hw_params(source, substream, params);
3916*4882a593Smuzhiyun 		if (ret < 0)
3917*4882a593Smuzhiyun 			goto out;
3918*4882a593Smuzhiyun 
3919*4882a593Smuzhiyun 		dapm_update_dai_unlocked(substream, params, source);
3920*4882a593Smuzhiyun 	}
3921*4882a593Smuzhiyun 
3922*4882a593Smuzhiyun 	substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
3923*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_sink_path(w, path) {
3924*4882a593Smuzhiyun 		sink = path->sink->priv;
3925*4882a593Smuzhiyun 
3926*4882a593Smuzhiyun 		ret = snd_soc_dai_hw_params(sink, substream, params);
3927*4882a593Smuzhiyun 		if (ret < 0)
3928*4882a593Smuzhiyun 			goto out;
3929*4882a593Smuzhiyun 
3930*4882a593Smuzhiyun 		dapm_update_dai_unlocked(substream, params, sink);
3931*4882a593Smuzhiyun 	}
3932*4882a593Smuzhiyun 
3933*4882a593Smuzhiyun 	runtime->format = params_format(params);
3934*4882a593Smuzhiyun 	runtime->subformat = params_subformat(params);
3935*4882a593Smuzhiyun 	runtime->channels = params_channels(params);
3936*4882a593Smuzhiyun 	runtime->rate = params_rate(params);
3937*4882a593Smuzhiyun 
3938*4882a593Smuzhiyun out:
3939*4882a593Smuzhiyun 	kfree(params);
3940*4882a593Smuzhiyun 	return ret;
3941*4882a593Smuzhiyun }
3942*4882a593Smuzhiyun 
snd_soc_dai_link_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)3943*4882a593Smuzhiyun static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3944*4882a593Smuzhiyun 				  struct snd_kcontrol *kcontrol, int event)
3945*4882a593Smuzhiyun {
3946*4882a593Smuzhiyun 	struct snd_soc_dapm_path *path;
3947*4882a593Smuzhiyun 	struct snd_soc_dai *source, *sink;
3948*4882a593Smuzhiyun 	struct snd_pcm_substream *substream = w->priv;
3949*4882a593Smuzhiyun 	int ret = 0, saved_stream = substream->stream;
3950*4882a593Smuzhiyun 
3951*4882a593Smuzhiyun 	if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3952*4882a593Smuzhiyun 		    list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
3953*4882a593Smuzhiyun 		return -EINVAL;
3954*4882a593Smuzhiyun 
3955*4882a593Smuzhiyun 	switch (event) {
3956*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMU:
3957*4882a593Smuzhiyun 		ret = snd_soc_dai_link_event_pre_pmu(w, substream);
3958*4882a593Smuzhiyun 		if (ret < 0)
3959*4882a593Smuzhiyun 			goto out;
3960*4882a593Smuzhiyun 
3961*4882a593Smuzhiyun 		break;
3962*4882a593Smuzhiyun 
3963*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMU:
3964*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_sink_path(w, path) {
3965*4882a593Smuzhiyun 			sink = path->sink->priv;
3966*4882a593Smuzhiyun 
3967*4882a593Smuzhiyun 			ret = snd_soc_dai_digital_mute(sink, 0,
3968*4882a593Smuzhiyun 						       SNDRV_PCM_STREAM_PLAYBACK);
3969*4882a593Smuzhiyun 			if (ret != 0 && ret != -ENOTSUPP)
3970*4882a593Smuzhiyun 				dev_warn(sink->dev,
3971*4882a593Smuzhiyun 					 "ASoC: Failed to unmute: %d\n", ret);
3972*4882a593Smuzhiyun 			ret = 0;
3973*4882a593Smuzhiyun 		}
3974*4882a593Smuzhiyun 		break;
3975*4882a593Smuzhiyun 
3976*4882a593Smuzhiyun 	case SND_SOC_DAPM_PRE_PMD:
3977*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_sink_path(w, path) {
3978*4882a593Smuzhiyun 			sink = path->sink->priv;
3979*4882a593Smuzhiyun 
3980*4882a593Smuzhiyun 			ret = snd_soc_dai_digital_mute(sink, 1,
3981*4882a593Smuzhiyun 						       SNDRV_PCM_STREAM_PLAYBACK);
3982*4882a593Smuzhiyun 			if (ret != 0 && ret != -ENOTSUPP)
3983*4882a593Smuzhiyun 				dev_warn(sink->dev,
3984*4882a593Smuzhiyun 					 "ASoC: Failed to mute: %d\n", ret);
3985*4882a593Smuzhiyun 			ret = 0;
3986*4882a593Smuzhiyun 		}
3987*4882a593Smuzhiyun 
3988*4882a593Smuzhiyun 		substream->stream = SNDRV_PCM_STREAM_CAPTURE;
3989*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_source_path(w, path) {
3990*4882a593Smuzhiyun 			source = path->source->priv;
3991*4882a593Smuzhiyun 			snd_soc_dai_hw_free(source, substream);
3992*4882a593Smuzhiyun 		}
3993*4882a593Smuzhiyun 
3994*4882a593Smuzhiyun 		substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
3995*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_sink_path(w, path) {
3996*4882a593Smuzhiyun 			sink = path->sink->priv;
3997*4882a593Smuzhiyun 			snd_soc_dai_hw_free(sink, substream);
3998*4882a593Smuzhiyun 		}
3999*4882a593Smuzhiyun 
4000*4882a593Smuzhiyun 		substream->stream = SNDRV_PCM_STREAM_CAPTURE;
4001*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_source_path(w, path) {
4002*4882a593Smuzhiyun 			source = path->source->priv;
4003*4882a593Smuzhiyun 			snd_soc_dai_deactivate(source, substream->stream);
4004*4882a593Smuzhiyun 			snd_soc_dai_shutdown(source, substream, 0);
4005*4882a593Smuzhiyun 		}
4006*4882a593Smuzhiyun 
4007*4882a593Smuzhiyun 		substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
4008*4882a593Smuzhiyun 		snd_soc_dapm_widget_for_each_sink_path(w, path) {
4009*4882a593Smuzhiyun 			sink = path->sink->priv;
4010*4882a593Smuzhiyun 			snd_soc_dai_deactivate(sink, substream->stream);
4011*4882a593Smuzhiyun 			snd_soc_dai_shutdown(sink, substream, 0);
4012*4882a593Smuzhiyun 		}
4013*4882a593Smuzhiyun 		break;
4014*4882a593Smuzhiyun 
4015*4882a593Smuzhiyun 	case SND_SOC_DAPM_POST_PMD:
4016*4882a593Smuzhiyun 		kfree(substream->runtime);
4017*4882a593Smuzhiyun 		break;
4018*4882a593Smuzhiyun 
4019*4882a593Smuzhiyun 	default:
4020*4882a593Smuzhiyun 		WARN(1, "Unknown event %d\n", event);
4021*4882a593Smuzhiyun 		ret = -EINVAL;
4022*4882a593Smuzhiyun 	}
4023*4882a593Smuzhiyun 
4024*4882a593Smuzhiyun out:
4025*4882a593Smuzhiyun 	/* Restore the substream direction */
4026*4882a593Smuzhiyun 	substream->stream = saved_stream;
4027*4882a593Smuzhiyun 	return ret;
4028*4882a593Smuzhiyun }
4029*4882a593Smuzhiyun 
snd_soc_dapm_dai_link_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4030*4882a593Smuzhiyun static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
4031*4882a593Smuzhiyun 			  struct snd_ctl_elem_value *ucontrol)
4032*4882a593Smuzhiyun {
4033*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
4034*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = w->priv;
4035*4882a593Smuzhiyun 
4036*4882a593Smuzhiyun 	ucontrol->value.enumerated.item[0] = rtd->params_select;
4037*4882a593Smuzhiyun 
4038*4882a593Smuzhiyun 	return 0;
4039*4882a593Smuzhiyun }
4040*4882a593Smuzhiyun 
snd_soc_dapm_dai_link_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4041*4882a593Smuzhiyun static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
4042*4882a593Smuzhiyun 			  struct snd_ctl_elem_value *ucontrol)
4043*4882a593Smuzhiyun {
4044*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
4045*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = w->priv;
4046*4882a593Smuzhiyun 
4047*4882a593Smuzhiyun 	/* Can't change the config when widget is already powered */
4048*4882a593Smuzhiyun 	if (w->power)
4049*4882a593Smuzhiyun 		return -EBUSY;
4050*4882a593Smuzhiyun 
4051*4882a593Smuzhiyun 	if (ucontrol->value.enumerated.item[0] == rtd->params_select)
4052*4882a593Smuzhiyun 		return 0;
4053*4882a593Smuzhiyun 
4054*4882a593Smuzhiyun 	if (ucontrol->value.enumerated.item[0] >= rtd->dai_link->num_params)
4055*4882a593Smuzhiyun 		return -EINVAL;
4056*4882a593Smuzhiyun 
4057*4882a593Smuzhiyun 	rtd->params_select = ucontrol->value.enumerated.item[0];
4058*4882a593Smuzhiyun 
4059*4882a593Smuzhiyun 	return 1;
4060*4882a593Smuzhiyun }
4061*4882a593Smuzhiyun 
4062*4882a593Smuzhiyun static void
snd_soc_dapm_free_kcontrol(struct snd_soc_card * card,unsigned long * private_value,int num_params,const char ** w_param_text)4063*4882a593Smuzhiyun snd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
4064*4882a593Smuzhiyun 			unsigned long *private_value,
4065*4882a593Smuzhiyun 			int num_params,
4066*4882a593Smuzhiyun 			const char **w_param_text)
4067*4882a593Smuzhiyun {
4068*4882a593Smuzhiyun 	int count;
4069*4882a593Smuzhiyun 
4070*4882a593Smuzhiyun 	devm_kfree(card->dev, (void *)*private_value);
4071*4882a593Smuzhiyun 
4072*4882a593Smuzhiyun 	if (!w_param_text)
4073*4882a593Smuzhiyun 		return;
4074*4882a593Smuzhiyun 
4075*4882a593Smuzhiyun 	for (count = 0 ; count < num_params; count++)
4076*4882a593Smuzhiyun 		devm_kfree(card->dev, (void *)w_param_text[count]);
4077*4882a593Smuzhiyun 	devm_kfree(card->dev, w_param_text);
4078*4882a593Smuzhiyun }
4079*4882a593Smuzhiyun 
4080*4882a593Smuzhiyun static struct snd_kcontrol_new *
snd_soc_dapm_alloc_kcontrol(struct snd_soc_card * card,char * link_name,const struct snd_soc_pcm_stream * params,int num_params,const char ** w_param_text,unsigned long * private_value)4081*4882a593Smuzhiyun snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
4082*4882a593Smuzhiyun 			char *link_name,
4083*4882a593Smuzhiyun 			const struct snd_soc_pcm_stream *params,
4084*4882a593Smuzhiyun 			int num_params, const char **w_param_text,
4085*4882a593Smuzhiyun 			unsigned long *private_value)
4086*4882a593Smuzhiyun {
4087*4882a593Smuzhiyun 	struct soc_enum w_param_enum[] = {
4088*4882a593Smuzhiyun 		SOC_ENUM_SINGLE(0, 0, 0, NULL),
4089*4882a593Smuzhiyun 	};
4090*4882a593Smuzhiyun 	struct snd_kcontrol_new kcontrol_dai_link[] = {
4091*4882a593Smuzhiyun 		SOC_ENUM_EXT(NULL, w_param_enum[0],
4092*4882a593Smuzhiyun 			     snd_soc_dapm_dai_link_get,
4093*4882a593Smuzhiyun 			     snd_soc_dapm_dai_link_put),
4094*4882a593Smuzhiyun 	};
4095*4882a593Smuzhiyun 	struct snd_kcontrol_new *kcontrol_news;
4096*4882a593Smuzhiyun 	const struct snd_soc_pcm_stream *config = params;
4097*4882a593Smuzhiyun 	int count;
4098*4882a593Smuzhiyun 
4099*4882a593Smuzhiyun 	for (count = 0 ; count < num_params; count++) {
4100*4882a593Smuzhiyun 		if (!config->stream_name) {
4101*4882a593Smuzhiyun 			dev_warn(card->dapm.dev,
4102*4882a593Smuzhiyun 				"ASoC: anonymous config %d for dai link %s\n",
4103*4882a593Smuzhiyun 				count, link_name);
4104*4882a593Smuzhiyun 			w_param_text[count] =
4105*4882a593Smuzhiyun 				devm_kasprintf(card->dev, GFP_KERNEL,
4106*4882a593Smuzhiyun 					       "Anonymous Configuration %d",
4107*4882a593Smuzhiyun 					       count);
4108*4882a593Smuzhiyun 		} else {
4109*4882a593Smuzhiyun 			w_param_text[count] = devm_kmemdup(card->dev,
4110*4882a593Smuzhiyun 						config->stream_name,
4111*4882a593Smuzhiyun 						strlen(config->stream_name) + 1,
4112*4882a593Smuzhiyun 						GFP_KERNEL);
4113*4882a593Smuzhiyun 		}
4114*4882a593Smuzhiyun 		if (!w_param_text[count])
4115*4882a593Smuzhiyun 			goto outfree_w_param;
4116*4882a593Smuzhiyun 		config++;
4117*4882a593Smuzhiyun 	}
4118*4882a593Smuzhiyun 
4119*4882a593Smuzhiyun 	w_param_enum[0].items = num_params;
4120*4882a593Smuzhiyun 	w_param_enum[0].texts = w_param_text;
4121*4882a593Smuzhiyun 
4122*4882a593Smuzhiyun 	*private_value =
4123*4882a593Smuzhiyun 		(unsigned long) devm_kmemdup(card->dev,
4124*4882a593Smuzhiyun 			(void *)(kcontrol_dai_link[0].private_value),
4125*4882a593Smuzhiyun 			sizeof(struct soc_enum), GFP_KERNEL);
4126*4882a593Smuzhiyun 	if (!*private_value) {
4127*4882a593Smuzhiyun 		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
4128*4882a593Smuzhiyun 			link_name);
4129*4882a593Smuzhiyun 		goto outfree_w_param;
4130*4882a593Smuzhiyun 	}
4131*4882a593Smuzhiyun 	kcontrol_dai_link[0].private_value = *private_value;
4132*4882a593Smuzhiyun 	/* duplicate kcontrol_dai_link on heap so that memory persists */
4133*4882a593Smuzhiyun 	kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
4134*4882a593Smuzhiyun 					sizeof(struct snd_kcontrol_new),
4135*4882a593Smuzhiyun 					GFP_KERNEL);
4136*4882a593Smuzhiyun 	if (!kcontrol_news) {
4137*4882a593Smuzhiyun 		dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
4138*4882a593Smuzhiyun 			link_name);
4139*4882a593Smuzhiyun 		goto outfree_w_param;
4140*4882a593Smuzhiyun 	}
4141*4882a593Smuzhiyun 	return kcontrol_news;
4142*4882a593Smuzhiyun 
4143*4882a593Smuzhiyun outfree_w_param:
4144*4882a593Smuzhiyun 	snd_soc_dapm_free_kcontrol(card, private_value, num_params, w_param_text);
4145*4882a593Smuzhiyun 	return NULL;
4146*4882a593Smuzhiyun }
4147*4882a593Smuzhiyun 
4148*4882a593Smuzhiyun static struct snd_soc_dapm_widget *
snd_soc_dapm_new_dai(struct snd_soc_card * card,struct snd_pcm_substream * substream,char * id)4149*4882a593Smuzhiyun snd_soc_dapm_new_dai(struct snd_soc_card *card,
4150*4882a593Smuzhiyun 		     struct snd_pcm_substream *substream,
4151*4882a593Smuzhiyun 		     char *id)
4152*4882a593Smuzhiyun {
4153*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
4154*4882a593Smuzhiyun 	struct snd_soc_dapm_widget template;
4155*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
4156*4882a593Smuzhiyun 	const char **w_param_text;
4157*4882a593Smuzhiyun 	unsigned long private_value = 0;
4158*4882a593Smuzhiyun 	char *link_name;
4159*4882a593Smuzhiyun 	int ret;
4160*4882a593Smuzhiyun 
4161*4882a593Smuzhiyun 	link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
4162*4882a593Smuzhiyun 				   rtd->dai_link->name, id);
4163*4882a593Smuzhiyun 	if (!link_name)
4164*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
4165*4882a593Smuzhiyun 
4166*4882a593Smuzhiyun 	memset(&template, 0, sizeof(template));
4167*4882a593Smuzhiyun 	template.reg = SND_SOC_NOPM;
4168*4882a593Smuzhiyun 	template.id = snd_soc_dapm_dai_link;
4169*4882a593Smuzhiyun 	template.name = link_name;
4170*4882a593Smuzhiyun 	template.event = snd_soc_dai_link_event;
4171*4882a593Smuzhiyun 	template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4172*4882a593Smuzhiyun 		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD;
4173*4882a593Smuzhiyun 	template.kcontrol_news = NULL;
4174*4882a593Smuzhiyun 
4175*4882a593Smuzhiyun 	/* allocate memory for control, only in case of multiple configs */
4176*4882a593Smuzhiyun 	if (rtd->dai_link->num_params > 1) {
4177*4882a593Smuzhiyun 		w_param_text = devm_kcalloc(card->dev,
4178*4882a593Smuzhiyun 					    rtd->dai_link->num_params,
4179*4882a593Smuzhiyun 					    sizeof(char *), GFP_KERNEL);
4180*4882a593Smuzhiyun 		if (!w_param_text) {
4181*4882a593Smuzhiyun 			ret = -ENOMEM;
4182*4882a593Smuzhiyun 			goto param_fail;
4183*4882a593Smuzhiyun 		}
4184*4882a593Smuzhiyun 
4185*4882a593Smuzhiyun 		template.num_kcontrols = 1;
4186*4882a593Smuzhiyun 		template.kcontrol_news =
4187*4882a593Smuzhiyun 					snd_soc_dapm_alloc_kcontrol(card,
4188*4882a593Smuzhiyun 						link_name,
4189*4882a593Smuzhiyun 						rtd->dai_link->params,
4190*4882a593Smuzhiyun 						rtd->dai_link->num_params,
4191*4882a593Smuzhiyun 						w_param_text, &private_value);
4192*4882a593Smuzhiyun 		if (!template.kcontrol_news) {
4193*4882a593Smuzhiyun 			ret = -ENOMEM;
4194*4882a593Smuzhiyun 			goto param_fail;
4195*4882a593Smuzhiyun 		}
4196*4882a593Smuzhiyun 	} else {
4197*4882a593Smuzhiyun 		w_param_text = NULL;
4198*4882a593Smuzhiyun 	}
4199*4882a593Smuzhiyun 	dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
4200*4882a593Smuzhiyun 
4201*4882a593Smuzhiyun 	w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
4202*4882a593Smuzhiyun 	if (IS_ERR(w)) {
4203*4882a593Smuzhiyun 		ret = PTR_ERR(w);
4204*4882a593Smuzhiyun 		dev_err(rtd->dev, "ASoC: Failed to create %s widget: %d\n",
4205*4882a593Smuzhiyun 			link_name, ret);
4206*4882a593Smuzhiyun 		goto outfree_kcontrol_news;
4207*4882a593Smuzhiyun 	}
4208*4882a593Smuzhiyun 
4209*4882a593Smuzhiyun 	w->priv = substream;
4210*4882a593Smuzhiyun 
4211*4882a593Smuzhiyun 	return w;
4212*4882a593Smuzhiyun 
4213*4882a593Smuzhiyun outfree_kcontrol_news:
4214*4882a593Smuzhiyun 	devm_kfree(card->dev, (void *)template.kcontrol_news);
4215*4882a593Smuzhiyun 	snd_soc_dapm_free_kcontrol(card, &private_value,
4216*4882a593Smuzhiyun 				   rtd->dai_link->num_params, w_param_text);
4217*4882a593Smuzhiyun param_fail:
4218*4882a593Smuzhiyun 	devm_kfree(card->dev, link_name);
4219*4882a593Smuzhiyun 	return ERR_PTR(ret);
4220*4882a593Smuzhiyun }
4221*4882a593Smuzhiyun 
snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context * dapm,struct snd_soc_dai * dai)4222*4882a593Smuzhiyun int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
4223*4882a593Smuzhiyun 				 struct snd_soc_dai *dai)
4224*4882a593Smuzhiyun {
4225*4882a593Smuzhiyun 	struct snd_soc_dapm_widget template;
4226*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
4227*4882a593Smuzhiyun 
4228*4882a593Smuzhiyun 	WARN_ON(dapm->dev != dai->dev);
4229*4882a593Smuzhiyun 
4230*4882a593Smuzhiyun 	memset(&template, 0, sizeof(template));
4231*4882a593Smuzhiyun 	template.reg = SND_SOC_NOPM;
4232*4882a593Smuzhiyun 
4233*4882a593Smuzhiyun 	if (dai->driver->playback.stream_name) {
4234*4882a593Smuzhiyun 		template.id = snd_soc_dapm_dai_in;
4235*4882a593Smuzhiyun 		template.name = dai->driver->playback.stream_name;
4236*4882a593Smuzhiyun 		template.sname = dai->driver->playback.stream_name;
4237*4882a593Smuzhiyun 
4238*4882a593Smuzhiyun 		dev_dbg(dai->dev, "ASoC: adding %s widget\n",
4239*4882a593Smuzhiyun 			template.name);
4240*4882a593Smuzhiyun 
4241*4882a593Smuzhiyun 		w = snd_soc_dapm_new_control_unlocked(dapm, &template);
4242*4882a593Smuzhiyun 		if (IS_ERR(w))
4243*4882a593Smuzhiyun 			return PTR_ERR(w);
4244*4882a593Smuzhiyun 
4245*4882a593Smuzhiyun 		w->priv = dai;
4246*4882a593Smuzhiyun 		dai->playback_widget = w;
4247*4882a593Smuzhiyun 	}
4248*4882a593Smuzhiyun 
4249*4882a593Smuzhiyun 	if (dai->driver->capture.stream_name) {
4250*4882a593Smuzhiyun 		template.id = snd_soc_dapm_dai_out;
4251*4882a593Smuzhiyun 		template.name = dai->driver->capture.stream_name;
4252*4882a593Smuzhiyun 		template.sname = dai->driver->capture.stream_name;
4253*4882a593Smuzhiyun 
4254*4882a593Smuzhiyun 		dev_dbg(dai->dev, "ASoC: adding %s widget\n",
4255*4882a593Smuzhiyun 			template.name);
4256*4882a593Smuzhiyun 
4257*4882a593Smuzhiyun 		w = snd_soc_dapm_new_control_unlocked(dapm, &template);
4258*4882a593Smuzhiyun 		if (IS_ERR(w))
4259*4882a593Smuzhiyun 			return PTR_ERR(w);
4260*4882a593Smuzhiyun 
4261*4882a593Smuzhiyun 		w->priv = dai;
4262*4882a593Smuzhiyun 		dai->capture_widget = w;
4263*4882a593Smuzhiyun 	}
4264*4882a593Smuzhiyun 
4265*4882a593Smuzhiyun 	return 0;
4266*4882a593Smuzhiyun }
4267*4882a593Smuzhiyun 
snd_soc_dapm_link_dai_widgets(struct snd_soc_card * card)4268*4882a593Smuzhiyun int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
4269*4882a593Smuzhiyun {
4270*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *dai_w, *w;
4271*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *src, *sink;
4272*4882a593Smuzhiyun 	struct snd_soc_dai *dai;
4273*4882a593Smuzhiyun 
4274*4882a593Smuzhiyun 	/* For each DAI widget... */
4275*4882a593Smuzhiyun 	for_each_card_widgets(card, dai_w) {
4276*4882a593Smuzhiyun 		switch (dai_w->id) {
4277*4882a593Smuzhiyun 		case snd_soc_dapm_dai_in:
4278*4882a593Smuzhiyun 		case snd_soc_dapm_dai_out:
4279*4882a593Smuzhiyun 			break;
4280*4882a593Smuzhiyun 		default:
4281*4882a593Smuzhiyun 			continue;
4282*4882a593Smuzhiyun 		}
4283*4882a593Smuzhiyun 
4284*4882a593Smuzhiyun 		/* let users know there is no DAI to link */
4285*4882a593Smuzhiyun 		if (!dai_w->priv) {
4286*4882a593Smuzhiyun 			dev_dbg(card->dev, "dai widget %s has no DAI\n",
4287*4882a593Smuzhiyun 				dai_w->name);
4288*4882a593Smuzhiyun 			continue;
4289*4882a593Smuzhiyun 		}
4290*4882a593Smuzhiyun 
4291*4882a593Smuzhiyun 		dai = dai_w->priv;
4292*4882a593Smuzhiyun 
4293*4882a593Smuzhiyun 		/* ...find all widgets with the same stream and link them */
4294*4882a593Smuzhiyun 		for_each_card_widgets(card, w) {
4295*4882a593Smuzhiyun 			if (w->dapm != dai_w->dapm)
4296*4882a593Smuzhiyun 				continue;
4297*4882a593Smuzhiyun 
4298*4882a593Smuzhiyun 			switch (w->id) {
4299*4882a593Smuzhiyun 			case snd_soc_dapm_dai_in:
4300*4882a593Smuzhiyun 			case snd_soc_dapm_dai_out:
4301*4882a593Smuzhiyun 				continue;
4302*4882a593Smuzhiyun 			default:
4303*4882a593Smuzhiyun 				break;
4304*4882a593Smuzhiyun 			}
4305*4882a593Smuzhiyun 
4306*4882a593Smuzhiyun 			if (!w->sname || !strstr(w->sname, dai_w->sname))
4307*4882a593Smuzhiyun 				continue;
4308*4882a593Smuzhiyun 
4309*4882a593Smuzhiyun 			if (dai_w->id == snd_soc_dapm_dai_in) {
4310*4882a593Smuzhiyun 				src = dai_w;
4311*4882a593Smuzhiyun 				sink = w;
4312*4882a593Smuzhiyun 			} else {
4313*4882a593Smuzhiyun 				src = w;
4314*4882a593Smuzhiyun 				sink = dai_w;
4315*4882a593Smuzhiyun 			}
4316*4882a593Smuzhiyun 			dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
4317*4882a593Smuzhiyun 			snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
4318*4882a593Smuzhiyun 		}
4319*4882a593Smuzhiyun 	}
4320*4882a593Smuzhiyun 
4321*4882a593Smuzhiyun 	return 0;
4322*4882a593Smuzhiyun }
4323*4882a593Smuzhiyun 
dapm_connect_dai_routes(struct snd_soc_dapm_context * dapm,struct snd_soc_dai * src_dai,struct snd_soc_dapm_widget * src,struct snd_soc_dapm_widget * dai,struct snd_soc_dai * sink_dai,struct snd_soc_dapm_widget * sink)4324*4882a593Smuzhiyun static void dapm_connect_dai_routes(struct snd_soc_dapm_context *dapm,
4325*4882a593Smuzhiyun 				    struct snd_soc_dai *src_dai,
4326*4882a593Smuzhiyun 				    struct snd_soc_dapm_widget *src,
4327*4882a593Smuzhiyun 				    struct snd_soc_dapm_widget *dai,
4328*4882a593Smuzhiyun 				    struct snd_soc_dai *sink_dai,
4329*4882a593Smuzhiyun 				    struct snd_soc_dapm_widget *sink)
4330*4882a593Smuzhiyun {
4331*4882a593Smuzhiyun 	dev_dbg(dapm->dev, "connected DAI link %s:%s -> %s:%s\n",
4332*4882a593Smuzhiyun 		src_dai->component->name, src->name,
4333*4882a593Smuzhiyun 		sink_dai->component->name, sink->name);
4334*4882a593Smuzhiyun 
4335*4882a593Smuzhiyun 	if (dai) {
4336*4882a593Smuzhiyun 		snd_soc_dapm_add_path(dapm, src, dai, NULL, NULL);
4337*4882a593Smuzhiyun 		src = dai;
4338*4882a593Smuzhiyun 	}
4339*4882a593Smuzhiyun 
4340*4882a593Smuzhiyun 	snd_soc_dapm_add_path(dapm, src, sink, NULL, NULL);
4341*4882a593Smuzhiyun }
4342*4882a593Smuzhiyun 
dapm_connect_dai_pair(struct snd_soc_card * card,struct snd_soc_pcm_runtime * rtd,struct snd_soc_dai * codec_dai,struct snd_soc_dai * cpu_dai)4343*4882a593Smuzhiyun static void dapm_connect_dai_pair(struct snd_soc_card *card,
4344*4882a593Smuzhiyun 				  struct snd_soc_pcm_runtime *rtd,
4345*4882a593Smuzhiyun 				  struct snd_soc_dai *codec_dai,
4346*4882a593Smuzhiyun 				  struct snd_soc_dai *cpu_dai)
4347*4882a593Smuzhiyun {
4348*4882a593Smuzhiyun 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
4349*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *dai, *codec, *playback_cpu, *capture_cpu;
4350*4882a593Smuzhiyun 	struct snd_pcm_substream *substream;
4351*4882a593Smuzhiyun 	struct snd_pcm_str *streams = rtd->pcm->streams;
4352*4882a593Smuzhiyun 
4353*4882a593Smuzhiyun 	if (dai_link->params) {
4354*4882a593Smuzhiyun 		playback_cpu = cpu_dai->capture_widget;
4355*4882a593Smuzhiyun 		capture_cpu = cpu_dai->playback_widget;
4356*4882a593Smuzhiyun 	} else {
4357*4882a593Smuzhiyun 		playback_cpu = cpu_dai->playback_widget;
4358*4882a593Smuzhiyun 		capture_cpu = cpu_dai->capture_widget;
4359*4882a593Smuzhiyun 	}
4360*4882a593Smuzhiyun 
4361*4882a593Smuzhiyun 	/* connect BE DAI playback if widgets are valid */
4362*4882a593Smuzhiyun 	codec = codec_dai->playback_widget;
4363*4882a593Smuzhiyun 
4364*4882a593Smuzhiyun 	if (playback_cpu && codec) {
4365*4882a593Smuzhiyun 		if (dai_link->params && !rtd->playback_widget) {
4366*4882a593Smuzhiyun 			substream = streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
4367*4882a593Smuzhiyun 			dai = snd_soc_dapm_new_dai(card, substream, "playback");
4368*4882a593Smuzhiyun 			if (IS_ERR(dai))
4369*4882a593Smuzhiyun 				goto capture;
4370*4882a593Smuzhiyun 			rtd->playback_widget = dai;
4371*4882a593Smuzhiyun 		}
4372*4882a593Smuzhiyun 
4373*4882a593Smuzhiyun 		dapm_connect_dai_routes(&card->dapm, cpu_dai, playback_cpu,
4374*4882a593Smuzhiyun 					rtd->playback_widget,
4375*4882a593Smuzhiyun 					codec_dai, codec);
4376*4882a593Smuzhiyun 	}
4377*4882a593Smuzhiyun 
4378*4882a593Smuzhiyun capture:
4379*4882a593Smuzhiyun 	/* connect BE DAI capture if widgets are valid */
4380*4882a593Smuzhiyun 	codec = codec_dai->capture_widget;
4381*4882a593Smuzhiyun 
4382*4882a593Smuzhiyun 	if (codec && capture_cpu) {
4383*4882a593Smuzhiyun 		if (dai_link->params && !rtd->capture_widget) {
4384*4882a593Smuzhiyun 			substream = streams[SNDRV_PCM_STREAM_CAPTURE].substream;
4385*4882a593Smuzhiyun 			dai = snd_soc_dapm_new_dai(card, substream, "capture");
4386*4882a593Smuzhiyun 			if (IS_ERR(dai))
4387*4882a593Smuzhiyun 				return;
4388*4882a593Smuzhiyun 			rtd->capture_widget = dai;
4389*4882a593Smuzhiyun 		}
4390*4882a593Smuzhiyun 
4391*4882a593Smuzhiyun 		dapm_connect_dai_routes(&card->dapm, codec_dai, codec,
4392*4882a593Smuzhiyun 					rtd->capture_widget,
4393*4882a593Smuzhiyun 					cpu_dai, capture_cpu);
4394*4882a593Smuzhiyun 	}
4395*4882a593Smuzhiyun }
4396*4882a593Smuzhiyun 
soc_dapm_dai_stream_event(struct snd_soc_dai * dai,int stream,int event)4397*4882a593Smuzhiyun static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
4398*4882a593Smuzhiyun 	int event)
4399*4882a593Smuzhiyun {
4400*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
4401*4882a593Smuzhiyun 	unsigned int ep;
4402*4882a593Smuzhiyun 
4403*4882a593Smuzhiyun 	w = snd_soc_dai_get_widget(dai, stream);
4404*4882a593Smuzhiyun 
4405*4882a593Smuzhiyun 	if (w) {
4406*4882a593Smuzhiyun 		dapm_mark_dirty(w, "stream event");
4407*4882a593Smuzhiyun 
4408*4882a593Smuzhiyun 		if (w->id == snd_soc_dapm_dai_in) {
4409*4882a593Smuzhiyun 			ep = SND_SOC_DAPM_EP_SOURCE;
4410*4882a593Smuzhiyun 			dapm_widget_invalidate_input_paths(w);
4411*4882a593Smuzhiyun 		} else {
4412*4882a593Smuzhiyun 			ep = SND_SOC_DAPM_EP_SINK;
4413*4882a593Smuzhiyun 			dapm_widget_invalidate_output_paths(w);
4414*4882a593Smuzhiyun 		}
4415*4882a593Smuzhiyun 
4416*4882a593Smuzhiyun 		switch (event) {
4417*4882a593Smuzhiyun 		case SND_SOC_DAPM_STREAM_START:
4418*4882a593Smuzhiyun 			w->active = 1;
4419*4882a593Smuzhiyun 			w->is_ep = ep;
4420*4882a593Smuzhiyun 			break;
4421*4882a593Smuzhiyun 		case SND_SOC_DAPM_STREAM_STOP:
4422*4882a593Smuzhiyun 			w->active = 0;
4423*4882a593Smuzhiyun 			w->is_ep = 0;
4424*4882a593Smuzhiyun 			break;
4425*4882a593Smuzhiyun 		case SND_SOC_DAPM_STREAM_SUSPEND:
4426*4882a593Smuzhiyun 		case SND_SOC_DAPM_STREAM_RESUME:
4427*4882a593Smuzhiyun 		case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
4428*4882a593Smuzhiyun 		case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
4429*4882a593Smuzhiyun 			break;
4430*4882a593Smuzhiyun 		}
4431*4882a593Smuzhiyun 	}
4432*4882a593Smuzhiyun }
4433*4882a593Smuzhiyun 
snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card * card)4434*4882a593Smuzhiyun void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
4435*4882a593Smuzhiyun {
4436*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd;
4437*4882a593Smuzhiyun 	struct snd_soc_dai *codec_dai;
4438*4882a593Smuzhiyun 	int i;
4439*4882a593Smuzhiyun 
4440*4882a593Smuzhiyun 	/* for each BE DAI link... */
4441*4882a593Smuzhiyun 	for_each_card_rtds(card, rtd)  {
4442*4882a593Smuzhiyun 		/*
4443*4882a593Smuzhiyun 		 * dynamic FE links have no fixed DAI mapping.
4444*4882a593Smuzhiyun 		 * CODEC<->CODEC links have no direct connection.
4445*4882a593Smuzhiyun 		 */
4446*4882a593Smuzhiyun 		if (rtd->dai_link->dynamic)
4447*4882a593Smuzhiyun 			continue;
4448*4882a593Smuzhiyun 
4449*4882a593Smuzhiyun 		if (rtd->num_cpus == 1) {
4450*4882a593Smuzhiyun 			for_each_rtd_codec_dais(rtd, i, codec_dai)
4451*4882a593Smuzhiyun 				dapm_connect_dai_pair(card, rtd, codec_dai,
4452*4882a593Smuzhiyun 						      asoc_rtd_to_cpu(rtd, 0));
4453*4882a593Smuzhiyun 		} else if (rtd->num_codecs == rtd->num_cpus) {
4454*4882a593Smuzhiyun 			for_each_rtd_codec_dais(rtd, i, codec_dai)
4455*4882a593Smuzhiyun 				dapm_connect_dai_pair(card, rtd, codec_dai,
4456*4882a593Smuzhiyun 						      asoc_rtd_to_cpu(rtd, i));
4457*4882a593Smuzhiyun 		} else {
4458*4882a593Smuzhiyun 			dev_err(card->dev,
4459*4882a593Smuzhiyun 				"N cpus to M codecs link is not supported yet\n");
4460*4882a593Smuzhiyun 		}
4461*4882a593Smuzhiyun 	}
4462*4882a593Smuzhiyun }
4463*4882a593Smuzhiyun 
soc_dapm_stream_event(struct snd_soc_pcm_runtime * rtd,int stream,int event)4464*4882a593Smuzhiyun static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4465*4882a593Smuzhiyun 	int event)
4466*4882a593Smuzhiyun {
4467*4882a593Smuzhiyun 	struct snd_soc_dai *dai;
4468*4882a593Smuzhiyun 	int i;
4469*4882a593Smuzhiyun 
4470*4882a593Smuzhiyun 	for_each_rtd_dais(rtd, i, dai)
4471*4882a593Smuzhiyun 		soc_dapm_dai_stream_event(dai, stream, event);
4472*4882a593Smuzhiyun 
4473*4882a593Smuzhiyun 	dapm_power_widgets(rtd->card, event);
4474*4882a593Smuzhiyun }
4475*4882a593Smuzhiyun 
4476*4882a593Smuzhiyun /**
4477*4882a593Smuzhiyun  * snd_soc_dapm_stream_event - send a stream event to the dapm core
4478*4882a593Smuzhiyun  * @rtd: PCM runtime data
4479*4882a593Smuzhiyun  * @stream: stream name
4480*4882a593Smuzhiyun  * @event: stream event
4481*4882a593Smuzhiyun  *
4482*4882a593Smuzhiyun  * Sends a stream event to the dapm core. The core then makes any
4483*4882a593Smuzhiyun  * necessary widget power changes.
4484*4882a593Smuzhiyun  *
4485*4882a593Smuzhiyun  * Returns 0 for success else error.
4486*4882a593Smuzhiyun  */
snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime * rtd,int stream,int event)4487*4882a593Smuzhiyun void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4488*4882a593Smuzhiyun 			      int event)
4489*4882a593Smuzhiyun {
4490*4882a593Smuzhiyun 	struct snd_soc_card *card = rtd->card;
4491*4882a593Smuzhiyun 
4492*4882a593Smuzhiyun 	mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4493*4882a593Smuzhiyun 	soc_dapm_stream_event(rtd, stream, event);
4494*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
4495*4882a593Smuzhiyun }
4496*4882a593Smuzhiyun 
snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime * rtd,int stream)4497*4882a593Smuzhiyun void snd_soc_dapm_stream_stop(struct snd_soc_pcm_runtime *rtd, int stream)
4498*4882a593Smuzhiyun {
4499*4882a593Smuzhiyun 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
4500*4882a593Smuzhiyun 		if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
4501*4882a593Smuzhiyun 			/* powered down playback stream now */
4502*4882a593Smuzhiyun 			snd_soc_dapm_stream_event(rtd,
4503*4882a593Smuzhiyun 						  SNDRV_PCM_STREAM_PLAYBACK,
4504*4882a593Smuzhiyun 						  SND_SOC_DAPM_STREAM_STOP);
4505*4882a593Smuzhiyun 		} else {
4506*4882a593Smuzhiyun 			/* start delayed pop wq here for playback streams */
4507*4882a593Smuzhiyun 			rtd->pop_wait = 1;
4508*4882a593Smuzhiyun 			queue_delayed_work(system_power_efficient_wq,
4509*4882a593Smuzhiyun 					   &rtd->delayed_work,
4510*4882a593Smuzhiyun 					   msecs_to_jiffies(rtd->pmdown_time));
4511*4882a593Smuzhiyun 		}
4512*4882a593Smuzhiyun 	} else {
4513*4882a593Smuzhiyun 		/* capture streams can be powered down now */
4514*4882a593Smuzhiyun 		snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
4515*4882a593Smuzhiyun 					  SND_SOC_DAPM_STREAM_STOP);
4516*4882a593Smuzhiyun 	}
4517*4882a593Smuzhiyun }
4518*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_stop);
4519*4882a593Smuzhiyun 
4520*4882a593Smuzhiyun /**
4521*4882a593Smuzhiyun  * snd_soc_dapm_enable_pin_unlocked - enable pin.
4522*4882a593Smuzhiyun  * @dapm: DAPM context
4523*4882a593Smuzhiyun  * @pin: pin name
4524*4882a593Smuzhiyun  *
4525*4882a593Smuzhiyun  * Enables input/output pin and its parents or children widgets iff there is
4526*4882a593Smuzhiyun  * a valid audio route and active audio stream.
4527*4882a593Smuzhiyun  *
4528*4882a593Smuzhiyun  * Requires external locking.
4529*4882a593Smuzhiyun  *
4530*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4531*4882a593Smuzhiyun  * do any widget power switching.
4532*4882a593Smuzhiyun  */
snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context * dapm,const char * pin)4533*4882a593Smuzhiyun int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4534*4882a593Smuzhiyun 				   const char *pin)
4535*4882a593Smuzhiyun {
4536*4882a593Smuzhiyun 	return snd_soc_dapm_set_pin(dapm, pin, 1);
4537*4882a593Smuzhiyun }
4538*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
4539*4882a593Smuzhiyun 
4540*4882a593Smuzhiyun /**
4541*4882a593Smuzhiyun  * snd_soc_dapm_enable_pin - enable pin.
4542*4882a593Smuzhiyun  * @dapm: DAPM context
4543*4882a593Smuzhiyun  * @pin: pin name
4544*4882a593Smuzhiyun  *
4545*4882a593Smuzhiyun  * Enables input/output pin and its parents or children widgets iff there is
4546*4882a593Smuzhiyun  * a valid audio route and active audio stream.
4547*4882a593Smuzhiyun  *
4548*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4549*4882a593Smuzhiyun  * do any widget power switching.
4550*4882a593Smuzhiyun  */
snd_soc_dapm_enable_pin(struct snd_soc_dapm_context * dapm,const char * pin)4551*4882a593Smuzhiyun int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
4552*4882a593Smuzhiyun {
4553*4882a593Smuzhiyun 	int ret;
4554*4882a593Smuzhiyun 
4555*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4556*4882a593Smuzhiyun 
4557*4882a593Smuzhiyun 	ret = snd_soc_dapm_set_pin(dapm, pin, 1);
4558*4882a593Smuzhiyun 
4559*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
4560*4882a593Smuzhiyun 
4561*4882a593Smuzhiyun 	return ret;
4562*4882a593Smuzhiyun }
4563*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
4564*4882a593Smuzhiyun 
4565*4882a593Smuzhiyun /**
4566*4882a593Smuzhiyun  * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
4567*4882a593Smuzhiyun  * @dapm: DAPM context
4568*4882a593Smuzhiyun  * @pin: pin name
4569*4882a593Smuzhiyun  *
4570*4882a593Smuzhiyun  * Enables input/output pin regardless of any other state.  This is
4571*4882a593Smuzhiyun  * intended for use with microphone bias supplies used in microphone
4572*4882a593Smuzhiyun  * jack detection.
4573*4882a593Smuzhiyun  *
4574*4882a593Smuzhiyun  * Requires external locking.
4575*4882a593Smuzhiyun  *
4576*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4577*4882a593Smuzhiyun  * do any widget power switching.
4578*4882a593Smuzhiyun  */
snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context * dapm,const char * pin)4579*4882a593Smuzhiyun int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4580*4882a593Smuzhiyun 					 const char *pin)
4581*4882a593Smuzhiyun {
4582*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4583*4882a593Smuzhiyun 
4584*4882a593Smuzhiyun 	if (!w) {
4585*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4586*4882a593Smuzhiyun 		return -EINVAL;
4587*4882a593Smuzhiyun 	}
4588*4882a593Smuzhiyun 
4589*4882a593Smuzhiyun 	dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
4590*4882a593Smuzhiyun 	if (!w->connected) {
4591*4882a593Smuzhiyun 		/*
4592*4882a593Smuzhiyun 		 * w->force does not affect the number of input or output paths,
4593*4882a593Smuzhiyun 		 * so we only have to recheck if w->connected is changed
4594*4882a593Smuzhiyun 		 */
4595*4882a593Smuzhiyun 		dapm_widget_invalidate_input_paths(w);
4596*4882a593Smuzhiyun 		dapm_widget_invalidate_output_paths(w);
4597*4882a593Smuzhiyun 		w->connected = 1;
4598*4882a593Smuzhiyun 	}
4599*4882a593Smuzhiyun 	w->force = 1;
4600*4882a593Smuzhiyun 	dapm_mark_dirty(w, "force enable");
4601*4882a593Smuzhiyun 
4602*4882a593Smuzhiyun 	return 0;
4603*4882a593Smuzhiyun }
4604*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4605*4882a593Smuzhiyun 
4606*4882a593Smuzhiyun /**
4607*4882a593Smuzhiyun  * snd_soc_dapm_force_enable_pin - force a pin to be enabled
4608*4882a593Smuzhiyun  * @dapm: DAPM context
4609*4882a593Smuzhiyun  * @pin: pin name
4610*4882a593Smuzhiyun  *
4611*4882a593Smuzhiyun  * Enables input/output pin regardless of any other state.  This is
4612*4882a593Smuzhiyun  * intended for use with microphone bias supplies used in microphone
4613*4882a593Smuzhiyun  * jack detection.
4614*4882a593Smuzhiyun  *
4615*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4616*4882a593Smuzhiyun  * do any widget power switching.
4617*4882a593Smuzhiyun  */
snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context * dapm,const char * pin)4618*4882a593Smuzhiyun int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4619*4882a593Smuzhiyun 				  const char *pin)
4620*4882a593Smuzhiyun {
4621*4882a593Smuzhiyun 	int ret;
4622*4882a593Smuzhiyun 
4623*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4624*4882a593Smuzhiyun 
4625*4882a593Smuzhiyun 	ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
4626*4882a593Smuzhiyun 
4627*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
4628*4882a593Smuzhiyun 
4629*4882a593Smuzhiyun 	return ret;
4630*4882a593Smuzhiyun }
4631*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4632*4882a593Smuzhiyun 
4633*4882a593Smuzhiyun /**
4634*4882a593Smuzhiyun  * snd_soc_dapm_disable_pin_unlocked - disable pin.
4635*4882a593Smuzhiyun  * @dapm: DAPM context
4636*4882a593Smuzhiyun  * @pin: pin name
4637*4882a593Smuzhiyun  *
4638*4882a593Smuzhiyun  * Disables input/output pin and its parents or children widgets.
4639*4882a593Smuzhiyun  *
4640*4882a593Smuzhiyun  * Requires external locking.
4641*4882a593Smuzhiyun  *
4642*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4643*4882a593Smuzhiyun  * do any widget power switching.
4644*4882a593Smuzhiyun  */
snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context * dapm,const char * pin)4645*4882a593Smuzhiyun int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4646*4882a593Smuzhiyun 				    const char *pin)
4647*4882a593Smuzhiyun {
4648*4882a593Smuzhiyun 	return snd_soc_dapm_set_pin(dapm, pin, 0);
4649*4882a593Smuzhiyun }
4650*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4651*4882a593Smuzhiyun 
4652*4882a593Smuzhiyun /**
4653*4882a593Smuzhiyun  * snd_soc_dapm_disable_pin - disable pin.
4654*4882a593Smuzhiyun  * @dapm: DAPM context
4655*4882a593Smuzhiyun  * @pin: pin name
4656*4882a593Smuzhiyun  *
4657*4882a593Smuzhiyun  * Disables input/output pin and its parents or children widgets.
4658*4882a593Smuzhiyun  *
4659*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4660*4882a593Smuzhiyun  * do any widget power switching.
4661*4882a593Smuzhiyun  */
snd_soc_dapm_disable_pin(struct snd_soc_dapm_context * dapm,const char * pin)4662*4882a593Smuzhiyun int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4663*4882a593Smuzhiyun 			     const char *pin)
4664*4882a593Smuzhiyun {
4665*4882a593Smuzhiyun 	int ret;
4666*4882a593Smuzhiyun 
4667*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4668*4882a593Smuzhiyun 
4669*4882a593Smuzhiyun 	ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4670*4882a593Smuzhiyun 
4671*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
4672*4882a593Smuzhiyun 
4673*4882a593Smuzhiyun 	return ret;
4674*4882a593Smuzhiyun }
4675*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4676*4882a593Smuzhiyun 
4677*4882a593Smuzhiyun /**
4678*4882a593Smuzhiyun  * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4679*4882a593Smuzhiyun  * @dapm: DAPM context
4680*4882a593Smuzhiyun  * @pin: pin name
4681*4882a593Smuzhiyun  *
4682*4882a593Smuzhiyun  * Marks the specified pin as being not connected, disabling it along
4683*4882a593Smuzhiyun  * any parent or child widgets.  At present this is identical to
4684*4882a593Smuzhiyun  * snd_soc_dapm_disable_pin() but in future it will be extended to do
4685*4882a593Smuzhiyun  * additional things such as disabling controls which only affect
4686*4882a593Smuzhiyun  * paths through the pin.
4687*4882a593Smuzhiyun  *
4688*4882a593Smuzhiyun  * Requires external locking.
4689*4882a593Smuzhiyun  *
4690*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4691*4882a593Smuzhiyun  * do any widget power switching.
4692*4882a593Smuzhiyun  */
snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context * dapm,const char * pin)4693*4882a593Smuzhiyun int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4694*4882a593Smuzhiyun 			       const char *pin)
4695*4882a593Smuzhiyun {
4696*4882a593Smuzhiyun 	return snd_soc_dapm_set_pin(dapm, pin, 0);
4697*4882a593Smuzhiyun }
4698*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4699*4882a593Smuzhiyun 
4700*4882a593Smuzhiyun /**
4701*4882a593Smuzhiyun  * snd_soc_dapm_nc_pin - permanently disable pin.
4702*4882a593Smuzhiyun  * @dapm: DAPM context
4703*4882a593Smuzhiyun  * @pin: pin name
4704*4882a593Smuzhiyun  *
4705*4882a593Smuzhiyun  * Marks the specified pin as being not connected, disabling it along
4706*4882a593Smuzhiyun  * any parent or child widgets.  At present this is identical to
4707*4882a593Smuzhiyun  * snd_soc_dapm_disable_pin() but in future it will be extended to do
4708*4882a593Smuzhiyun  * additional things such as disabling controls which only affect
4709*4882a593Smuzhiyun  * paths through the pin.
4710*4882a593Smuzhiyun  *
4711*4882a593Smuzhiyun  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4712*4882a593Smuzhiyun  * do any widget power switching.
4713*4882a593Smuzhiyun  */
snd_soc_dapm_nc_pin(struct snd_soc_dapm_context * dapm,const char * pin)4714*4882a593Smuzhiyun int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
4715*4882a593Smuzhiyun {
4716*4882a593Smuzhiyun 	int ret;
4717*4882a593Smuzhiyun 
4718*4882a593Smuzhiyun 	mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4719*4882a593Smuzhiyun 
4720*4882a593Smuzhiyun 	ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4721*4882a593Smuzhiyun 
4722*4882a593Smuzhiyun 	mutex_unlock(&dapm->card->dapm_mutex);
4723*4882a593Smuzhiyun 
4724*4882a593Smuzhiyun 	return ret;
4725*4882a593Smuzhiyun }
4726*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4727*4882a593Smuzhiyun 
4728*4882a593Smuzhiyun /**
4729*4882a593Smuzhiyun  * snd_soc_dapm_get_pin_status - get audio pin status
4730*4882a593Smuzhiyun  * @dapm: DAPM context
4731*4882a593Smuzhiyun  * @pin: audio signal pin endpoint (or start point)
4732*4882a593Smuzhiyun  *
4733*4882a593Smuzhiyun  * Get audio pin status - connected or disconnected.
4734*4882a593Smuzhiyun  *
4735*4882a593Smuzhiyun  * Returns 1 for connected otherwise 0.
4736*4882a593Smuzhiyun  */
snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context * dapm,const char * pin)4737*4882a593Smuzhiyun int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4738*4882a593Smuzhiyun 				const char *pin)
4739*4882a593Smuzhiyun {
4740*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4741*4882a593Smuzhiyun 
4742*4882a593Smuzhiyun 	if (w)
4743*4882a593Smuzhiyun 		return w->connected;
4744*4882a593Smuzhiyun 
4745*4882a593Smuzhiyun 	return 0;
4746*4882a593Smuzhiyun }
4747*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
4748*4882a593Smuzhiyun 
4749*4882a593Smuzhiyun /**
4750*4882a593Smuzhiyun  * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
4751*4882a593Smuzhiyun  * @dapm: DAPM context
4752*4882a593Smuzhiyun  * @pin: audio signal pin endpoint (or start point)
4753*4882a593Smuzhiyun  *
4754*4882a593Smuzhiyun  * Mark the given endpoint or pin as ignoring suspend.  When the
4755*4882a593Smuzhiyun  * system is disabled a path between two endpoints flagged as ignoring
4756*4882a593Smuzhiyun  * suspend will not be disabled.  The path must already be enabled via
4757*4882a593Smuzhiyun  * normal means at suspend time, it will not be turned on if it was not
4758*4882a593Smuzhiyun  * already enabled.
4759*4882a593Smuzhiyun  */
snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context * dapm,const char * pin)4760*4882a593Smuzhiyun int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4761*4882a593Smuzhiyun 				const char *pin)
4762*4882a593Smuzhiyun {
4763*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
4764*4882a593Smuzhiyun 
4765*4882a593Smuzhiyun 	if (!w) {
4766*4882a593Smuzhiyun 		dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4767*4882a593Smuzhiyun 		return -EINVAL;
4768*4882a593Smuzhiyun 	}
4769*4882a593Smuzhiyun 
4770*4882a593Smuzhiyun 	w->ignore_suspend = 1;
4771*4882a593Smuzhiyun 
4772*4882a593Smuzhiyun 	return 0;
4773*4882a593Smuzhiyun }
4774*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4775*4882a593Smuzhiyun 
4776*4882a593Smuzhiyun /**
4777*4882a593Smuzhiyun  * snd_soc_dapm_free - free dapm resources
4778*4882a593Smuzhiyun  * @dapm: DAPM context
4779*4882a593Smuzhiyun  *
4780*4882a593Smuzhiyun  * Free all dapm widgets and resources.
4781*4882a593Smuzhiyun  */
snd_soc_dapm_free(struct snd_soc_dapm_context * dapm)4782*4882a593Smuzhiyun void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
4783*4882a593Smuzhiyun {
4784*4882a593Smuzhiyun 	dapm_debugfs_cleanup(dapm);
4785*4882a593Smuzhiyun 	dapm_free_widgets(dapm);
4786*4882a593Smuzhiyun 	list_del(&dapm->list);
4787*4882a593Smuzhiyun }
4788*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4789*4882a593Smuzhiyun 
snd_soc_dapm_init(struct snd_soc_dapm_context * dapm,struct snd_soc_card * card,struct snd_soc_component * component)4790*4882a593Smuzhiyun void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm,
4791*4882a593Smuzhiyun 		       struct snd_soc_card *card,
4792*4882a593Smuzhiyun 		       struct snd_soc_component *component)
4793*4882a593Smuzhiyun {
4794*4882a593Smuzhiyun 	dapm->card		= card;
4795*4882a593Smuzhiyun 	dapm->component		= component;
4796*4882a593Smuzhiyun 	dapm->bias_level	= SND_SOC_BIAS_OFF;
4797*4882a593Smuzhiyun 
4798*4882a593Smuzhiyun 	if (component) {
4799*4882a593Smuzhiyun 		dapm->dev		= component->dev;
4800*4882a593Smuzhiyun 		dapm->idle_bias_off	= !component->driver->idle_bias_on,
4801*4882a593Smuzhiyun 		dapm->suspend_bias_off	= component->driver->suspend_bias_off;
4802*4882a593Smuzhiyun 	} else {
4803*4882a593Smuzhiyun 		dapm->dev		= card->dev;
4804*4882a593Smuzhiyun 	}
4805*4882a593Smuzhiyun 
4806*4882a593Smuzhiyun 	INIT_LIST_HEAD(&dapm->list);
4807*4882a593Smuzhiyun 	/* see for_each_card_dapms */
4808*4882a593Smuzhiyun 	list_add(&dapm->list, &card->dapm_list);
4809*4882a593Smuzhiyun }
4810*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_soc_dapm_init);
4811*4882a593Smuzhiyun 
soc_dapm_shutdown_dapm(struct snd_soc_dapm_context * dapm)4812*4882a593Smuzhiyun static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
4813*4882a593Smuzhiyun {
4814*4882a593Smuzhiyun 	struct snd_soc_card *card = dapm->card;
4815*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *w;
4816*4882a593Smuzhiyun 	LIST_HEAD(down_list);
4817*4882a593Smuzhiyun 	int powerdown = 0;
4818*4882a593Smuzhiyun 
4819*4882a593Smuzhiyun 	mutex_lock(&card->dapm_mutex);
4820*4882a593Smuzhiyun 
4821*4882a593Smuzhiyun 	for_each_card_widgets(dapm->card, w) {
4822*4882a593Smuzhiyun 		if (w->dapm != dapm)
4823*4882a593Smuzhiyun 			continue;
4824*4882a593Smuzhiyun 		if (w->power) {
4825*4882a593Smuzhiyun 			dapm_seq_insert(w, &down_list, false);
4826*4882a593Smuzhiyun 			w->new_power = 0;
4827*4882a593Smuzhiyun 			powerdown = 1;
4828*4882a593Smuzhiyun 		}
4829*4882a593Smuzhiyun 	}
4830*4882a593Smuzhiyun 
4831*4882a593Smuzhiyun 	/* If there were no widgets to power down we're already in
4832*4882a593Smuzhiyun 	 * standby.
4833*4882a593Smuzhiyun 	 */
4834*4882a593Smuzhiyun 	if (powerdown) {
4835*4882a593Smuzhiyun 		if (dapm->bias_level == SND_SOC_BIAS_ON)
4836*4882a593Smuzhiyun 			snd_soc_dapm_set_bias_level(dapm,
4837*4882a593Smuzhiyun 						    SND_SOC_BIAS_PREPARE);
4838*4882a593Smuzhiyun 		dapm_seq_run(card, &down_list, 0, false);
4839*4882a593Smuzhiyun 		if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4840*4882a593Smuzhiyun 			snd_soc_dapm_set_bias_level(dapm,
4841*4882a593Smuzhiyun 						    SND_SOC_BIAS_STANDBY);
4842*4882a593Smuzhiyun 	}
4843*4882a593Smuzhiyun 
4844*4882a593Smuzhiyun 	mutex_unlock(&card->dapm_mutex);
4845*4882a593Smuzhiyun }
4846*4882a593Smuzhiyun 
4847*4882a593Smuzhiyun /*
4848*4882a593Smuzhiyun  * snd_soc_dapm_shutdown - callback for system shutdown
4849*4882a593Smuzhiyun  */
snd_soc_dapm_shutdown(struct snd_soc_card * card)4850*4882a593Smuzhiyun void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4851*4882a593Smuzhiyun {
4852*4882a593Smuzhiyun 	struct snd_soc_dapm_context *dapm;
4853*4882a593Smuzhiyun 
4854*4882a593Smuzhiyun 	for_each_card_dapms(card, dapm) {
4855*4882a593Smuzhiyun 		if (dapm != &card->dapm) {
4856*4882a593Smuzhiyun 			soc_dapm_shutdown_dapm(dapm);
4857*4882a593Smuzhiyun 			if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4858*4882a593Smuzhiyun 				snd_soc_dapm_set_bias_level(dapm,
4859*4882a593Smuzhiyun 							    SND_SOC_BIAS_OFF);
4860*4882a593Smuzhiyun 		}
4861*4882a593Smuzhiyun 	}
4862*4882a593Smuzhiyun 
4863*4882a593Smuzhiyun 	soc_dapm_shutdown_dapm(&card->dapm);
4864*4882a593Smuzhiyun 	if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4865*4882a593Smuzhiyun 		snd_soc_dapm_set_bias_level(&card->dapm,
4866*4882a593Smuzhiyun 					    SND_SOC_BIAS_OFF);
4867*4882a593Smuzhiyun }
4868*4882a593Smuzhiyun 
4869*4882a593Smuzhiyun /* Module information */
4870*4882a593Smuzhiyun MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
4871*4882a593Smuzhiyun MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4872*4882a593Smuzhiyun MODULE_LICENSE("GPL");
4873