blob: dcef67a9bd4854a29c79ad8355343c5f16ae76a2 [file] [log] [blame]
Richard Purdie2b97eab2006-10-06 18:32:18 +02001/*
2 * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
3 *
4 * Copyright 2005 Wolfson Microelectronics PLC.
Liam Girdwoodd3311242008-10-12 13:17:36 +01005 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
Richard Purdie2b97eab2006-10-06 18:32:18 +02006 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
Richard Purdie2b97eab2006-10-06 18:32:18 +020012 * Features:
13 * o Changes power status of internal codec blocks depending on the
14 * dynamic configuration of codec internal audio paths and active
Mark Brown74b8f952009-06-06 11:26:15 +010015 * DACs/ADCs.
Richard Purdie2b97eab2006-10-06 18:32:18 +020016 * o Platform power domain - can support external components i.e. amps and
Liam Girdwood612a3fe2012-02-06 16:05:29 +000017 * mic/headphone insertion events.
Richard Purdie2b97eab2006-10-06 18:32:18 +020018 * o Automatic Mic Bias support
19 * o Jack insertion power event initiation - e.g. hp insertion will enable
20 * sinks, dacs, etc
Liam Girdwood612a3fe2012-02-06 16:05:29 +000021 * o Delayed power down of audio subsystem to reduce pops between a quick
Richard Purdie2b97eab2006-10-06 18:32:18 +020022 * device reopen.
23 *
Richard Purdie2b97eab2006-10-06 18:32:18 +020024 */
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/init.h>
Mark Brown9d0624a2011-02-18 11:49:43 -080029#include <linux/async.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020030#include <linux/delay.h>
31#include <linux/pm.h>
32#include <linux/bitops.h>
33#include <linux/platform_device.h>
34#include <linux/jiffies.h>
Takashi Iwai20496ff2009-08-24 09:40:34 +020035#include <linux/debugfs.h>
Mark Brownf1aac482011-12-05 15:17:06 +000036#include <linux/pm_runtime.h>
Mark Brown62ea8742012-01-21 21:14:48 +000037#include <linux/regulator/consumer.h>
Ola Liljad7e7eb92012-05-24 15:26:25 +020038#include <linux/clk.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090039#include <linux/slab.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020040#include <sound/core.h>
41#include <sound/pcm.h>
42#include <sound/pcm_params.h>
Liam Girdwoodce6120c2010-11-05 15:53:46 +020043#include <sound/soc.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020044#include <sound/initval.h>
45
Mark Brown84e90932010-11-04 00:07:02 -040046#include <trace/events/asoc.h>
47
Mark Brownde02d072011-09-20 21:43:24 +010048#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
49
Lars-Peter Clausena3423b02015-08-11 21:38:00 +020050#define SND_SOC_DAPM_DIR_REVERSE(x) ((x == SND_SOC_DAPM_DIR_IN) ? \
51 SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN)
52
53#define snd_soc_dapm_for_each_direction(dir) \
54 for ((dir) = SND_SOC_DAPM_DIR_IN; (dir) <= SND_SOC_DAPM_DIR_OUT; \
55 (dir)++)
56
Lars-Peter Clausen57295072013-08-05 11:27:31 +020057static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
58 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
59 const char *control,
60 int (*connected)(struct snd_soc_dapm_widget *source,
61 struct snd_soc_dapm_widget *sink));
Vladimir Zapolskiy5353f652015-06-02 00:57:53 +030062
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +010063struct snd_soc_dapm_widget *
Lars-Peter Clausen57295072013-08-05 11:27:31 +020064snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
65 const struct snd_soc_dapm_widget *widget);
66
Liam Girdwood02aa78a2015-05-25 18:21:17 +010067struct snd_soc_dapm_widget *
68snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +020069 const struct snd_soc_dapm_widget *widget);
70
Richard Purdie2b97eab2006-10-06 18:32:18 +020071/* dapm power sequences - make this per codec in the future */
72static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010073 [snd_soc_dapm_pre] = 0,
Mark Brown62ea8742012-01-21 21:14:48 +000074 [snd_soc_dapm_regulator_supply] = 1,
Ola Liljad7e7eb92012-05-24 15:26:25 +020075 [snd_soc_dapm_clock_supply] = 1,
Mark Brown1dd275b2013-10-09 13:56:37 +010076 [snd_soc_dapm_supply] = 2,
77 [snd_soc_dapm_micbias] = 3,
Mark Brownc74184e2012-04-04 22:12:09 +010078 [snd_soc_dapm_dai_link] = 2,
Mark Brown1dd275b2013-10-09 13:56:37 +010079 [snd_soc_dapm_dai_in] = 4,
80 [snd_soc_dapm_dai_out] = 4,
81 [snd_soc_dapm_aif_in] = 4,
82 [snd_soc_dapm_aif_out] = 4,
83 [snd_soc_dapm_mic] = 5,
84 [snd_soc_dapm_mux] = 6,
Lars-Peter Clausend714f972015-05-01 18:02:43 +020085 [snd_soc_dapm_demux] = 6,
Mark Brown1dd275b2013-10-09 13:56:37 +010086 [snd_soc_dapm_dac] = 7,
87 [snd_soc_dapm_switch] = 8,
88 [snd_soc_dapm_mixer] = 8,
89 [snd_soc_dapm_mixer_named_ctl] = 8,
90 [snd_soc_dapm_pga] = 9,
91 [snd_soc_dapm_adc] = 10,
92 [snd_soc_dapm_out_drv] = 11,
93 [snd_soc_dapm_hp] = 11,
94 [snd_soc_dapm_spk] = 11,
95 [snd_soc_dapm_line] = 11,
96 [snd_soc_dapm_kcontrol] = 12,
97 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020098};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000099
Richard Purdie2b97eab2006-10-06 18:32:18 +0200100static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +0100101 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200102 [snd_soc_dapm_kcontrol] = 1,
103 [snd_soc_dapm_adc] = 2,
104 [snd_soc_dapm_hp] = 3,
105 [snd_soc_dapm_spk] = 3,
106 [snd_soc_dapm_line] = 3,
107 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +0100108 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +0200109 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +0100110 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +0100111 [snd_soc_dapm_mixer] = 5,
112 [snd_soc_dapm_dac] = 6,
113 [snd_soc_dapm_mic] = 7,
114 [snd_soc_dapm_micbias] = 8,
115 [snd_soc_dapm_mux] = 9,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200116 [snd_soc_dapm_demux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100117 [snd_soc_dapm_aif_in] = 10,
118 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100119 [snd_soc_dapm_dai_in] = 10,
120 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100121 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100122 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100123 [snd_soc_dapm_clock_supply] = 13,
124 [snd_soc_dapm_regulator_supply] = 13,
125 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200126};
127
Mark Brownf9fa2b12014-03-06 16:49:11 +0800128static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
129{
130 if (dapm->card && dapm->card->instantiated)
131 lockdep_assert_held(&dapm->card->dapm_mutex);
132}
133
Troy Kisky12ef1932008-10-13 17:42:14 -0700134static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100135{
136 if (pop_time)
137 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
138}
139
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200140static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100141{
142 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200143 char *buf;
144
145 if (!pop_time)
146 return;
147
148 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
149 if (buf == NULL)
150 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100151
152 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200153 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100154 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100155 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200156
157 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100158}
159
Mark Browndb432b42011-10-03 21:06:40 +0100160static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
161{
162 return !list_empty(&w->dirty);
163}
164
Mark Brown492c0a12014-03-06 16:15:48 +0800165static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100166{
Mark Brownf9fa2b12014-03-06 16:49:11 +0800167 dapm_assert_locked(w->dapm);
168
Mark Brown75c1f892011-10-04 22:28:08 +0100169 if (!dapm_dirty_widget(w)) {
170 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
171 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100172 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100173 }
Mark Browndb432b42011-10-03 21:06:40 +0100174}
175
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200176/*
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200177 * Common implementation for dapm_widget_invalidate_input_paths() and
178 * dapm_widget_invalidate_output_paths(). The function is inlined since the
179 * combined size of the two specialized functions is only marginally larger then
180 * the size of the generic function and at the same time the fast path of the
181 * specialized functions is significantly smaller than the generic function.
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200182 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200183static __always_inline void dapm_widget_invalidate_paths(
184 struct snd_soc_dapm_widget *w, enum snd_soc_dapm_direction dir)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200185{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200186 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
187 struct snd_soc_dapm_widget *node;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200188 struct snd_soc_dapm_path *p;
189 LIST_HEAD(list);
190
191 dapm_assert_locked(w->dapm);
192
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200193 if (w->endpoints[dir] == -1)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200194 return;
195
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200196 list_add_tail(&w->work_list, &list);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200197 w->endpoints[dir] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200198
199 list_for_each_entry(w, &list, work_list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200200 snd_soc_dapm_widget_for_each_path(w, dir, p) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200201 if (p->is_supply || p->weak || !p->connect)
202 continue;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200203 node = p->node[rdir];
204 if (node->endpoints[dir] != -1) {
205 node->endpoints[dir] = -1;
206 list_add_tail(&node->work_list, &list);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200207 }
208 }
209 }
210}
211
212/*
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200213 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of
214 * input paths
215 * @w: The widget for which to invalidate the cached number of input paths
216 *
217 * Resets the cached number of inputs for the specified widget and all widgets
218 * that can be reached via outcoming paths from the widget.
219 *
220 * This function must be called if the number of output paths for a widget might
221 * have changed. E.g. if the source state of a widget changes or a path is added
222 * or activated with the widget as the sink.
223 */
224static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
225{
226 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_IN);
227}
228
229/*
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200230 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
231 * output paths
232 * @w: The widget for which to invalidate the cached number of output paths
233 *
234 * Resets the cached number of outputs for the specified widget and all widgets
235 * that can be reached via incoming paths from the widget.
236 *
237 * This function must be called if the number of output paths for a widget might
238 * have changed. E.g. if the sink state of a widget changes or a path is added
239 * or activated with the widget as the source.
240 */
241static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
242{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200243 dapm_widget_invalidate_paths(w, SND_SOC_DAPM_DIR_OUT);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200244}
245
246/*
247 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
248 * for the widgets connected to a path
249 * @p: The path to invalidate
250 *
251 * Resets the cached number of inputs for the sink of the path and the cached
252 * number of outputs for the source of the path.
253 *
254 * This function must be called when a path is added, removed or the connected
255 * state changes.
256 */
257static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
258{
259 /*
260 * Weak paths or supply paths do not influence the number of input or
261 * output paths of their neighbors.
262 */
263 if (p->weak || p->is_supply)
264 return;
265
266 /*
267 * The number of connected endpoints is the sum of the number of
268 * connected endpoints of all neighbors. If a node with 0 connected
269 * endpoints is either connected or disconnected that sum won't change,
270 * so there is no need to re-check the path.
271 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200272 if (p->source->endpoints[SND_SOC_DAPM_DIR_IN] != 0)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200273 dapm_widget_invalidate_input_paths(p->sink);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200274 if (p->sink->endpoints[SND_SOC_DAPM_DIR_OUT] != 0)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200275 dapm_widget_invalidate_output_paths(p->source);
276}
277
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200278void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
Mark Browne2d32ff2012-08-31 17:38:32 -0700279{
Mark Browne2d32ff2012-08-31 17:38:32 -0700280 struct snd_soc_dapm_widget *w;
281
282 mutex_lock(&card->dapm_mutex);
283
284 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200285 if (w->is_ep) {
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200286 dapm_mark_dirty(w, "Rechecking endpoints");
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200287 if (w->is_ep & SND_SOC_DAPM_EP_SINK)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200288 dapm_widget_invalidate_output_paths(w);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200289 if (w->is_ep & SND_SOC_DAPM_EP_SOURCE)
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200290 dapm_widget_invalidate_input_paths(w);
291 }
Mark Browne2d32ff2012-08-31 17:38:32 -0700292 }
293
294 mutex_unlock(&card->dapm_mutex);
295}
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200296EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
Mark Browne2d32ff2012-08-31 17:38:32 -0700297
Richard Purdie2b97eab2006-10-06 18:32:18 +0200298/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100299static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200300 const struct snd_soc_dapm_widget *_widget)
301{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100302 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200303}
304
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200305struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200306 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200307 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200308 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200309 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200310};
311
312static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100313 struct snd_kcontrol *kcontrol, const char *ctrl_name)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200314{
315 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200316 struct soc_mixer_control *mc;
Charles Keepax561ed682015-05-01 12:37:26 +0100317 struct soc_enum *e;
Charles Keepax773da9b2015-05-01 12:37:25 +0100318 const char *name;
319 int ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200320
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200321 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100322 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200323 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200324
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200325 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200326
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200327 switch (widget->id) {
328 case snd_soc_dapm_switch:
329 case snd_soc_dapm_mixer:
330 case snd_soc_dapm_mixer_named_ctl:
331 mc = (struct soc_mixer_control *)kcontrol->private_value;
332
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800333 if (mc->autodisable && snd_soc_volsw_is_stereo(mc))
334 dev_warn(widget->dapm->dev,
335 "ASoC: Unsupported stereo autodisable control '%s'\n",
336 ctrl_name);
337
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200338 if (mc->autodisable) {
339 struct snd_soc_dapm_widget template;
340
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100341 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
Charles Keepax773da9b2015-05-01 12:37:25 +0100342 "Autodisable");
343 if (!name) {
344 ret = -ENOMEM;
345 goto err_data;
346 }
347
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200348 memset(&template, 0, sizeof(template));
349 template.reg = mc->reg;
350 template.mask = (1 << fls(mc->max)) - 1;
351 template.shift = mc->shift;
352 if (mc->invert)
353 template.off_val = mc->max;
354 else
355 template.off_val = 0;
356 template.on_val = template.off_val;
357 template.id = snd_soc_dapm_kcontrol;
Charles Keepax773da9b2015-05-01 12:37:25 +0100358 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200359
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200360 data->value = template.on_val;
361
Liam Girdwood02aa78a2015-05-25 18:21:17 +0100362 data->widget =
363 snd_soc_dapm_new_control_unlocked(widget->dapm,
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200364 &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200365 kfree(name);
Linus Walleij37e1df82017-01-13 10:23:52 +0100366 if (IS_ERR(data->widget)) {
367 ret = PTR_ERR(data->widget);
368 goto err_data;
369 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200370 if (!data->widget) {
Charles Keepax773da9b2015-05-01 12:37:25 +0100371 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200372 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200373 }
374 }
375 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200376 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100377 case snd_soc_dapm_mux:
378 e = (struct soc_enum *)kcontrol->private_value;
379
380 if (e->autodisable) {
381 struct snd_soc_dapm_widget template;
382
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100383 name = kasprintf(GFP_KERNEL, "%s %s", ctrl_name,
Charles Keepax561ed682015-05-01 12:37:26 +0100384 "Autodisable");
385 if (!name) {
386 ret = -ENOMEM;
387 goto err_data;
388 }
389
390 memset(&template, 0, sizeof(template));
391 template.reg = e->reg;
392 template.mask = e->mask << e->shift_l;
393 template.shift = e->shift_l;
394 template.off_val = snd_soc_enum_item_to_val(e, 0);
395 template.on_val = template.off_val;
396 template.id = snd_soc_dapm_kcontrol;
397 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200398
399 data->value = template.on_val;
400
Charles Keepaxffacb482015-06-26 10:39:43 +0100401 data->widget = snd_soc_dapm_new_control_unlocked(
402 widget->dapm, &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200403 kfree(name);
Linus Walleij37e1df82017-01-13 10:23:52 +0100404 if (IS_ERR(data->widget)) {
405 ret = PTR_ERR(data->widget);
406 goto err_data;
407 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200408 if (!data->widget) {
Charles Keepax561ed682015-05-01 12:37:26 +0100409 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200410 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200411 }
Charles Keepax561ed682015-05-01 12:37:26 +0100412
413 snd_soc_dapm_add_path(widget->dapm, data->widget,
414 widget, NULL, NULL);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200415 }
416 break;
417 default:
418 break;
419 }
420
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200421 kcontrol->private_data = data;
422
423 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100424
Charles Keepax773da9b2015-05-01 12:37:25 +0100425err_data:
426 kfree(data);
427 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200428}
429
430static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
431{
432 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200433 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200434 kfree(data);
435}
436
437static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
438 const struct snd_kcontrol *kcontrol)
439{
440 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
441
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200442 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200443}
444
445static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
446 struct snd_soc_dapm_widget *widget)
447{
448 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200449 struct snd_soc_dapm_widget_list *new_wlist;
450 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200451
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200452 if (data->wlist)
453 n = data->wlist->num_widgets + 1;
454 else
455 n = 1;
456
457 new_wlist = krealloc(data->wlist,
458 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
459 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200460 return -ENOMEM;
461
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200462 new_wlist->widgets[n - 1] = widget;
463 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200464
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200465 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200466
467 return 0;
468}
469
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200470static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
471 struct snd_soc_dapm_path *path)
472{
473 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
474
475 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200476}
477
478static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
479{
480 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
481
482 if (!data->widget)
483 return true;
484
485 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200486}
487
488static struct list_head *dapm_kcontrol_get_path_list(
489 const struct snd_kcontrol *kcontrol)
490{
491 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
492
493 return &data->paths;
494}
495
496#define dapm_kcontrol_for_each_path(path, kcontrol) \
497 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
498 list_kcontrol)
499
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530500unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200501{
502 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
503
504 return data->value;
505}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530506EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200507
508static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
509 unsigned int value)
510{
511 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
512
513 if (data->value == value)
514 return false;
515
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200516 if (data->widget)
517 data->widget->on_val = value;
518
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200519 data->value = value;
520
521 return true;
522}
523
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200524/**
Mythri P K93e39a12015-10-20 22:30:08 +0530525 * snd_soc_dapm_kcontrol_widget() - Returns the widget associated to a
526 * kcontrol
527 * @kcontrol: The kcontrol
528 */
529struct snd_soc_dapm_widget *snd_soc_dapm_kcontrol_widget(
530 struct snd_kcontrol *kcontrol)
531{
532 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0];
533}
534EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_widget);
535
536/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200537 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
538 * kcontrol
539 * @kcontrol: The kcontrol
540 *
541 * Note: This function must only be used on kcontrols that are known to have
542 * been registered for a CODEC. Otherwise the behaviour is undefined.
543 */
544struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
545 struct snd_kcontrol *kcontrol)
546{
547 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
548}
549EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
550
Liam Girdwood6c120e12012-02-15 15:15:34 +0000551static void dapm_reset(struct snd_soc_card *card)
552{
553 struct snd_soc_dapm_widget *w;
554
Mark Brownf9fa2b12014-03-06 16:49:11 +0800555 lockdep_assert_held(&card->dapm_mutex);
556
Liam Girdwood6c120e12012-02-15 15:15:34 +0000557 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
558
559 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200560 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000561 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000562 }
563}
564
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200565static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
566{
567 if (!dapm->component)
568 return NULL;
569 return dapm->component->name_prefix;
570}
571
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200572static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800573 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100574{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200575 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200576 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200577 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100578}
579
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200580static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800581 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100582{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200583 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200584 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000585 return snd_soc_component_update_bits(dapm->component, reg,
586 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000587}
588
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200589static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
590 int reg, unsigned int mask, unsigned int value)
591{
592 if (!dapm->component)
593 return -EIO;
594 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
595}
596
Mark Browneb270e92013-10-09 13:52:52 +0100597static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
598{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200599 if (dapm->component)
600 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100601}
602
Charles Keepax45a110a2015-05-11 13:50:30 +0100603static struct snd_soc_dapm_widget *
604dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
605{
606 struct snd_soc_dapm_widget *w = wcache->widget;
607 struct list_head *wlist;
608 const int depth = 2;
609 int i = 0;
610
611 if (w) {
612 wlist = &w->dapm->card->widgets;
613
614 list_for_each_entry_from(w, wlist, list) {
615 if (!strcmp(name, w->name))
616 return w;
617
618 if (++i == depth)
619 break;
620 }
621 }
622
623 return NULL;
624}
625
626static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
627 struct snd_soc_dapm_widget *w)
628{
629 wcache->widget = w;
630}
631
Mark Brown452c5ea2009-05-17 21:41:23 +0100632/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200633 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
634 * @dapm: The DAPM context for which to set the level
635 * @level: The level to set
636 *
637 * Forces the DAPM bias level to a specific state. It will call the bias level
638 * callback of DAPM context with the specified level. This will even happen if
639 * the context is already at the same level. Furthermore it will not go through
640 * the normal bias level sequencing, meaning any intermediate states between the
641 * current and the target state will not be entered.
642 *
643 * Note that the change in bias level is only temporary and the next time
644 * snd_soc_dapm_sync() is called the state will be set to the level as
645 * determined by the DAPM core. The function is mainly intended to be used to
646 * used during probe or resume from suspend to power up the device so
647 * initialization can be done, before the DAPM core takes over.
648 */
649int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
650 enum snd_soc_bias_level level)
651{
652 int ret = 0;
653
654 if (dapm->set_bias_level)
655 ret = dapm->set_bias_level(dapm, level);
656
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200657 if (ret == 0)
658 dapm->bias_level = level;
659
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200660 return ret;
661}
662EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
663
Mark Brown452c5ea2009-05-17 21:41:23 +0100664/**
665 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800666 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100667 * @level: level to configure
668 *
669 * Configure the bias (power) levels for the SoC audio device.
670 *
671 * Returns 0 for success else error.
672 */
Mark Browned5a4c42011-02-18 11:12:42 -0800673static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200674 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100675{
Mark Browned5a4c42011-02-18 11:12:42 -0800676 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100677 int ret = 0;
678
Mark Brown84e90932010-11-04 00:07:02 -0400679 trace_snd_soc_bias_level_start(card, level);
680
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000681 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100682 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100683 if (ret != 0)
684 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100685
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200686 if (!card || dapm != &card->dapm)
687 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100688
Mark Brown171ec6b2011-06-06 18:15:19 +0100689 if (ret != 0)
690 goto out;
691
692 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100693 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100694out:
Mark Brown84e90932010-11-04 00:07:02 -0400695 trace_snd_soc_bias_level_done(card, level);
696
Mark Brown452c5ea2009-05-17 21:41:23 +0100697 return ret;
698}
699
Mark Brown74b8f952009-06-06 11:26:15 +0100700/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200701static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200702 struct snd_soc_dapm_path *path, const char *control_name,
703 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200704{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200705 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200706 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100707 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200708 int i;
709
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100710 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200711 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100712 val = (val >> e->shift_l) & e->mask;
713 item = snd_soc_enum_val_to_item(e, val);
714 } else {
715 /* since a virtual mux has no backing registers to
716 * decide which path to connect, it will try to match
717 * with the first enumeration. This is to ensure
718 * that the default mux choice (the first) will be
719 * correctly powered up during initialization.
720 */
721 item = 0;
722 }
723
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100724 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200725 if (!(strcmp(control_name, e->texts[i]))) {
Rasmus Villemoes98ad73c2014-10-21 17:01:15 +0200726 path->name = e->texts[i];
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100727 if (i == item)
728 path->connect = 1;
729 else
730 path->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200731 return 0;
732 }
733 }
734
735 return -ENODEV;
736}
737
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100738/* set up initial codec paths */
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800739static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i,
740 int nth_path)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100741{
742 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200743 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100744 unsigned int reg = mc->reg;
745 unsigned int shift = mc->shift;
746 unsigned int max = mc->max;
747 unsigned int mask = (1 << fls(max)) - 1;
748 unsigned int invert = mc->invert;
749 unsigned int val;
750
751 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200752 soc_dapm_read(p->sink->dapm, reg, &val);
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800753 /*
754 * The nth_path argument allows this function to know
755 * which path of a kcontrol it is setting the initial
756 * status for. Ideally this would support any number
757 * of paths and channels. But since kcontrols only come
758 * in mono and stereo variants, we are limited to 2
759 * channels.
760 *
761 * The following code assumes for stereo controls the
762 * first path is the left channel, and all remaining
763 * paths are the right channel.
764 */
765 if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) {
766 if (reg != mc->rreg)
767 soc_dapm_read(p->sink->dapm, mc->rreg, &val);
768 val = (val >> mc->rshift) & mask;
769 } else {
770 val = (val >> shift) & mask;
771 }
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100772 if (invert)
773 val = max - val;
774 p->connect = !!val;
775 } else {
776 p->connect = 0;
777 }
778}
779
Mark Brown74b8f952009-06-06 11:26:15 +0100780/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200781static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200782 struct snd_soc_dapm_path *path, const char *control_name)
783{
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800784 int i, nth_path = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200785
786 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200787 for (i = 0; i < path->sink->num_kcontrols; i++) {
788 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
789 path->name = path->sink->kcontrol_news[i].name;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +0800790 dapm_set_mixer_path_status(path, i, nth_path++);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200791 return 0;
792 }
793 }
794 return -ENODEV;
795}
796
Stephen Warrenaf468002011-04-28 17:38:01 -0600797static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600798 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600799 const struct snd_kcontrol_new *kcontrol_new,
800 struct snd_kcontrol **kcontrol)
801{
802 struct snd_soc_dapm_widget *w;
803 int i;
804
805 *kcontrol = NULL;
806
807 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600808 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
809 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600810 for (i = 0; i < w->num_kcontrols; i++) {
811 if (&w->kcontrol_news[i] == kcontrol_new) {
812 if (w->kcontrols)
813 *kcontrol = w->kcontrols[i];
814 return 1;
815 }
816 }
817 }
818
819 return 0;
820}
821
Stephen Warren85762e72013-03-29 15:40:10 -0600822/*
823 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
824 * create it. Either way, add the widget into the control's widget list
825 */
Jeeja KP19a2557b2015-10-20 22:30:06 +0530826static int dapm_create_or_share_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100827 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200828{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200829 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000830 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000831 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600832 size_t prefix_len;
833 int shared;
834 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600835 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200836 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600837 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200838 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000839
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200840 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000841 if (prefix)
842 prefix_len = strlen(prefix) + 1;
843 else
844 prefix_len = 0;
845
Stephen Warren85762e72013-03-29 15:40:10 -0600846 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
847 &kcontrol);
848
Stephen Warren85762e72013-03-29 15:40:10 -0600849 if (!kcontrol) {
850 if (shared) {
851 wname_in_long_name = false;
852 kcname_in_long_name = true;
853 } else {
854 switch (w->id) {
855 case snd_soc_dapm_switch:
856 case snd_soc_dapm_mixer:
Jeeja KP19a2557b2015-10-20 22:30:06 +0530857 case snd_soc_dapm_pga:
Chen-Yu Tsaia3930ed2016-08-27 19:28:00 +0800858 case snd_soc_dapm_out_drv:
Stephen Warren85762e72013-03-29 15:40:10 -0600859 wname_in_long_name = true;
860 kcname_in_long_name = true;
861 break;
862 case snd_soc_dapm_mixer_named_ctl:
863 wname_in_long_name = false;
864 kcname_in_long_name = true;
865 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200866 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600867 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600868 wname_in_long_name = true;
869 kcname_in_long_name = false;
870 break;
871 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600872 return -EINVAL;
873 }
874 }
875
876 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600877 /*
878 * The control will get a prefix from the control
879 * creation process but we're also using the same
880 * prefix for widgets so cut the prefix off the
881 * front of the widget name.
882 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200883 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600884 w->name + prefix_len,
885 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200886 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200887 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600888
889 name = long_name;
890 } else if (wname_in_long_name) {
891 long_name = NULL;
892 name = w->name + prefix_len;
893 } else {
894 long_name = NULL;
895 name = w->kcontrol_news[kci].name;
896 }
897
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200898 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600899 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200900 if (!kcontrol) {
901 ret = -ENOMEM;
902 goto exit_free;
903 }
904
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200905 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200906
Lars-Peter Clausen41d80022016-02-03 21:59:50 +0100907 ret = dapm_kcontrol_data_alloc(w, kcontrol, name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200908 if (ret) {
909 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200910 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200911 }
912
Stephen Warren85762e72013-03-29 15:40:10 -0600913 ret = snd_ctl_add(card, kcontrol);
914 if (ret < 0) {
915 dev_err(dapm->dev,
916 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
917 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200918 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600919 }
Stephen Warren85762e72013-03-29 15:40:10 -0600920 }
921
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200922 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200923 if (ret == 0)
924 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200925
Daniel Macke5092c92014-10-07 13:41:24 +0200926exit_free:
927 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600928
Daniel Macke5092c92014-10-07 13:41:24 +0200929 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600930}
931
932/* create new dapm mixer control */
933static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
934{
935 int i, ret;
936 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100937 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600938
Richard Purdie2b97eab2006-10-06 18:32:18 +0200939 /* add kcontrol */
940 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200941 /* match name */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200942 snd_soc_dapm_widget_for_each_source_path(w, path) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200943 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600944 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200945 continue;
946
Charles Keepax561ed682015-05-01 12:37:26 +0100947 if (!w->kcontrols[i]) {
Jeeja KP19a2557b2015-10-20 22:30:06 +0530948 ret = dapm_create_or_share_kcontrol(w, i);
Charles Keepax561ed682015-05-01 12:37:26 +0100949 if (ret < 0)
950 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200951 }
952
Mark Brown946d92a2013-08-12 23:28:42 +0100953 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100954
955 data = snd_kcontrol_chip(w->kcontrols[i]);
956 if (data->widget)
957 snd_soc_dapm_add_path(data->widget->dapm,
958 data->widget,
959 path->source,
960 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200961 }
962 }
Stephen Warren85762e72013-03-29 15:40:10 -0600963
964 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200965}
966
967/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200968static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200969{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200970 struct snd_soc_dapm_context *dapm = w->dapm;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200971 enum snd_soc_dapm_direction dir;
Stephen Warren85762e72013-03-29 15:40:10 -0600972 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200973 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600974 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200975
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200976 switch (w->id) {
977 case snd_soc_dapm_mux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200978 dir = SND_SOC_DAPM_DIR_OUT;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200979 type = "mux";
980 break;
981 case snd_soc_dapm_demux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200982 dir = SND_SOC_DAPM_DIR_IN;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200983 type = "demux";
984 break;
985 default:
986 return -EINVAL;
987 }
988
Stephen Warrenaf468002011-04-28 17:38:01 -0600989 if (w->num_kcontrols != 1) {
990 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200991 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600992 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200993 return -EINVAL;
994 }
995
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200996 if (list_empty(&w->edges[dir])) {
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200997 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600998 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600999 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001000
Jeeja KP19a2557b2015-10-20 22:30:06 +05301001 ret = dapm_create_or_share_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -06001002 if (ret < 0)
1003 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -06001004
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001005 snd_soc_dapm_widget_for_each_path(w, dir, path) {
1006 if (path->name)
1007 dapm_kcontrol_add_path(w->kcontrols[0], path);
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +02001008 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001009
Stephen Warrenaf468002011-04-28 17:38:01 -06001010 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001011}
1012
1013/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02001014static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001015{
Jeeja KP19a2557b2015-10-20 22:30:06 +05301016 int i, ret;
1017
1018 for (i = 0; i < w->num_kcontrols; i++) {
1019 ret = dapm_create_or_share_kcontrol(w, i);
1020 if (ret < 0)
1021 return ret;
1022 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001023
Mark Browna6c65732010-03-03 17:45:21 +00001024 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001025}
1026
Nikesh Oswalc6615082015-02-02 17:06:44 +00001027/* create new dapm dai link control */
1028static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
1029{
1030 int i, ret;
1031 struct snd_kcontrol *kcontrol;
1032 struct snd_soc_dapm_context *dapm = w->dapm;
1033 struct snd_card *card = dapm->card->snd_card;
1034
1035 /* create control for links with > 1 config */
1036 if (w->num_params <= 1)
1037 return 0;
1038
1039 /* add kcontrol */
1040 for (i = 0; i < w->num_kcontrols; i++) {
1041 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
1042 w->name, NULL);
1043 ret = snd_ctl_add(card, kcontrol);
1044 if (ret < 0) {
1045 dev_err(dapm->dev,
1046 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
1047 w->name, w->kcontrol_news[i].name, ret);
1048 return ret;
1049 }
1050 kcontrol->private_data = w;
1051 w->kcontrols[i] = kcontrol;
1052 }
1053
1054 return 0;
1055}
1056
Mark Brown99497882010-05-07 20:24:05 +01001057/* We implement power down on suspend by checking the power state of
1058 * the ALSA card - when we are suspending the ALSA state for the card
1059 * is set to D3.
1060 */
1061static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1062{
Mark Brown12ea2c72011-03-02 18:17:32 +00001063 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +01001064
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001065 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +01001066 case SNDRV_CTL_POWER_D3hot:
1067 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +01001068 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001069 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001070 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +01001071 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +01001072 default:
1073 return 1;
1074 }
1075}
1076
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001077static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1078 struct list_head *widgets)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001079{
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001080 struct snd_soc_dapm_widget *w;
1081 struct list_head *it;
1082 unsigned int size = 0;
1083 unsigned int i = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001084
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001085 list_for_each(it, widgets)
1086 size++;
1087
1088 *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001089 if (*list == NULL)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001090 return -ENOMEM;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001091
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001092 list_for_each_entry(w, widgets, work_list)
1093 (*list)->widgets[i++] = w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001094
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001095 (*list)->num_widgets = i;
1096
1097 return 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001098}
1099
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001100/*
1101 * Common implementation for is_connected_output_ep() and
1102 * is_connected_input_ep(). The function is inlined since the combined size of
1103 * the two specialized functions is only marginally larger then the size of the
1104 * generic function and at the same time the fast path of the specialized
1105 * functions is significantly smaller than the generic function.
1106 */
1107static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
1108 struct list_head *list, enum snd_soc_dapm_direction dir,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001109 int (*fn)(struct snd_soc_dapm_widget *, struct list_head *,
1110 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1111 enum snd_soc_dapm_direction)),
1112 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1113 enum snd_soc_dapm_direction))
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001114{
1115 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001116 struct snd_soc_dapm_path *path;
1117 int con = 0;
1118
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001119 if (widget->endpoints[dir] >= 0)
1120 return widget->endpoints[dir];
Mark Brown024dc072011-10-09 11:52:05 +01001121
Mark Brownde02d072011-09-20 21:43:24 +01001122 DAPM_UPDATE_STAT(widget, path_checks);
1123
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001124 /* do we need to add this widget to the list ? */
1125 if (list)
1126 list_add_tail(&widget->work_list, list);
1127
Jeeja KP09464972016-06-15 11:16:55 +05301128 if (custom_stop_condition && custom_stop_condition(widget, dir)) {
1129 widget->endpoints[dir] = 1;
1130 return widget->endpoints[dir];
1131 }
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001132
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001133 if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
1134 widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
1135 return widget->endpoints[dir];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001136 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001137
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001138 snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
Mark Browne56235e02011-09-21 18:19:14 +01001139 DAPM_UPDATE_STAT(widget, neighbour_checks);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001140
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001141 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001142 continue;
1143
Mark Brown8af294b2013-02-22 17:48:15 +00001144 if (path->walking)
1145 return 1;
1146
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001147 trace_snd_soc_dapm_path(widget, dir, path);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001148
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001149 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001150 path->walking = 1;
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001151 con += fn(path->node[dir], list, custom_stop_condition);
Mark Brown8af294b2013-02-22 17:48:15 +00001152 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001153 }
1154 }
1155
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001156 widget->endpoints[dir] = con;
Mark Brown024dc072011-10-09 11:52:05 +01001157
Richard Purdie2b97eab2006-10-06 18:32:18 +02001158 return con;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001159}
1160
1161/*
1162 * Recursively check for a completed path to an active or physically connected
1163 * output widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001164 *
1165 * Optionally, can be supplied with a function acting as a stopping condition.
1166 * This function takes the dapm widget currently being examined and the walk
1167 * direction as an arguments, it should return true if the walk should be
1168 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001169 */
1170static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001171 struct list_head *list,
1172 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1173 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001174{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001175 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001176 is_connected_output_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001177}
1178
1179/*
1180 * Recursively check for a completed path to an active or physically connected
1181 * input widget. Returns number of complete paths.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001182 *
1183 * Optionally, can be supplied with a function acting as a stopping condition.
1184 * This function takes the dapm widget currently being examined and the walk
1185 * direction as an arguments, it should return true if the walk should be
1186 * stopped and false otherwise.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001187 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001188static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001189 struct list_head *list,
1190 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i,
1191 enum snd_soc_dapm_direction))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001192{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001193 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001194 is_connected_input_ep, custom_stop_condition);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001195}
1196
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001197/**
1198 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1199 * @dai: the soc DAI.
1200 * @stream: stream direction.
1201 * @list: list of active widgets for this stream.
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001202 * @custom_stop_condition: (optional) a function meant to stop the widget graph
1203 * walk based on custom logic.
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001204 *
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001205 * Queries DAPM graph as to whether a valid audio stream path exists for
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001206 * the initial stream specified by name. This takes into account
1207 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1208 *
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001209 * Optionally, can be supplied with a function acting as a stopping condition.
1210 * This function takes the dapm widget currently being examined and the walk
1211 * direction as an arguments, it should return true if the walk should be
1212 * stopped and false otherwise.
1213 *
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001214 * Returns the number of valid paths or negative error.
1215 */
1216int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001217 struct snd_soc_dapm_widget_list **list,
1218 bool (*custom_stop_condition)(struct snd_soc_dapm_widget *,
1219 enum snd_soc_dapm_direction))
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001220{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001221 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001222 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001223 LIST_HEAD(widgets);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001224 int paths;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001225 int ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001226
1227 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001228
1229 /*
1230 * For is_connected_{output,input}_ep fully discover the graph we need
1231 * to reset the cached number of inputs and outputs.
1232 */
1233 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001234 w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
1235 w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001236 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001237
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001238 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001239 paths = is_connected_output_ep(dai->playback_widget, &widgets,
1240 custom_stop_condition);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001241 else
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001242 paths = is_connected_input_ep(dai->capture_widget, &widgets,
1243 custom_stop_condition);
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001244
1245 /* Drop starting point */
1246 list_del(widgets.next);
1247
1248 ret = dapm_widget_list_create(list, &widgets);
1249 if (ret)
Lars-Peter Clausen30abbe72015-08-11 21:37:59 +02001250 paths = ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001251
1252 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001253 mutex_unlock(&card->dapm_mutex);
1254
1255 return paths;
1256}
1257
Richard Purdie2b97eab2006-10-06 18:32:18 +02001258/*
Mark Brown62ea8742012-01-21 21:14:48 +00001259 * Handler for regulator supply widget.
1260 */
1261int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1262 struct snd_kcontrol *kcontrol, int event)
1263{
Mark Brownc05b84d2012-09-07 12:57:11 +08001264 int ret;
1265
Mark Browneb270e92013-10-09 13:52:52 +01001266 soc_dapm_async_complete(w->dapm);
1267
Mark Brownc05b84d2012-09-07 12:57:11 +08001268 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001269 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001270 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001271 if (ret != 0)
1272 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001273 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001274 w->name, ret);
1275 }
1276
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001277 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001278 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001279 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001280 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001281 if (ret != 0)
1282 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001283 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001284 w->name, ret);
1285 }
1286
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001287 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001288 }
Mark Brown62ea8742012-01-21 21:14:48 +00001289}
1290EXPORT_SYMBOL_GPL(dapm_regulator_event);
1291
Ola Liljad7e7eb92012-05-24 15:26:25 +02001292/*
1293 * Handler for clock supply widget.
1294 */
1295int dapm_clock_event(struct snd_soc_dapm_widget *w,
1296 struct snd_kcontrol *kcontrol, int event)
1297{
1298 if (!w->clk)
1299 return -EIO;
1300
Mark Browneb270e92013-10-09 13:52:52 +01001301 soc_dapm_async_complete(w->dapm);
1302
Mark Brownec029952012-06-04 08:16:20 +01001303#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001304 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001305 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001306 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001307 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001308 return 0;
1309 }
Mark Brownec029952012-06-04 08:16:20 +01001310#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001311 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001312}
1313EXPORT_SYMBOL_GPL(dapm_clock_event);
1314
Mark Brownd8050022011-09-28 18:28:23 +01001315static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1316{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001317 if (w->power_checked)
1318 return w->new_power;
1319
Mark Brownd8050022011-09-28 18:28:23 +01001320 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001321 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001322 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001323 w->new_power = w->power_check(w);
1324
1325 w->power_checked = true;
1326
1327 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001328}
1329
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001330/* Generic check to see if a widget should be powered. */
Mark Browncd0f2d42009-04-20 16:56:59 +01001331static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1332{
1333 int in, out;
1334
Mark Brownde02d072011-09-20 21:43:24 +01001335 DAPM_UPDATE_STAT(w, power_checks);
1336
Piotr Stankiewicz67420642016-05-13 17:03:55 +01001337 in = is_connected_input_ep(w, NULL, NULL);
1338 out = is_connected_output_ep(w, NULL, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001339 return out != 0 && in != 0;
1340}
1341
Mark Brown246d0a12009-04-22 18:24:55 +01001342/* Check to see if a power supply is needed */
1343static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1344{
1345 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001346
Mark Brownde02d072011-09-20 21:43:24 +01001347 DAPM_UPDATE_STAT(w, power_checks);
1348
Mark Brown246d0a12009-04-22 18:24:55 +01001349 /* Check if one of our outputs is connected */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001350 snd_soc_dapm_widget_for_each_sink_path(w, path) {
Mark Browna8fdac82011-09-28 18:20:26 +01001351 DAPM_UPDATE_STAT(w, neighbour_checks);
1352
Mark Brownbf3a9e12011-06-13 16:42:29 +01001353 if (path->weak)
1354 continue;
1355
Mark Brown215edda2009-09-08 18:59:05 +01001356 if (path->connected &&
1357 !path->connected(path->source, path->sink))
1358 continue;
1359
Mark Brownf68d7e12011-10-04 22:57:50 +01001360 if (dapm_widget_power_check(path->sink))
1361 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001362 }
1363
Mark Brownf68d7e12011-10-04 22:57:50 +01001364 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001365}
1366
Mark Brown35c64bc2011-09-28 18:23:53 +01001367static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1368{
Charles Keepax20bb0182015-12-02 10:22:16 +00001369 return w->connected;
Mark Brown35c64bc2011-09-28 18:23:53 +01001370}
1371
Mark Brown38357ab2009-06-06 19:03:23 +01001372static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1373 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001374 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001375{
Mark Brown828a8422011-01-15 13:14:30 +00001376 int *sort;
1377
1378 if (power_up)
1379 sort = dapm_up_seq;
1380 else
1381 sort = dapm_down_seq;
1382
Mark Brown38357ab2009-06-06 19:03:23 +01001383 if (sort[a->id] != sort[b->id])
1384 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001385 if (a->subseq != b->subseq) {
1386 if (power_up)
1387 return a->subseq - b->subseq;
1388 else
1389 return b->subseq - a->subseq;
1390 }
Mark Brownb22ead22009-06-07 12:51:26 +01001391 if (a->reg != b->reg)
1392 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001393 if (a->dapm != b->dapm)
1394 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001395
Mark Brown38357ab2009-06-06 19:03:23 +01001396 return 0;
1397}
Mark Brown42aa3412009-03-01 19:21:10 +00001398
Mark Brown38357ab2009-06-06 19:03:23 +01001399/* Insert a widget in order into a DAPM power sequence. */
1400static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1401 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001402 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001403{
1404 struct snd_soc_dapm_widget *w;
1405
1406 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001407 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001408 list_add_tail(&new_widget->power_list, &w->power_list);
1409 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001410 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001411
Mark Brown38357ab2009-06-06 19:03:23 +01001412 list_add_tail(&new_widget->power_list, list);
1413}
Mark Brown42aa3412009-03-01 19:21:10 +00001414
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001415static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001416 struct snd_soc_dapm_widget *w, int event)
1417{
Mark Brown68f89ad2010-11-03 23:51:49 -04001418 const char *ev_name;
1419 int power, ret;
1420
1421 switch (event) {
1422 case SND_SOC_DAPM_PRE_PMU:
1423 ev_name = "PRE_PMU";
1424 power = 1;
1425 break;
1426 case SND_SOC_DAPM_POST_PMU:
1427 ev_name = "POST_PMU";
1428 power = 1;
1429 break;
1430 case SND_SOC_DAPM_PRE_PMD:
1431 ev_name = "PRE_PMD";
1432 power = 0;
1433 break;
1434 case SND_SOC_DAPM_POST_PMD:
1435 ev_name = "POST_PMD";
1436 power = 0;
1437 break;
Mark Brown80114122013-02-25 15:14:19 +00001438 case SND_SOC_DAPM_WILL_PMU:
1439 ev_name = "WILL_PMU";
1440 power = 1;
1441 break;
1442 case SND_SOC_DAPM_WILL_PMD:
1443 ev_name = "WILL_PMD";
1444 power = 0;
1445 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001446 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001447 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001448 return;
1449 }
1450
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001451 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001452 return;
1453
1454 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001455 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001456 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001457 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001458 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001459 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001460 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001461 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001462 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001463 ev_name, w->name, ret);
1464 }
1465}
1466
Mark Brownb22ead22009-06-07 12:51:26 +01001467/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001468static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001469 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001470{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001471 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001472 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001473 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001474 unsigned int value = 0;
1475 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001476
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001477 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1478 reg = w->reg;
1479 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001480
1481 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001482 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001483 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001484
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001485 mask |= w->mask << w->shift;
1486 if (w->power)
1487 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001488 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001489 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001490
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001491 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001492 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1493 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001494
Mark Brown68f89ad2010-11-03 23:51:49 -04001495 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001496 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1497 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001498 }
1499
Mark Brown81628102009-06-07 13:21:24 +01001500 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001501 /* Any widget will do, they should all be updating the
1502 * same register.
1503 */
Mark Brown29376bc2011-06-19 13:49:28 +01001504
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001505 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001506 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001507 value, mask, reg, card->pop_time);
1508 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001509 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001510 }
1511
1512 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001513 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1514 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001515 }
Mark Brown42aa3412009-03-01 19:21:10 +00001516}
1517
Mark Brownb22ead22009-06-07 12:51:26 +01001518/* Apply a DAPM power sequence.
1519 *
1520 * We walk over a pre-sorted list of widgets to apply power to. In
1521 * order to minimise the number of writes to the device required
1522 * multiple widgets will be updated in a single write where possible.
1523 * Currently anything that requires more than a single write is not
1524 * handled.
1525 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001526static void dapm_seq_run(struct snd_soc_card *card,
1527 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001528{
1529 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001530 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001531 LIST_HEAD(pending);
1532 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001533 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001534 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001535 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001536 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001537 int *sort;
1538
1539 if (power_up)
1540 sort = dapm_up_seq;
1541 else
1542 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001543
Mark Brownb22ead22009-06-07 12:51:26 +01001544 list_for_each_entry_safe(w, n, list, power_list) {
1545 ret = 0;
1546
1547 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001548 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001549 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001550 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001551 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001552
Mark Brown474b62d2011-01-18 16:14:44 +00001553 if (cur_dapm && cur_dapm->seq_notifier) {
1554 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1555 if (sort[i] == cur_sort)
1556 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001557 i,
1558 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001559 }
1560
Mark Browneb270e92013-10-09 13:52:52 +01001561 if (cur_dapm && w->dapm != cur_dapm)
1562 soc_dapm_async_complete(cur_dapm);
1563
Mark Brownb22ead22009-06-07 12:51:26 +01001564 INIT_LIST_HEAD(&pending);
1565 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001566 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001567 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001568 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001569 }
1570
Mark Brown163cac02009-06-07 10:12:52 +01001571 switch (w->id) {
1572 case snd_soc_dapm_pre:
1573 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001574 list_for_each_entry_safe_continue(w, n, list,
1575 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001576
Mark Brownb22ead22009-06-07 12:51:26 +01001577 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001578 ret = w->event(w,
1579 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001580 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001581 ret = w->event(w,
1582 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001583 break;
1584
1585 case snd_soc_dapm_post:
1586 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001587 list_for_each_entry_safe_continue(w, n, list,
1588 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001589
Mark Brownb22ead22009-06-07 12:51:26 +01001590 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001591 ret = w->event(w,
1592 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001593 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001594 ret = w->event(w,
1595 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001596 break;
1597
Mark Brown163cac02009-06-07 10:12:52 +01001598 default:
Mark Brown81628102009-06-07 13:21:24 +01001599 /* Queue it up for application */
1600 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001601 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001602 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001603 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001604 list_move(&w->power_list, &pending);
1605 break;
Mark Brown163cac02009-06-07 10:12:52 +01001606 }
Mark Brownb22ead22009-06-07 12:51:26 +01001607
1608 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001609 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001610 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001611 }
Mark Brownb22ead22009-06-07 12:51:26 +01001612
1613 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001614 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001615
1616 if (cur_dapm && cur_dapm->seq_notifier) {
1617 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1618 if (sort[i] == cur_sort)
1619 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001620 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001621 }
Mark Browneb270e92013-10-09 13:52:52 +01001622
1623 list_for_each_entry(d, &card->dapm_list, list) {
1624 soc_dapm_async_complete(d);
1625 }
Mark Brown163cac02009-06-07 10:12:52 +01001626}
1627
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001628static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001629{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001630 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001631 struct snd_soc_dapm_widget_list *wlist;
1632 struct snd_soc_dapm_widget *w = NULL;
1633 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001634 int ret;
1635
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001636 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001637 return;
1638
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001639 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001640
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001641 for (wi = 0; wi < wlist->num_widgets; wi++) {
1642 w = wlist->widgets[wi];
1643
1644 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1645 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1646 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001647 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001648 w->name, ret);
1649 }
Mark Brown97404f22010-12-14 16:13:57 +00001650 }
1651
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001652 if (!w)
1653 return;
1654
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001655 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1656 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001657 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001658 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001659 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001660
Chen-Yu Tsaie411b0b2016-11-02 15:35:58 +08001661 if (update->has_second_set) {
1662 ret = soc_dapm_update_bits(w->dapm, update->reg2,
1663 update->mask2, update->val2);
1664 if (ret < 0)
1665 dev_err(w->dapm->dev,
1666 "ASoC: %s DAPM update failed: %d\n",
1667 w->name, ret);
1668 }
1669
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001670 for (wi = 0; wi < wlist->num_widgets; wi++) {
1671 w = wlist->widgets[wi];
1672
1673 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1674 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1675 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001676 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001677 w->name, ret);
1678 }
Mark Brown97404f22010-12-14 16:13:57 +00001679 }
1680}
1681
Mark Brown9d0624a2011-02-18 11:49:43 -08001682/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1683 * they're changing state.
1684 */
1685static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1686{
1687 struct snd_soc_dapm_context *d = data;
1688 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001689
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001690 /* If we're off and we're not supposed to go into STANDBY */
Mark Brown56fba412011-06-04 11:25:10 +01001691 if (d->bias_level == SND_SOC_BIAS_OFF &&
1692 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001693 if (d->dev)
1694 pm_runtime_get_sync(d->dev);
1695
Mark Brown9d0624a2011-02-18 11:49:43 -08001696 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1697 if (ret != 0)
1698 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001699 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001700 }
1701
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001702 /* Prepare for a transition to ON or away from ON */
1703 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1704 d->bias_level != SND_SOC_BIAS_ON) ||
1705 (d->target_bias_level != SND_SOC_BIAS_ON &&
1706 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001707 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1708 if (ret != 0)
1709 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001710 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001711 }
1712}
1713
1714/* Async callback run prior to DAPM sequences - brings to their final
1715 * state.
1716 */
1717static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1718{
1719 struct snd_soc_dapm_context *d = data;
1720 int ret;
1721
1722 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001723 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1724 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1725 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001726 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1727 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001728 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001729 ret);
1730 }
1731
1732 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001733 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1734 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001735 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1736 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001737 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1738 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001739
1740 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001741 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001742 }
1743
1744 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001745 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1746 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001747 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1748 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001749 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001750 ret);
1751 }
1752}
Mark Brown97404f22010-12-14 16:13:57 +00001753
Mark Brownfe4fda52011-10-03 22:36:57 +01001754static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1755 bool power, bool connect)
1756{
1757 /* If a connection is being made or broken then that update
1758 * will have marked the peer dirty, otherwise the widgets are
1759 * not connected and this update has no impact. */
1760 if (!connect)
1761 return;
1762
1763 /* If the peer is already in the state we're moving to then we
1764 * won't have an impact on it. */
1765 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001766 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001767}
1768
Mark Brown05623c42011-09-28 17:02:31 +01001769static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1770 struct list_head *up_list,
1771 struct list_head *down_list)
1772{
Mark Browndb432b42011-10-03 21:06:40 +01001773 struct snd_soc_dapm_path *path;
1774
Mark Brown05623c42011-09-28 17:02:31 +01001775 if (w->power == power)
1776 return;
1777
1778 trace_snd_soc_dapm_widget_power(w, power);
1779
Mark Browndb432b42011-10-03 21:06:40 +01001780 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001781 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001782 */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001783 snd_soc_dapm_widget_for_each_source_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001784 dapm_widget_set_peer_power(path->source, power, path->connect);
1785
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001786 /* Supplies can't affect their outputs, only their inputs */
1787 if (!w->is_supply) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001788 snd_soc_dapm_widget_for_each_sink_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001789 dapm_widget_set_peer_power(path->sink, power,
1790 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001791 }
1792
Mark Brown05623c42011-09-28 17:02:31 +01001793 if (power)
1794 dapm_seq_insert(w, up_list, true);
1795 else
1796 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001797}
1798
Mark Brown7c81beb2011-09-20 22:22:32 +01001799static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1800 struct list_head *up_list,
1801 struct list_head *down_list)
1802{
Mark Brown7c81beb2011-09-20 22:22:32 +01001803 int power;
1804
1805 switch (w->id) {
1806 case snd_soc_dapm_pre:
1807 dapm_seq_insert(w, down_list, false);
1808 break;
1809 case snd_soc_dapm_post:
1810 dapm_seq_insert(w, up_list, true);
1811 break;
1812
1813 default:
Mark Brownd8050022011-09-28 18:28:23 +01001814 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001815
Mark Brown05623c42011-09-28 17:02:31 +01001816 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001817 break;
1818 }
1819}
1820
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001821static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1822{
1823 if (dapm->idle_bias_off)
1824 return true;
1825
1826 switch (snd_power_get_state(dapm->card->snd_card)) {
1827 case SNDRV_CTL_POWER_D3hot:
1828 case SNDRV_CTL_POWER_D3cold:
1829 return dapm->suspend_bias_off;
1830 default:
1831 break;
1832 }
1833
1834 return false;
1835}
1836
Mark Brown42aa3412009-03-01 19:21:10 +00001837/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001838 * Scan each dapm widget for complete audio path.
1839 * A complete path is a route that has valid endpoints i.e.:-
1840 *
1841 * o DAC to output pin.
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02001842 * o Input pin to ADC.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001843 * o Input pin to Output pin (bypass, sidetone)
1844 * o DAC to ADC (loopback).
1845 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001846static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001847{
1848 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001849 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001850 LIST_HEAD(up_list);
1851 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001852 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001853 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001854
Mark Brownf9fa2b12014-03-06 16:49:11 +08001855 lockdep_assert_held(&card->dapm_mutex);
1856
Mark Brown84e90932010-11-04 00:07:02 -04001857 trace_snd_soc_dapm_start(card);
1858
Mark Brown56fba412011-06-04 11:25:10 +01001859 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001860 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001861 d->target_bias_level = SND_SOC_BIAS_OFF;
1862 else
1863 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001864 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001865
Liam Girdwood6c120e12012-02-15 15:15:34 +00001866 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001867
Mark Brown6d3ddc82009-05-16 17:47:29 +01001868 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001869 * lists indicating if they should be powered up or down. We
1870 * only check widgets that have been flagged as dirty but note
1871 * that new widgets may be added to the dirty list while we
1872 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001873 */
Mark Browndb432b42011-10-03 21:06:40 +01001874 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001875 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001876 }
1877
Mark Brownf9de6d72011-09-28 17:19:47 +01001878 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001879 switch (w->id) {
1880 case snd_soc_dapm_pre:
1881 case snd_soc_dapm_post:
1882 /* These widgets always need to be powered */
1883 break;
1884 default:
1885 list_del_init(&w->dirty);
1886 break;
1887 }
Mark Browndb432b42011-10-03 21:06:40 +01001888
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001889 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001890 d = w->dapm;
1891
1892 /* Supplies and micbiases only bring the
1893 * context up to STANDBY as unless something
1894 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001895 * generally don't require full power. Signal
1896 * generators are virtual pins and have no
1897 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001898 */
1899 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001900 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001901 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001902 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001903 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001904 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001905 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001906 case snd_soc_dapm_micbias:
1907 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1908 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1909 break;
1910 default:
1911 d->target_bias_level = SND_SOC_BIAS_ON;
1912 break;
1913 }
1914 }
1915
1916 }
1917
Mark Brown85a843c2011-09-21 21:29:47 +01001918 /* Force all contexts in the card to the same bias state if
1919 * they're not ground referenced.
1920 */
Mark Brown56fba412011-06-04 11:25:10 +01001921 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001922 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001923 if (d->target_bias_level > bias)
1924 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001925 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001926 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001927 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001928
Mark Brownde02d072011-09-20 21:43:24 +01001929 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001930
Xiang Xiao17282ba2014-03-02 00:04:03 +08001931 /* Run card bias changes at first */
1932 dapm_pre_sequence_async(&card->dapm, 0);
1933 /* Run other bias changes in parallel */
1934 list_for_each_entry(d, &card->dapm_list, list) {
1935 if (d != &card->dapm)
1936 async_schedule_domain(dapm_pre_sequence_async, d,
1937 &async_domain);
1938 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001939 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001940
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001941 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001942 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001943 }
1944
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001945 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001946 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001947 }
1948
Mark Brown6d3ddc82009-05-16 17:47:29 +01001949 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001950 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001951
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001952 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001953
Mark Brown6d3ddc82009-05-16 17:47:29 +01001954 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001955 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001956
Mark Brown9d0624a2011-02-18 11:49:43 -08001957 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001958 list_for_each_entry(d, &card->dapm_list, list) {
1959 if (d != &card->dapm)
1960 async_schedule_domain(dapm_post_sequence_async, d,
1961 &async_domain);
1962 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001963 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001964 /* Run card bias changes at last */
1965 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001966
Liam Girdwood8078d872012-02-15 15:15:35 +00001967 /* do we need to notify any clients that DAPM event is complete */
1968 list_for_each_entry(d, &card->dapm_list, list) {
1969 if (d->stream_event)
1970 d->stream_event(d, event);
1971 }
1972
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001973 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001974 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001975 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001976
Mark Brown84e90932010-11-04 00:07:02 -04001977 trace_snd_soc_dapm_done(card);
1978
Mark Brown42aa3412009-03-01 19:21:10 +00001979 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001980}
1981
Mark Brown79fb9382009-08-21 16:38:13 +01001982#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001983static ssize_t dapm_widget_power_read_file(struct file *file,
1984 char __user *user_buf,
1985 size_t count, loff_t *ppos)
1986{
1987 struct snd_soc_dapm_widget *w = file->private_data;
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001988 struct snd_soc_card *card = w->dapm->card;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001989 enum snd_soc_dapm_direction dir, rdir;
Mark Brown79fb9382009-08-21 16:38:13 +01001990 char *buf;
1991 int in, out;
1992 ssize_t ret;
1993 struct snd_soc_dapm_path *p = NULL;
1994
1995 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1996 if (!buf)
1997 return -ENOMEM;
1998
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001999 mutex_lock(&card->dapm_mutex);
2000
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002001 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
2002 if (w->is_supply) {
2003 in = 0;
2004 out = 0;
2005 } else {
Piotr Stankiewicz67420642016-05-13 17:03:55 +01002006 in = is_connected_input_ep(w, NULL, NULL);
2007 out = is_connected_output_ep(w, NULL, NULL);
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002008 }
Mark Brown79fb9382009-08-21 16:38:13 +01002009
Mark Brownf13ebad2012-03-03 18:01:01 +00002010 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
2011 w->name, w->power ? "On" : "Off",
2012 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01002013
Mark Brownd033c362009-12-04 15:25:56 +00002014 if (w->reg >= 0)
2015 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002016 " - R%d(0x%x) mask 0x%x",
2017 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00002018
2019 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
2020
Mark Brown3eef08b2009-09-14 16:49:00 +01002021 if (w->sname)
2022 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
2023 w->sname,
2024 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01002025
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002026 snd_soc_dapm_for_each_direction(dir) {
2027 rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
2028 snd_soc_dapm_widget_for_each_path(w, dir, p) {
2029 if (p->connected && !p->connected(w, p->node[rdir]))
2030 continue;
Mark Brown215edda2009-09-08 18:59:05 +01002031
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002032 if (!p->connect)
2033 continue;
Mark Brown215edda2009-09-08 18:59:05 +01002034
Mark Brown79fb9382009-08-21 16:38:13 +01002035 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002036 " %s \"%s\" \"%s\"\n",
2037 (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
Mark Brown79fb9382009-08-21 16:38:13 +01002038 p->name ? p->name : "static",
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002039 p->node[rdir]->name);
2040 }
Mark Brown79fb9382009-08-21 16:38:13 +01002041 }
2042
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002043 mutex_unlock(&card->dapm_mutex);
2044
Mark Brown79fb9382009-08-21 16:38:13 +01002045 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
2046
2047 kfree(buf);
2048 return ret;
2049}
2050
2051static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002052 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01002053 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02002054 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01002055};
2056
Mark Brownef49e4f2011-04-04 20:48:13 +09002057static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
2058 size_t count, loff_t *ppos)
2059{
2060 struct snd_soc_dapm_context *dapm = file->private_data;
2061 char *level;
2062
2063 switch (dapm->bias_level) {
2064 case SND_SOC_BIAS_ON:
2065 level = "On\n";
2066 break;
2067 case SND_SOC_BIAS_PREPARE:
2068 level = "Prepare\n";
2069 break;
2070 case SND_SOC_BIAS_STANDBY:
2071 level = "Standby\n";
2072 break;
2073 case SND_SOC_BIAS_OFF:
2074 level = "Off\n";
2075 break;
2076 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002077 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002078 level = "Unknown\n";
2079 break;
2080 }
2081
2082 return simple_read_from_buffer(user_buf, count, ppos, level,
2083 strlen(level));
2084}
2085
2086static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002087 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002088 .read = dapm_bias_read_file,
2089 .llseek = default_llseek,
2090};
2091
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002092void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2093 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002094{
Mark Brown79fb9382009-08-21 16:38:13 +01002095 struct dentry *d;
2096
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002097 if (!parent)
2098 return;
2099
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002100 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2101
2102 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002103 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002104 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002105 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002106 }
Mark Brown79fb9382009-08-21 16:38:13 +01002107
Mark Brownef49e4f2011-04-04 20:48:13 +09002108 d = debugfs_create_file("bias_level", 0444,
2109 dapm->debugfs_dapm, dapm,
2110 &dapm_bias_fops);
2111 if (!d)
2112 dev_warn(dapm->dev,
2113 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002114}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002115
2116static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2117{
2118 struct snd_soc_dapm_context *dapm = w->dapm;
2119 struct dentry *d;
2120
2121 if (!dapm->debugfs_dapm || !w->name)
2122 return;
2123
2124 d = debugfs_create_file(w->name, 0444,
2125 dapm->debugfs_dapm, w,
2126 &dapm_widget_power_fops);
2127 if (!d)
2128 dev_warn(w->dapm->dev,
2129 "ASoC: Failed to create %s debugfs file\n",
2130 w->name);
2131}
2132
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002133static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2134{
2135 debugfs_remove_recursive(dapm->debugfs_dapm);
2136}
2137
Mark Brown79fb9382009-08-21 16:38:13 +01002138#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002139void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2140 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002141{
2142}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002143
2144static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2145{
2146}
2147
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002148static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2149{
2150}
2151
Mark Brown79fb9382009-08-21 16:38:13 +01002152#endif
2153
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002154/*
2155 * soc_dapm_connect_path() - Connects or disconnects a path
2156 * @path: The path to update
2157 * @connect: The new connect state of the path. True if the path is connected,
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002158 * false if it is disconnected.
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002159 * @reason: The reason why the path changed (for debugging only)
2160 */
2161static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2162 bool connect, const char *reason)
2163{
2164 if (path->connect == connect)
2165 return;
2166
2167 path->connect = connect;
2168 dapm_mark_dirty(path->source, reason);
2169 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002170 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002171}
2172
Richard Purdie2b97eab2006-10-06 18:32:18 +02002173/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002174static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002175 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002176{
2177 struct snd_soc_dapm_path *path;
2178 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002179 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002180
Mark Brownf9fa2b12014-03-06 16:49:11 +08002181 lockdep_assert_held(&card->dapm_mutex);
2182
Richard Purdie2b97eab2006-10-06 18:32:18 +02002183 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002184 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002185 found = 1;
2186 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002187 if (!(strcmp(path->name, e->texts[mux])))
2188 connect = true;
2189 else
2190 connect = false;
2191
2192 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002193 }
2194
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002195 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002196 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002197
Liam Girdwood618dae12012-04-25 12:12:51 +01002198 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002199}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002200
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002201int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002202 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2203 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002204{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002205 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002206 int ret;
2207
Liam Girdwood3cd04342012-03-09 12:02:08 +00002208 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002209 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002210 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002211 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002212 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002213 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002214 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002215 return ret;
2216}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002217EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002218
Milan plzik1b075e32008-01-10 14:39:46 +01002219/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002220static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002221 struct snd_kcontrol *kcontrol,
2222 int connect, int rconnect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002223{
2224 struct snd_soc_dapm_path *path;
2225 int found = 0;
2226
Mark Brownf9fa2b12014-03-06 16:49:11 +08002227 lockdep_assert_held(&card->dapm_mutex);
2228
Richard Purdie2b97eab2006-10-06 18:32:18 +02002229 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002230 dapm_kcontrol_for_each_path(path, kcontrol) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002231 /*
2232 * Ideally this function should support any number of
2233 * paths and channels. But since kcontrols only come
2234 * in mono and stereo variants, we are limited to 2
2235 * channels.
2236 *
2237 * The following code assumes for stereo controls the
2238 * first path (when 'found == 0') is the left channel,
2239 * and all remaining paths (when 'found == 1') are the
2240 * right channel.
2241 *
2242 * A stereo control is signified by a valid 'rconnect'
2243 * value, either 0 for unconnected, or >= 0 for connected.
2244 * This is chosen instead of using snd_soc_volsw_is_stereo,
2245 * so that the behavior of snd_soc_dapm_mixer_update_power
2246 * doesn't change even when the kcontrol passed in is
2247 * stereo.
2248 *
2249 * It passes 'connect' as the path connect status for
2250 * the left channel, and 'rconnect' for the right
2251 * channel.
2252 */
2253 if (found && rconnect >= 0)
2254 soc_dapm_connect_path(path, rconnect, "mixer update");
2255 else
2256 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002257 found = 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002258 }
2259
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002260 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002261 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002262
Liam Girdwood618dae12012-04-25 12:12:51 +01002263 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002264}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002265
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002266int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002267 struct snd_kcontrol *kcontrol, int connect,
2268 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002269{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002270 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002271 int ret;
2272
Liam Girdwood3cd04342012-03-09 12:02:08 +00002273 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002274 card->update = update;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08002275 ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002276 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002277 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002278 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002279 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002280 return ret;
2281}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002282EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002283
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002284static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt,
2285 char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002286{
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002287 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002288 struct snd_soc_dapm_widget *w;
2289 int count = 0;
2290 char *state = "not set";
2291
Mark Brown47325072016-03-18 12:04:23 +00002292 /* card won't be set for the dummy component, as a spot fix
2293 * we're checking for that case specifically here but in future
2294 * we will ensure that the dummy component looks like others.
2295 */
2296 if (!cmpnt->card)
2297 return 0;
2298
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002299 list_for_each_entry(w, &cmpnt->card->widgets, list) {
2300 if (w->dapm != dapm)
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002301 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002302
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002303 /* only display widgets that burn power */
Richard Purdie2b97eab2006-10-06 18:32:18 +02002304 switch (w->id) {
2305 case snd_soc_dapm_hp:
2306 case snd_soc_dapm_mic:
2307 case snd_soc_dapm_spk:
2308 case snd_soc_dapm_line:
2309 case snd_soc_dapm_micbias:
2310 case snd_soc_dapm_dac:
2311 case snd_soc_dapm_adc:
2312 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002313 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002314 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002315 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002316 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002317 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002318 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002319 if (w->name)
2320 count += sprintf(buf + count, "%s: %s\n",
2321 w->name, w->power ? "On":"Off");
2322 break;
2323 default:
2324 break;
2325 }
2326 }
2327
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002328 switch (snd_soc_dapm_get_bias_level(dapm)) {
Mark Brown0be98982008-05-19 12:31:28 +02002329 case SND_SOC_BIAS_ON:
2330 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002331 break;
Mark Brown0be98982008-05-19 12:31:28 +02002332 case SND_SOC_BIAS_PREPARE:
2333 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002334 break;
Mark Brown0be98982008-05-19 12:31:28 +02002335 case SND_SOC_BIAS_STANDBY:
2336 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002337 break;
Mark Brown0be98982008-05-19 12:31:28 +02002338 case SND_SOC_BIAS_OFF:
2339 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002340 break;
2341 }
2342 count += sprintf(buf + count, "PM State: %s\n", state);
2343
2344 return count;
2345}
2346
Benoit Cousson44ba2642014-07-08 23:19:36 +02002347/* show dapm widget status in sys fs */
2348static ssize_t dapm_widget_show(struct device *dev,
2349 struct device_attribute *attr, char *buf)
2350{
2351 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2352 int i, count = 0;
2353
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002354 mutex_lock(&rtd->card->dapm_mutex);
2355
Benoit Cousson44ba2642014-07-08 23:19:36 +02002356 for (i = 0; i < rtd->num_codecs; i++) {
Lars-Peter Clausenb3c25fb2015-07-06 15:38:10 +02002357 struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component;
2358
2359 count += dapm_widget_show_component(cmpnt, buf + count);
Benoit Cousson44ba2642014-07-08 23:19:36 +02002360 }
2361
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002362 mutex_unlock(&rtd->card->dapm_mutex);
2363
Benoit Cousson44ba2642014-07-08 23:19:36 +02002364 return count;
2365}
2366
Richard Purdie2b97eab2006-10-06 18:32:18 +02002367static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2368
Takashi Iwaid29697d2015-01-30 20:16:37 +01002369struct attribute *soc_dapm_dev_attrs[] = {
2370 &dev_attr_dapm_widget.attr,
2371 NULL
2372};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002373
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002374static void dapm_free_path(struct snd_soc_dapm_path *path)
2375{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002376 list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
2377 list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002378 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002379 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002380 kfree(path);
2381}
2382
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002383void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2384{
2385 struct snd_soc_dapm_path *p, *next_p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002386 enum snd_soc_dapm_direction dir;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002387
2388 list_del(&w->list);
2389 /*
2390 * remove source and sink paths associated to this widget.
2391 * While removing the path, remove reference to it from both
2392 * source and sink widgets so that path is removed only once.
2393 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002394 snd_soc_dapm_for_each_direction(dir) {
2395 snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
2396 dapm_free_path(p);
2397 }
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002398
2399 kfree(w->kcontrols);
Lars-Peter Clausen48068962015-07-21 18:11:08 +02002400 kfree_const(w->name);
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002401 kfree(w);
2402}
2403
Jyri Sarhafd589a12015-11-10 18:12:42 +02002404void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
2405{
2406 dapm->path_sink_cache.widget = NULL;
2407 dapm->path_source_cache.widget = NULL;
2408}
2409
Richard Purdie2b97eab2006-10-06 18:32:18 +02002410/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002411static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002412{
2413 struct snd_soc_dapm_widget *w, *next_w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002414
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002415 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2416 if (w->dapm != dapm)
2417 continue;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002418 snd_soc_dapm_free_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002419 }
Jyri Sarhafd589a12015-11-10 18:12:42 +02002420 snd_soc_dapm_reset_cache(dapm);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002421}
2422
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002423static struct snd_soc_dapm_widget *dapm_find_widget(
2424 struct snd_soc_dapm_context *dapm, const char *pin,
2425 bool search_other_contexts)
2426{
2427 struct snd_soc_dapm_widget *w;
2428 struct snd_soc_dapm_widget *fallback = NULL;
2429
2430 list_for_each_entry(w, &dapm->card->widgets, list) {
2431 if (!strcmp(w->name, pin)) {
2432 if (w->dapm == dapm)
2433 return w;
2434 else
2435 fallback = w;
2436 }
2437 }
2438
2439 if (search_other_contexts)
2440 return fallback;
2441
2442 return NULL;
2443}
2444
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002445static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002446 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002447{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002448 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002449
Mark Brownf9fa2b12014-03-06 16:49:11 +08002450 dapm_assert_locked(dapm);
2451
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002452 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002453 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002454 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002455 }
2456
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002457 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002458 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002459 dapm_widget_invalidate_input_paths(w);
2460 dapm_widget_invalidate_output_paths(w);
2461 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002462
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002463 w->connected = status;
2464 if (status == 0)
2465 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002466
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002467 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002468}
2469
Richard Purdie2b97eab2006-10-06 18:32:18 +02002470/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002471 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2472 * @dapm: DAPM context
2473 *
2474 * Walks all dapm audio paths and powers widgets according to their
2475 * stream or path usage.
2476 *
2477 * Requires external locking.
2478 *
2479 * Returns 0 for success.
2480 */
2481int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2482{
2483 /*
2484 * Suppress early reports (eg, jacks syncing their state) to avoid
2485 * silly DAPM runs during card startup.
2486 */
2487 if (!dapm->card || !dapm->card->instantiated)
2488 return 0;
2489
2490 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2491}
2492EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2493
2494/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002495 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002496 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002497 *
2498 * Walks all dapm audio paths and powers widgets according to their
2499 * stream or path usage.
2500 *
2501 * Returns 0 for success.
2502 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002503int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002504{
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002505 int ret;
2506
Liam Girdwood3cd04342012-03-09 12:02:08 +00002507 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002508 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002509 mutex_unlock(&dapm->card->dapm_mutex);
2510 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002511}
Liam Girdwooda5302182008-07-07 13:35:17 +01002512EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002513
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002514/*
2515 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2516 * @w: The widget for which to update the flags
2517 *
2518 * Some widgets have a dynamic category which depends on which neighbors they
2519 * are connected to. This function update the category for these widgets.
2520 *
2521 * This function must be called whenever a path is added or removed to a widget.
2522 */
2523static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2524{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002525 enum snd_soc_dapm_direction dir;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002526 struct snd_soc_dapm_path *p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002527 unsigned int ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002528
2529 switch (w->id) {
2530 case snd_soc_dapm_input:
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02002531 /* On a fully routed card an input is never a source */
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002532 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002533 return;
2534 ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002535 snd_soc_dapm_widget_for_each_source_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002536 if (p->source->id == snd_soc_dapm_micbias ||
2537 p->source->id == snd_soc_dapm_mic ||
2538 p->source->id == snd_soc_dapm_line ||
2539 p->source->id == snd_soc_dapm_output) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002540 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002541 break;
2542 }
2543 }
2544 break;
2545 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002546 /* On a fully routed card a output is never a sink */
2547 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002548 return;
2549 ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002550 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002551 if (p->sink->id == snd_soc_dapm_spk ||
2552 p->sink->id == snd_soc_dapm_hp ||
2553 p->sink->id == snd_soc_dapm_line ||
2554 p->sink->id == snd_soc_dapm_input) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002555 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002556 break;
2557 }
2558 }
2559 break;
2560 case snd_soc_dapm_line:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002561 ep = 0;
2562 snd_soc_dapm_for_each_direction(dir) {
2563 if (!list_empty(&w->edges[dir]))
2564 ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
2565 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002566 break;
2567 default:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002568 return;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002569 }
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002570
2571 w->is_ep = ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002572}
2573
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002574static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2575 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2576 const char *control)
2577{
2578 bool dynamic_source = false;
2579 bool dynamic_sink = false;
2580
2581 if (!control)
2582 return 0;
2583
2584 switch (source->id) {
2585 case snd_soc_dapm_demux:
2586 dynamic_source = true;
2587 break;
2588 default:
2589 break;
2590 }
2591
2592 switch (sink->id) {
2593 case snd_soc_dapm_mux:
2594 case snd_soc_dapm_switch:
2595 case snd_soc_dapm_mixer:
2596 case snd_soc_dapm_mixer_named_ctl:
2597 dynamic_sink = true;
2598 break;
2599 default:
2600 break;
2601 }
2602
2603 if (dynamic_source && dynamic_sink) {
2604 dev_err(dapm->dev,
2605 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2606 source->name, control, sink->name);
2607 return -EINVAL;
2608 } else if (!dynamic_source && !dynamic_sink) {
2609 dev_err(dapm->dev,
2610 "Control not supported for path %s -> [%s] -> %s\n",
2611 source->name, control, sink->name);
2612 return -EINVAL;
2613 }
2614
2615 return 0;
2616}
2617
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002618static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2619 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2620 const char *control,
2621 int (*connected)(struct snd_soc_dapm_widget *source,
2622 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002623{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002624 struct snd_soc_dapm_widget *widgets[2];
2625 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002626 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002627 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002628
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002629 if (wsink->is_supply && !wsource->is_supply) {
2630 dev_err(dapm->dev,
2631 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2632 wsource->name, wsink->name);
2633 return -EINVAL;
2634 }
2635
2636 if (connected && !wsource->is_supply) {
2637 dev_err(dapm->dev,
2638 "connected() callback only supported for supply widgets (%s -> %s)\n",
2639 wsource->name, wsink->name);
2640 return -EINVAL;
2641 }
2642
2643 if (wsource->is_supply && control) {
2644 dev_err(dapm->dev,
2645 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2646 wsource->name, control, wsink->name);
2647 return -EINVAL;
2648 }
2649
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002650 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2651 if (ret)
2652 return ret;
2653
Richard Purdie2b97eab2006-10-06 18:32:18 +02002654 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2655 if (!path)
2656 return -ENOMEM;
2657
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002658 path->node[SND_SOC_DAPM_DIR_IN] = wsource;
2659 path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
2660 widgets[SND_SOC_DAPM_DIR_IN] = wsource;
2661 widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
2662
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002663 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002664 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002665 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002666
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002667 if (wsource->is_supply || wsink->is_supply)
2668 path->is_supply = 1;
2669
Richard Purdie2b97eab2006-10-06 18:32:18 +02002670 /* connect static paths */
2671 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002672 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002673 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002674 switch (wsource->id) {
2675 case snd_soc_dapm_demux:
2676 ret = dapm_connect_mux(dapm, path, control, wsource);
2677 if (ret)
2678 goto err;
2679 break;
2680 default:
2681 break;
2682 }
2683
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002684 switch (wsink->id) {
2685 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002686 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002687 if (ret != 0)
2688 goto err;
2689 break;
2690 case snd_soc_dapm_switch:
2691 case snd_soc_dapm_mixer:
2692 case snd_soc_dapm_mixer_named_ctl:
2693 ret = dapm_connect_mixer(dapm, path, control);
2694 if (ret != 0)
2695 goto err;
2696 break;
2697 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002698 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002699 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002700 }
2701
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002702 list_add(&path->list, &dapm->card->paths);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002703 snd_soc_dapm_for_each_direction(dir)
2704 list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002705
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002706 snd_soc_dapm_for_each_direction(dir) {
2707 dapm_update_widget_flags(widgets[dir]);
2708 dapm_mark_dirty(widgets[dir], "Route added");
2709 }
Mark Brownfabd0382012-07-05 17:20:06 +01002710
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002711 if (dapm->card->instantiated && path->connect)
2712 dapm_path_invalidate(path);
2713
Richard Purdie2b97eab2006-10-06 18:32:18 +02002714 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002715err:
2716 kfree(path);
2717 return ret;
2718}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002719
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002720static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002721 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002722{
2723 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2724 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2725 const char *sink;
2726 const char *source;
2727 char prefixed_sink[80];
2728 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002729 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002730 int ret;
2731
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002732 prefix = soc_dapm_prefix(dapm);
2733 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002734 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002735 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002736 sink = prefixed_sink;
2737 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002738 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002739 source = prefixed_source;
2740 } else {
2741 sink = route->sink;
2742 source = route->source;
2743 }
2744
Charles Keepax45a110a2015-05-11 13:50:30 +01002745 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2746 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2747
2748 if (wsink && wsource)
2749 goto skip_search;
2750
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002751 /*
2752 * find src and dest widgets over all widgets but favor a widget from
2753 * current DAPM context
2754 */
2755 list_for_each_entry(w, &dapm->card->widgets, list) {
2756 if (!wsink && !(strcmp(w->name, sink))) {
2757 wtsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002758 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002759 wsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002760 if (wsource)
2761 break;
2762 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002763 continue;
2764 }
2765 if (!wsource && !(strcmp(w->name, source))) {
2766 wtsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002767 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002768 wsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002769 if (wsink)
2770 break;
2771 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002772 }
2773 }
2774 /* use widget from another DAPM context if not found from this */
2775 if (!wsink)
2776 wsink = wtsink;
2777 if (!wsource)
2778 wsource = wtsource;
2779
2780 if (wsource == NULL) {
2781 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2782 route->source);
2783 return -ENODEV;
2784 }
2785 if (wsink == NULL) {
2786 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2787 route->sink);
2788 return -ENODEV;
2789 }
2790
Charles Keepax45a110a2015-05-11 13:50:30 +01002791skip_search:
2792 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2793 dapm_wcache_update(&dapm->path_source_cache, wsource);
2794
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002795 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2796 route->connected);
2797 if (ret)
2798 goto err;
2799
2800 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002801err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002802 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002803 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002804 return ret;
2805}
Mark Brown105f1c22008-05-13 14:52:19 +02002806
Mark Brownefcc3c62012-07-05 17:24:19 +01002807static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2808 const struct snd_soc_dapm_route *route)
2809{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002810 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002811 struct snd_soc_dapm_path *path, *p;
2812 const char *sink;
2813 const char *source;
2814 char prefixed_sink[80];
2815 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002816 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002817
2818 if (route->control) {
2819 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002820 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002821 return -EINVAL;
2822 }
2823
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002824 prefix = soc_dapm_prefix(dapm);
2825 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002826 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002827 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002828 sink = prefixed_sink;
2829 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002830 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002831 source = prefixed_source;
2832 } else {
2833 sink = route->sink;
2834 source = route->source;
2835 }
2836
2837 path = NULL;
2838 list_for_each_entry(p, &dapm->card->paths, list) {
2839 if (strcmp(p->source->name, source) != 0)
2840 continue;
2841 if (strcmp(p->sink->name, sink) != 0)
2842 continue;
2843 path = p;
2844 break;
2845 }
2846
2847 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002848 wsource = path->source;
2849 wsink = path->sink;
2850
2851 dapm_mark_dirty(wsource, "Route removed");
2852 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002853 if (path->connect)
2854 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002855
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002856 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002857
2858 /* Update any path related flags */
2859 dapm_update_widget_flags(wsource);
2860 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002861 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002862 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002863 source, sink);
2864 }
2865
2866 return 0;
2867}
2868
Mark Brown105f1c22008-05-13 14:52:19 +02002869/**
Mark Brown105f1c22008-05-13 14:52:19 +02002870 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002871 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002872 * @route: audio routes
2873 * @num: number of routes
2874 *
2875 * Connects 2 dapm widgets together via a named audio path. The sink is
2876 * the widget receiving the audio signal, whilst the source is the sender
2877 * of the audio signal.
2878 *
2879 * Returns 0 for success else error. On error all resources can be freed
2880 * with a call to snd_soc_card_free().
2881 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002882int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002883 const struct snd_soc_dapm_route *route, int num)
2884{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002885 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002886
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002887 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002888 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002889 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002890 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002891 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2892 route->source,
2893 route->control ? route->control : "direct",
2894 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002895 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002896 }
2897 route++;
2898 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002899 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002900
Dan Carpenter60884c22012-04-13 22:25:43 +03002901 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002902}
2903EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2904
Mark Brownefcc3c62012-07-05 17:24:19 +01002905/**
2906 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2907 * @dapm: DAPM context
2908 * @route: audio routes
2909 * @num: number of routes
2910 *
2911 * Removes routes from the DAPM context.
2912 */
2913int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2914 const struct snd_soc_dapm_route *route, int num)
2915{
Rajan Vajae066ea22016-02-11 11:23:35 +05302916 int i;
Mark Brownefcc3c62012-07-05 17:24:19 +01002917
2918 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2919 for (i = 0; i < num; i++) {
2920 snd_soc_dapm_del_route(dapm, route);
2921 route++;
2922 }
2923 mutex_unlock(&dapm->card->dapm_mutex);
2924
Rajan Vajae066ea22016-02-11 11:23:35 +05302925 return 0;
Mark Brownefcc3c62012-07-05 17:24:19 +01002926}
2927EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2928
Mark Brownbf3a9e12011-06-13 16:42:29 +01002929static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2930 const struct snd_soc_dapm_route *route)
2931{
2932 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2933 route->source,
2934 true);
2935 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2936 route->sink,
2937 true);
2938 struct snd_soc_dapm_path *path;
2939 int count = 0;
2940
2941 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002942 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002943 route->source);
2944 return -ENODEV;
2945 }
2946
2947 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002948 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002949 route->sink);
2950 return -ENODEV;
2951 }
2952
2953 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002954 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002955 route->source, route->sink);
2956
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002957 snd_soc_dapm_widget_for_each_sink_path(source, path) {
Mark Brownbf3a9e12011-06-13 16:42:29 +01002958 if (path->sink == sink) {
2959 path->weak = 1;
2960 count++;
2961 }
2962 }
2963
2964 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002965 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002966 route->source, route->sink);
2967 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002968 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002969 count, route->source, route->sink);
2970
2971 return 0;
2972}
2973
2974/**
2975 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2976 * @dapm: DAPM context
2977 * @route: audio routes
2978 * @num: number of routes
2979 *
2980 * Mark existing routes matching those specified in the passed array
2981 * as being weak, meaning that they are ignored for the purpose of
2982 * power decisions. The main intended use case is for sidetone paths
2983 * which couple audio between other independent paths if they are both
2984 * active in order to make the combination work better at the user
2985 * level but which aren't intended to be "used".
2986 *
2987 * Note that CODEC drivers should not use this as sidetone type paths
2988 * can frequently also be used as bypass paths.
2989 */
2990int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2991 const struct snd_soc_dapm_route *route, int num)
2992{
2993 int i, err;
2994 int ret = 0;
2995
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00002996 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002997 for (i = 0; i < num; i++) {
2998 err = snd_soc_dapm_weak_route(dapm, route);
2999 if (err)
3000 ret = err;
3001 route++;
3002 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003003 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01003004
3005 return ret;
3006}
3007EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
3008
Mark Brown105f1c22008-05-13 14:52:19 +02003009/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02003010 * snd_soc_dapm_new_widgets - add new dapm widgets
Jonathan Corbet628536e2015-08-25 01:14:48 -06003011 * @card: card to be checked for new dapm widgets
Richard Purdie2b97eab2006-10-06 18:32:18 +02003012 *
3013 * Checks the codec for any new dapm widgets and creates them if found.
3014 *
3015 * Returns 0 for success.
3016 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02003017int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003018{
3019 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00003020 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003021
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003022 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003023
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003024 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003025 {
3026 if (w->new)
3027 continue;
3028
Stephen Warrenfad59882011-04-28 17:37:59 -06003029 if (w->num_kcontrols) {
3030 w->kcontrols = kzalloc(w->num_kcontrols *
3031 sizeof(struct snd_kcontrol *),
3032 GFP_KERNEL);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003033 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003034 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06003035 return -ENOMEM;
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003036 }
Stephen Warrenfad59882011-04-28 17:37:59 -06003037 }
3038
Richard Purdie2b97eab2006-10-06 18:32:18 +02003039 switch(w->id) {
3040 case snd_soc_dapm_switch:
3041 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00003042 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003043 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003044 break;
3045 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003046 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003047 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003048 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003049 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06003050 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02003051 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003052 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003053 case snd_soc_dapm_dai_link:
3054 dapm_new_dai_link(w);
3055 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01003056 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003057 break;
3058 }
Mark Brownb66a70d2011-02-09 18:04:11 +00003059
3060 /* Read the initial power state from the device */
3061 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003062 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08003063 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003064 val &= w->mask;
3065 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00003066 w->power = 1;
3067 }
3068
Richard Purdie2b97eab2006-10-06 18:32:18 +02003069 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003070
Mark Brown7508b122011-10-05 12:09:12 +01003071 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02003072 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003073 }
3074
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003075 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
3076 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003077 return 0;
3078}
3079EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
3080
3081/**
3082 * snd_soc_dapm_get_volsw - dapm mixer get callback
3083 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003084 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003085 *
3086 * Callback to get the value of a dapm mixer control.
3087 *
3088 * Returns 0 for success.
3089 */
3090int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
3091 struct snd_ctl_elem_value *ucontrol)
3092{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003093 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3094 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003095 struct soc_mixer_control *mc =
3096 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003097 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003098 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003099 int max = mc->max;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003100 unsigned int width = fls(max);
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003101 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003102 unsigned int invert = mc->invert;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003103 unsigned int reg_val, val, rval = 0;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003104 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003105
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003106 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003107 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003108 ret = soc_dapm_read(dapm, reg, &reg_val);
3109 val = (reg_val >> shift) & mask;
3110
3111 if (ret == 0 && reg != mc->rreg)
3112 ret = soc_dapm_read(dapm, mc->rreg, &reg_val);
3113
3114 if (snd_soc_volsw_is_stereo(mc))
3115 rval = (reg_val >> mc->rshift) & mask;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003116 } else {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003117 reg_val = dapm_kcontrol_get_value(kcontrol);
3118 val = reg_val & mask;
3119
3120 if (snd_soc_volsw_is_stereo(mc))
3121 rval = (reg_val >> width) & mask;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003122 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003123 mutex_unlock(&card->dapm_mutex);
3124
Chen-Yu Tsai01ad5e72016-08-27 19:27:58 +08003125 if (ret)
3126 return ret;
3127
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003128 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003129 ucontrol->value.integer.value[0] = max - val;
3130 else
3131 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003132
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003133 if (snd_soc_volsw_is_stereo(mc)) {
3134 if (invert)
3135 ucontrol->value.integer.value[1] = max - rval;
3136 else
3137 ucontrol->value.integer.value[1] = rval;
3138 }
3139
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003140 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003141}
3142EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3143
3144/**
3145 * snd_soc_dapm_put_volsw - dapm mixer set callback
3146 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003147 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003148 *
3149 * Callback to set the value of a dapm mixer control.
3150 *
3151 * Returns 0 for success.
3152 */
3153int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3154 struct snd_ctl_elem_value *ucontrol)
3155{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003156 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3157 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003158 struct soc_mixer_control *mc =
3159 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003160 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003161 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003162 int max = mc->max;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003163 unsigned int width = fls(max);
3164 unsigned int mask = (1 << width) - 1;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003165 unsigned int invert = mc->invert;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003166 unsigned int val, rval = 0;
3167 int connect, rconnect = -1, change, reg_change = 0;
Chen-Yu Tsaie411b0b2016-11-02 15:35:58 +08003168 struct snd_soc_dapm_update update = { NULL };
Nenghua Cao52765972013-12-13 20:13:49 +08003169 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003170
3171 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003172 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003173
3174 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003175 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003176
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003177 if (snd_soc_volsw_is_stereo(mc)) {
3178 rval = (ucontrol->value.integer.value[1] & mask);
3179 rconnect = !!rval;
3180 if (invert)
3181 rval = max - rval;
3182 }
3183
Liam Girdwood3cd04342012-03-09 12:02:08 +00003184 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003185
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003186 /* This assumes field width < (bits in unsigned int / 2) */
3187 if (width > sizeof(unsigned int) * 8 / 2)
3188 dev_warn(dapm->dev,
3189 "ASoC: control %s field width limit exceeded\n",
3190 kcontrol->id.name);
3191 change = dapm_kcontrol_set_value(kcontrol, val | (rval << width));
Mark Brown283375c2009-12-07 18:09:03 +00003192
Jarkko Nikula18626c72014-06-09 14:20:29 +03003193 if (reg != SND_SOC_NOPM) {
Jarkko Nikula18626c72014-06-09 14:20:29 +03003194 val = val << shift;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003195 rval = rval << mc->rshift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003196
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003197 reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val);
3198
3199 if (snd_soc_volsw_is_stereo(mc))
3200 reg_change |= soc_dapm_test_bits(dapm, mc->rreg,
3201 mask << mc->rshift,
3202 rval);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003203 }
3204
3205 if (change || reg_change) {
3206 if (reg_change) {
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003207 if (snd_soc_volsw_is_stereo(mc)) {
3208 update.has_second_set = true;
3209 update.reg2 = mc->rreg;
3210 update.mask2 = mask << mc->rshift;
3211 update.val2 = rval;
3212 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003213 update.kcontrol = kcontrol;
3214 update.reg = reg;
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003215 update.mask = mask << shift;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003216 update.val = val;
3217 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003218 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003219 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003220
Chen-Yu Tsaie7aa4502016-11-02 15:35:59 +08003221 ret = soc_dapm_mixer_update_power(card, kcontrol, connect,
3222 rconnect);
Mark Brown97404f22010-12-14 16:13:57 +00003223
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003224 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003225 }
3226
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003227 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003228
3229 if (ret > 0)
3230 soc_dpcm_runtime_update(card);
3231
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003232 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003233}
3234EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3235
3236/**
3237 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3238 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003239 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003240 *
3241 * Callback to get the value of a dapm enumerated double mixer control.
3242 *
3243 * Returns 0 for success.
3244 */
3245int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3246 struct snd_ctl_elem_value *ucontrol)
3247{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003248 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003249 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003250 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003251 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003252
Charles Keepax561ed682015-05-01 12:37:26 +01003253 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3254 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003255 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003256 if (ret) {
3257 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003258 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003259 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003260 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003261 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003262 }
Charles Keepax561ed682015-05-01 12:37:26 +01003263 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003264
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003265 val = (reg_val >> e->shift_l) & e->mask;
3266 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3267 if (e->shift_l != e->shift_r) {
3268 val = (reg_val >> e->shift_r) & e->mask;
3269 val = snd_soc_enum_val_to_item(e, val);
3270 ucontrol->value.enumerated.item[1] = val;
3271 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003272
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003273 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003274}
3275EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3276
3277/**
3278 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3279 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003280 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003281 *
3282 * Callback to set the value of a dapm enumerated double mixer control.
3283 *
3284 * Returns 0 for success.
3285 */
3286int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3287 struct snd_ctl_elem_value *ucontrol)
3288{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003289 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3290 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003291 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003292 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003293 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003294 unsigned int mask;
Chen-Yu Tsaie411b0b2016-11-02 15:35:58 +08003295 struct snd_soc_dapm_update update = { NULL };
Nenghua Cao52765972013-12-13 20:13:49 +08003296 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003297
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003298 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003299 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003300
3301 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003302 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003303 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003304 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003305 return -EINVAL;
Chen-Yu Tsai071133a2016-08-27 19:27:59 +08003306 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003307 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003308 }
3309
Liam Girdwood3cd04342012-03-09 12:02:08 +00003310 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003311
Charles Keepax561ed682015-05-01 12:37:26 +01003312 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003313
Charles Keepax561ed682015-05-01 12:37:26 +01003314 if (e->reg != SND_SOC_NOPM)
3315 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3316
3317 if (change || reg_change) {
3318 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003319 update.kcontrol = kcontrol;
3320 update.reg = e->reg;
3321 update.mask = mask;
3322 update.val = val;
3323 card->update = &update;
3324 }
Charles Keepax561ed682015-05-01 12:37:26 +01003325 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003326
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003327 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003328
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003329 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003330 }
3331
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003332 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003333
3334 if (ret > 0)
3335 soc_dpcm_runtime_update(card);
3336
Mark Brown97404f22010-12-14 16:13:57 +00003337 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003338}
3339EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3340
3341/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003342 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3343 *
3344 * @kcontrol: mixer control
3345 * @uinfo: control element information
3346 *
3347 * Callback to provide information about a pin switch control.
3348 */
3349int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3350 struct snd_ctl_elem_info *uinfo)
3351{
3352 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3353 uinfo->count = 1;
3354 uinfo->value.integer.min = 0;
3355 uinfo->value.integer.max = 1;
3356
3357 return 0;
3358}
3359EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3360
3361/**
3362 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3363 *
3364 * @kcontrol: mixer control
3365 * @ucontrol: Value
3366 */
3367int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3368 struct snd_ctl_elem_value *ucontrol)
3369{
Mark Brown48a8c392012-02-14 17:11:15 -08003370 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003371 const char *pin = (const char *)kcontrol->private_value;
3372
Liam Girdwood3cd04342012-03-09 12:02:08 +00003373 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003374
3375 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003376 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003377
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003378 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003379
3380 return 0;
3381}
3382EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3383
3384/**
3385 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3386 *
3387 * @kcontrol: mixer control
3388 * @ucontrol: Value
3389 */
3390int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3391 struct snd_ctl_elem_value *ucontrol)
3392{
Mark Brown48a8c392012-02-14 17:11:15 -08003393 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003394 const char *pin = (const char *)kcontrol->private_value;
3395
Mark Brown8b37dbd2009-02-28 21:14:20 +00003396 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003397 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003398 else
Mark Brown48a8c392012-02-14 17:11:15 -08003399 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003400
Mark Brown48a8c392012-02-14 17:11:15 -08003401 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003402 return 0;
3403}
3404EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3405
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +01003406struct snd_soc_dapm_widget *
Mark Brown5ba06fc2012-02-16 11:07:13 -08003407snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003408 const struct snd_soc_dapm_widget *widget)
3409{
3410 struct snd_soc_dapm_widget *w;
3411
3412 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3413 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Linus Walleij37e1df82017-01-13 10:23:52 +01003414 /* Do not nag about probe deferrals */
3415 if (IS_ERR(w)) {
3416 int ret = PTR_ERR(w);
3417
3418 if (ret != -EPROBE_DEFER)
3419 dev_err(dapm->dev,
3420 "ASoC: Failed to create DAPM control %s (%d)\n",
3421 widget->name, ret);
3422 goto out_unlock;
3423 }
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003424 if (!w)
3425 dev_err(dapm->dev,
3426 "ASoC: Failed to create DAPM control %s\n",
3427 widget->name);
3428
Linus Walleij37e1df82017-01-13 10:23:52 +01003429out_unlock:
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003430 mutex_unlock(&dapm->card->dapm_mutex);
3431 return w;
3432}
Subhransu S. Prustya5d56392016-06-27 09:18:03 +05303433EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003434
3435struct snd_soc_dapm_widget *
3436snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003437 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003438{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003439 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003440 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003441 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003442 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003443
3444 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003445 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003446
Mark Brown62ea8742012-01-21 21:14:48 +00003447 switch (w->id) {
3448 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003449 w->regulator = devm_regulator_get(dapm->dev, w->name);
3450 if (IS_ERR(w->regulator)) {
3451 ret = PTR_ERR(w->regulator);
Linus Walleij37e1df82017-01-13 10:23:52 +01003452 if (ret == -EPROBE_DEFER)
3453 return ERR_PTR(ret);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003454 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003455 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003456 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003457 }
Mark Brown8784c772013-01-10 19:33:47 +00003458
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003459 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003460 ret = regulator_allow_bypass(w->regulator, true);
3461 if (ret != 0)
3462 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003463 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003464 w->name, ret);
3465 }
Mark Brown62ea8742012-01-21 21:14:48 +00003466 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003467 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003468#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003469 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003470 if (IS_ERR(w->clk)) {
3471 ret = PTR_ERR(w->clk);
Linus Walleij37e1df82017-01-13 10:23:52 +01003472 if (ret == -EPROBE_DEFER)
3473 return ERR_PTR(ret);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003474 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003475 w->name, ret);
3476 return NULL;
3477 }
Mark Brownec029952012-06-04 08:16:20 +01003478#else
3479 return NULL;
3480#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003481 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003482 default:
3483 break;
3484 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003485
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003486 prefix = soc_dapm_prefix(dapm);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003487 if (prefix)
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003488 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003489 else
Lars-Peter Clausen48068962015-07-21 18:11:08 +02003490 w->name = kstrdup_const(widget->name, GFP_KERNEL);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003491 if (w->name == NULL) {
3492 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003493 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003494 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003495
Mark Brown7ca3a182011-10-08 14:04:50 +01003496 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003497 case snd_soc_dapm_mic:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003498 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003499 w->power_check = dapm_generic_check_power;
3500 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003501 case snd_soc_dapm_input:
3502 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003503 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003504 w->power_check = dapm_generic_check_power;
3505 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003506 case snd_soc_dapm_spk:
3507 case snd_soc_dapm_hp:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003508 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003509 w->power_check = dapm_generic_check_power;
3510 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003511 case snd_soc_dapm_output:
3512 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003513 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003514 w->power_check = dapm_generic_check_power;
3515 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003516 case snd_soc_dapm_vmid:
3517 case snd_soc_dapm_siggen:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003518 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003519 w->power_check = dapm_always_on_check_power;
3520 break;
Vinod Koul56b44372015-11-23 21:22:30 +05303521 case snd_soc_dapm_sink:
3522 w->is_ep = SND_SOC_DAPM_EP_SINK;
3523 w->power_check = dapm_always_on_check_power;
3524 break;
3525
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003526 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003527 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003528 case snd_soc_dapm_switch:
3529 case snd_soc_dapm_mixer:
3530 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003531 case snd_soc_dapm_adc:
3532 case snd_soc_dapm_aif_out:
3533 case snd_soc_dapm_dac:
3534 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003535 case snd_soc_dapm_pga:
3536 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003537 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003538 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003539 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003540 case snd_soc_dapm_dai_out:
3541 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003542 w->power_check = dapm_generic_check_power;
3543 break;
3544 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003545 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003546 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003547 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003548 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003549 w->power_check = dapm_supply_check_power;
3550 break;
3551 default:
3552 w->power_check = dapm_always_on_check_power;
3553 break;
3554 }
3555
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003556 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003557 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003558 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003559 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003560
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003561 snd_soc_dapm_for_each_direction(dir) {
3562 INIT_LIST_HEAD(&w->edges[dir]);
3563 w->endpoints[dir] = -1;
3564 }
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003565
Peter Meerwald-Stadlerc8046002016-08-16 16:56:17 +02003566 /* machine layer sets up unconnected pins and insertions */
Richard Purdie2b97eab2006-10-06 18:32:18 +02003567 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003568 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003569}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003570
3571/**
Mark Brown4ba13272008-05-13 14:51:19 +02003572 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003573 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003574 * @widget: widget array
3575 * @num: number of widgets
3576 *
3577 * Creates new DAPM controls based upon the templates.
3578 *
3579 * Returns 0 for success else error.
3580 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003581int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003582 const struct snd_soc_dapm_widget *widget,
3583 int num)
3584{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003585 struct snd_soc_dapm_widget *w;
3586 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003587 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003588
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003589 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003590 for (i = 0; i < num; i++) {
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003591 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Linus Walleij37e1df82017-01-13 10:23:52 +01003592 if (IS_ERR(w)) {
3593 ret = PTR_ERR(w);
3594 /* Do not nag about probe deferrals */
3595 if (ret == -EPROBE_DEFER)
3596 break;
3597 dev_err(dapm->dev,
3598 "ASoC: Failed to create DAPM control %s (%d)\n",
3599 widget->name, ret);
3600 break;
3601 }
Mark Brown5ba06fc2012-02-16 11:07:13 -08003602 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003603 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003604 "ASoC: Failed to create DAPM control %s\n",
3605 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003606 ret = -ENOMEM;
3607 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003608 }
Mark Brown4ba13272008-05-13 14:51:19 +02003609 widget++;
3610 }
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00003611 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003612 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003613}
3614EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3615
Mark Brownc74184e2012-04-04 22:12:09 +01003616static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3617 struct snd_kcontrol *kcontrol, int event)
3618{
3619 struct snd_soc_dapm_path *source_p, *sink_p;
3620 struct snd_soc_dai *source, *sink;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003621 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003622 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003623 struct snd_pcm_hw_params *params = NULL;
Nicolin Chen8053f212016-07-26 14:55:51 -07003624 struct snd_pcm_runtime *runtime = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003625 u64 fmt;
3626 int ret;
3627
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003628 if (WARN_ON(!config) ||
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003629 WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3630 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003631 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003632
3633 /* We only support a single source and sink, pick the first */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003634 source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
3635 struct snd_soc_dapm_path,
3636 list_node[SND_SOC_DAPM_DIR_OUT]);
3637 sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
3638 struct snd_soc_dapm_path,
3639 list_node[SND_SOC_DAPM_DIR_IN]);
Mark Brownc74184e2012-04-04 22:12:09 +01003640
3641 source = source_p->source->priv;
3642 sink = sink_p->sink->priv;
3643
3644 /* Be a little careful as we don't want to overflow the mask array */
3645 if (config->formats) {
3646 fmt = ffs(config->formats) - 1;
3647 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003648 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003649 config->formats);
3650 fmt = 0;
3651 }
3652
3653 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003654 params = kzalloc(sizeof(*params), GFP_KERNEL);
3655 if (!params) {
3656 ret = -ENOMEM;
3657 goto out;
3658 }
3659 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003660
Mark Brown9747cec2012-04-26 19:12:21 +01003661 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003662 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003663 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003664 config->rate_max;
3665
Mark Brown9747cec2012-04-26 19:12:21 +01003666 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003667 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003668 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003669 = config->channels_max;
3670
3671 memset(&substream, 0, sizeof(substream));
3672
Nicolin Chen8053f212016-07-26 14:55:51 -07003673 /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */
3674 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
3675 if (!runtime) {
3676 ret = -ENOMEM;
3677 goto out;
3678 }
3679 substream.runtime = runtime;
3680
Mark Brownc74184e2012-04-04 22:12:09 +01003681 switch (event) {
3682 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003683 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303684 if (source->driver->ops && source->driver->ops->startup) {
3685 ret = source->driver->ops->startup(&substream, source);
3686 if (ret < 0) {
3687 dev_err(source->dev,
3688 "ASoC: startup() failed: %d\n", ret);
3689 goto out;
3690 }
3691 source->active++;
3692 }
Benoit Cousson93e69582014-07-08 23:19:38 +02003693 ret = soc_dai_hw_params(&substream, params, source);
3694 if (ret < 0)
3695 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003696
Benoit Cousson93e69582014-07-08 23:19:38 +02003697 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303698 if (sink->driver->ops && sink->driver->ops->startup) {
3699 ret = sink->driver->ops->startup(&substream, sink);
3700 if (ret < 0) {
3701 dev_err(sink->dev,
3702 "ASoC: startup() failed: %d\n", ret);
3703 goto out;
3704 }
3705 sink->active++;
3706 }
Benoit Cousson93e69582014-07-08 23:19:38 +02003707 ret = soc_dai_hw_params(&substream, params, sink);
3708 if (ret < 0)
3709 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003710 break;
3711
3712 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003713 ret = snd_soc_dai_digital_mute(sink, 0,
3714 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003715 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003716 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003717 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003718 break;
3719
3720 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003721 ret = snd_soc_dai_digital_mute(sink, 1,
3722 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003723 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003724 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003725 ret = 0;
Jeeja KP9b8ef9f2015-10-20 22:30:07 +05303726
3727 source->active--;
3728 if (source->driver->ops && source->driver->ops->shutdown) {
3729 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3730 source->driver->ops->shutdown(&substream, source);
3731 }
3732
3733 sink->active--;
3734 if (sink->driver->ops && sink->driver->ops->shutdown) {
3735 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3736 sink->driver->ops->shutdown(&substream, sink);
3737 }
Mark Brownc74184e2012-04-04 22:12:09 +01003738 break;
3739
3740 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003741 WARN(1, "Unknown event %d\n", event);
Sudip Mukherjee75881df2015-09-10 18:01:44 +05303742 ret = -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003743 }
3744
Mark Brown9747cec2012-04-26 19:12:21 +01003745out:
Nicolin Chen8053f212016-07-26 14:55:51 -07003746 kfree(runtime);
Mark Brown9747cec2012-04-26 19:12:21 +01003747 kfree(params);
3748 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003749}
3750
Nikesh Oswalc6615082015-02-02 17:06:44 +00003751static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3752 struct snd_ctl_elem_value *ucontrol)
3753{
3754 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3755
Takashi Iwai741338f2016-02-29 17:20:48 +01003756 ucontrol->value.enumerated.item[0] = w->params_select;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003757
3758 return 0;
3759}
3760
3761static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3762 struct snd_ctl_elem_value *ucontrol)
3763{
3764 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3765
3766 /* Can't change the config when widget is already powered */
3767 if (w->power)
3768 return -EBUSY;
3769
Takashi Iwai741338f2016-02-29 17:20:48 +01003770 if (ucontrol->value.enumerated.item[0] == w->params_select)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003771 return 0;
3772
Takashi Iwai741338f2016-02-29 17:20:48 +01003773 if (ucontrol->value.enumerated.item[0] >= w->num_params)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003774 return -EINVAL;
3775
Takashi Iwai741338f2016-02-29 17:20:48 +01003776 w->params_select = ucontrol->value.enumerated.item[0];
Nikesh Oswalc6615082015-02-02 17:06:44 +00003777
3778 return 0;
3779}
3780
Mark Brownc74184e2012-04-04 22:12:09 +01003781int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3782 const struct snd_soc_pcm_stream *params,
Nikesh Oswalc6615082015-02-02 17:06:44 +00003783 unsigned int num_params,
Mark Brownc74184e2012-04-04 22:12:09 +01003784 struct snd_soc_dapm_widget *source,
3785 struct snd_soc_dapm_widget *sink)
3786{
Mark Brownc74184e2012-04-04 22:12:09 +01003787 struct snd_soc_dapm_widget template;
3788 struct snd_soc_dapm_widget *w;
Mark Brownc74184e2012-04-04 22:12:09 +01003789 char *link_name;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003790 int ret, count;
3791 unsigned long private_value;
3792 const char **w_param_text;
3793 struct soc_enum w_param_enum[] = {
3794 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3795 };
3796 struct snd_kcontrol_new kcontrol_dai_link[] = {
3797 SOC_ENUM_EXT(NULL, w_param_enum[0],
3798 snd_soc_dapm_dai_link_get,
3799 snd_soc_dapm_dai_link_put),
3800 };
3801 const struct snd_soc_pcm_stream *config = params;
Mark Brownc74184e2012-04-04 22:12:09 +01003802
Nikesh Oswalc6615082015-02-02 17:06:44 +00003803 w_param_text = devm_kcalloc(card->dev, num_params,
3804 sizeof(char *), GFP_KERNEL);
3805 if (!w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003806 return -ENOMEM;
Mark Brownc74184e2012-04-04 22:12:09 +01003807
Charles Keepax46172b62015-03-25 11:22:35 +00003808 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3809 source->name, sink->name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003810 if (!link_name) {
3811 ret = -ENOMEM;
3812 goto outfree_w_param;
3813 }
Mark Brownc74184e2012-04-04 22:12:09 +01003814
Nikesh Oswalc6615082015-02-02 17:06:44 +00003815 for (count = 0 ; count < num_params; count++) {
3816 if (!config->stream_name) {
3817 dev_warn(card->dapm.dev,
3818 "ASoC: anonymous config %d for dai link %s\n",
3819 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003820 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003821 devm_kasprintf(card->dev, GFP_KERNEL,
3822 "Anonymous Configuration %d",
3823 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003824 if (!w_param_text[count]) {
3825 ret = -ENOMEM;
3826 goto outfree_link_name;
3827 }
Nikesh Oswalc6615082015-02-02 17:06:44 +00003828 } else {
3829 w_param_text[count] = devm_kmemdup(card->dev,
3830 config->stream_name,
3831 strlen(config->stream_name) + 1,
3832 GFP_KERNEL);
3833 if (!w_param_text[count]) {
3834 ret = -ENOMEM;
3835 goto outfree_link_name;
3836 }
3837 }
3838 config++;
3839 }
3840 w_param_enum[0].items = num_params;
3841 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003842
3843 memset(&template, 0, sizeof(template));
3844 template.reg = SND_SOC_NOPM;
3845 template.id = snd_soc_dapm_dai_link;
3846 template.name = link_name;
3847 template.event = snd_soc_dai_link_event;
3848 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3849 SND_SOC_DAPM_PRE_PMD;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003850 template.num_kcontrols = 1;
3851 /* duplicate w_param_enum on heap so that memory persists */
3852 private_value =
3853 (unsigned long) devm_kmemdup(card->dev,
3854 (void *)(kcontrol_dai_link[0].private_value),
3855 sizeof(struct soc_enum), GFP_KERNEL);
3856 if (!private_value) {
3857 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3858 link_name);
3859 ret = -ENOMEM;
3860 goto outfree_link_name;
3861 }
3862 kcontrol_dai_link[0].private_value = private_value;
3863 /* duplicate kcontrol_dai_link on heap so that memory persists */
3864 template.kcontrol_news =
3865 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3866 sizeof(struct snd_kcontrol_new),
3867 GFP_KERNEL);
3868 if (!template.kcontrol_news) {
3869 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3870 link_name);
3871 ret = -ENOMEM;
3872 goto outfree_private_value;
3873 }
Mark Brownc74184e2012-04-04 22:12:09 +01003874
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003875 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003876
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003877 w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
Linus Walleij37e1df82017-01-13 10:23:52 +01003878 if (IS_ERR(w)) {
3879 ret = PTR_ERR(w);
3880 /* Do not nag about probe deferrals */
3881 if (ret != -EPROBE_DEFER)
3882 dev_err(card->dev,
3883 "ASoC: Failed to create %s widget (%d)\n",
3884 link_name, ret);
3885 goto outfree_kcontrol_news;
3886 }
Mark Brownc74184e2012-04-04 22:12:09 +01003887 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003888 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003889 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003890 ret = -ENOMEM;
3891 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003892 }
3893
3894 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003895 w->num_params = num_params;
Mark Brownc74184e2012-04-04 22:12:09 +01003896
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003897 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3898 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003899 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003900 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003901
3902outfree_w:
3903 devm_kfree(card->dev, w);
3904outfree_kcontrol_news:
3905 devm_kfree(card->dev, (void *)template.kcontrol_news);
3906outfree_private_value:
3907 devm_kfree(card->dev, (void *)private_value);
3908outfree_link_name:
3909 devm_kfree(card->dev, link_name);
3910outfree_w_param:
3911 for (count = 0 ; count < num_params; count++)
3912 devm_kfree(card->dev, (void *)w_param_text[count]);
3913 devm_kfree(card->dev, w_param_text);
3914
3915 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003916}
3917
Mark Brown888df392012-02-16 19:37:51 -08003918int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3919 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003920{
Mark Brown888df392012-02-16 19:37:51 -08003921 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003922 struct snd_soc_dapm_widget *w;
3923
Mark Brown888df392012-02-16 19:37:51 -08003924 WARN_ON(dapm->dev != dai->dev);
3925
3926 memset(&template, 0, sizeof(template));
3927 template.reg = SND_SOC_NOPM;
3928
3929 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003930 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003931 template.name = dai->driver->playback.stream_name;
3932 template.sname = dai->driver->playback.stream_name;
3933
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003934 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003935 template.name);
3936
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003937 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Linus Walleij639467c2017-01-20 14:07:52 +01003938 if (IS_ERR(w)) {
3939 int ret = PTR_ERR(w);
3940
3941 /* Do not nag about probe deferrals */
3942 if (ret != -EPROBE_DEFER)
3943 dev_err(dapm->dev,
3944 "ASoC: Failed to create %s widget (%d)\n",
3945 dai->driver->playback.stream_name, ret);
3946 return ret;
3947 }
Mark Brown888df392012-02-16 19:37:51 -08003948 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003949 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003950 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003951 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003952 }
3953
3954 w->priv = dai;
3955 dai->playback_widget = w;
3956 }
3957
3958 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003959 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003960 template.name = dai->driver->capture.stream_name;
3961 template.sname = dai->driver->capture.stream_name;
3962
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003963 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003964 template.name);
3965
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003966 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Linus Walleij639467c2017-01-20 14:07:52 +01003967 if (IS_ERR(w)) {
3968 int ret = PTR_ERR(w);
3969
3970 /* Do not nag about probe deferrals */
3971 if (ret != -EPROBE_DEFER)
3972 dev_err(dapm->dev,
3973 "ASoC: Failed to create %s widget (%d)\n",
3974 dai->driver->playback.stream_name, ret);
3975 return ret;
3976 }
Mark Brown888df392012-02-16 19:37:51 -08003977 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003978 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003979 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003980 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003981 }
3982
3983 w->priv = dai;
3984 dai->capture_widget = w;
3985 }
3986
3987 return 0;
3988}
3989
3990int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3991{
3992 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003993 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08003994 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003995
3996 /* For each DAI widget... */
3997 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003998 switch (dai_w->id) {
3999 case snd_soc_dapm_dai_in:
4000 case snd_soc_dapm_dai_out:
4001 break;
4002 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02004003 continue;
Mark Brown46162742013-06-05 19:36:11 +01004004 }
Mark Brown888df392012-02-16 19:37:51 -08004005
4006 dai = dai_w->priv;
4007
4008 /* ...find all widgets with the same stream and link them */
4009 list_for_each_entry(w, &card->widgets, list) {
4010 if (w->dapm != dai_w->dapm)
4011 continue;
4012
Mark Brown46162742013-06-05 19:36:11 +01004013 switch (w->id) {
4014 case snd_soc_dapm_dai_in:
4015 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08004016 continue;
Mark Brown46162742013-06-05 19:36:11 +01004017 default:
4018 break;
4019 }
Mark Brown888df392012-02-16 19:37:51 -08004020
Lars-Peter Clausena798c242015-07-21 11:51:35 +02004021 if (!w->sname || !strstr(w->sname, dai_w->sname))
Mark Brown888df392012-02-16 19:37:51 -08004022 continue;
4023
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004024 if (dai_w->id == snd_soc_dapm_dai_in) {
4025 src = dai_w;
4026 sink = w;
4027 } else {
4028 src = w;
4029 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08004030 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02004031 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
4032 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004033 }
4034 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02004035
Mark Brown888df392012-02-16 19:37:51 -08004036 return 0;
4037}
Liam Girdwood64a648c2011-07-25 11:15:15 +01004038
Benoit Cousson44ba2642014-07-08 23:19:36 +02004039static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
4040 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004041{
Benoit Cousson44ba2642014-07-08 23:19:36 +02004042 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004043 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004044 int i;
4045
Benoit Cousson44ba2642014-07-08 23:19:36 +02004046 for (i = 0; i < rtd->num_codecs; i++) {
4047 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004048
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004049 /* connect BE DAI playback if widgets are valid */
4050 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004051 source = cpu_dai->playback_widget;
4052 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004053 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02004054 cpu_dai->component->name, source->name,
4055 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004056
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004057 snd_soc_dapm_add_path(&card->dapm, source, sink,
4058 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004059 }
4060
4061 /* connect BE DAI capture if widgets are valid */
4062 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004063 source = codec_dai->capture_widget;
4064 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004065 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02004066 codec_dai->component->name, source->name,
4067 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004068
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02004069 snd_soc_dapm_add_path(&card->dapm, source, sink,
4070 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004071 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004072 }
4073}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004074
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004075static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
4076 int event)
4077{
4078 struct snd_soc_dapm_widget *w;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004079 unsigned int ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004080
4081 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
4082 w = dai->playback_widget;
4083 else
4084 w = dai->capture_widget;
4085
4086 if (w) {
4087 dapm_mark_dirty(w, "stream event");
4088
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004089 if (w->id == snd_soc_dapm_dai_in) {
4090 ep = SND_SOC_DAPM_EP_SOURCE;
4091 dapm_widget_invalidate_input_paths(w);
4092 } else {
4093 ep = SND_SOC_DAPM_EP_SINK;
4094 dapm_widget_invalidate_output_paths(w);
4095 }
4096
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004097 switch (event) {
4098 case SND_SOC_DAPM_STREAM_START:
4099 w->active = 1;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004100 w->is_ep = ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004101 break;
4102 case SND_SOC_DAPM_STREAM_STOP:
4103 w->active = 0;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02004104 w->is_ep = 0;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004105 break;
4106 case SND_SOC_DAPM_STREAM_SUSPEND:
4107 case SND_SOC_DAPM_STREAM_RESUME:
4108 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
4109 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
4110 break;
4111 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00004112 }
4113}
4114
Benoit Cousson44ba2642014-07-08 23:19:36 +02004115void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
4116{
Mengdong Lin1a497982015-11-18 02:34:11 -05004117 struct snd_soc_pcm_runtime *rtd;
Benoit Cousson44ba2642014-07-08 23:19:36 +02004118
4119 /* for each BE DAI link... */
Mengdong Lin1a497982015-11-18 02:34:11 -05004120 list_for_each_entry(rtd, &card->rtd_list, list) {
Benoit Cousson44ba2642014-07-08 23:19:36 +02004121 /*
4122 * dynamic FE links have no fixed DAI mapping.
4123 * CODEC<->CODEC links have no direct connection.
4124 */
4125 if (rtd->dai_link->dynamic || rtd->dai_link->params)
4126 continue;
4127
4128 dapm_connect_dai_link_widgets(card, rtd);
4129 }
4130}
4131
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004132static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4133 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004134{
Benoit Cousson44ba2642014-07-08 23:19:36 +02004135 int i;
4136
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02004137 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02004138 for (i = 0; i < rtd->num_codecs; i++)
4139 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004140
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004141 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004142}
4143
4144/**
4145 * snd_soc_dapm_stream_event - send a stream event to the dapm core
4146 * @rtd: PCM runtime data
4147 * @stream: stream name
4148 * @event: stream event
4149 *
4150 * Sends a stream event to the dapm core. The core then makes any
4151 * necessary widget power changes.
4152 *
4153 * Returns 0 for success else error.
4154 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004155void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
4156 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004157{
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00004158 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004159
Liam Girdwood3cd04342012-03-09 12:02:08 +00004160 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00004161 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2df2012-03-07 10:38:26 +00004162 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004163}
Richard Purdie2b97eab2006-10-06 18:32:18 +02004164
4165/**
Charles Keepax11391102014-02-18 15:22:14 +00004166 * snd_soc_dapm_enable_pin_unlocked - enable pin.
4167 * @dapm: DAPM context
4168 * @pin: pin name
4169 *
4170 * Enables input/output pin and its parents or children widgets iff there is
4171 * a valid audio route and active audio stream.
4172 *
4173 * Requires external locking.
4174 *
4175 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4176 * do any widget power switching.
4177 */
4178int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4179 const char *pin)
4180{
4181 return snd_soc_dapm_set_pin(dapm, pin, 1);
4182}
4183EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
4184
4185/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004186 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004187 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004188 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02004189 *
Mark Brown74b8f952009-06-06 11:26:15 +01004190 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01004191 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00004192 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004193 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4194 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02004195 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004196int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004197{
Charles Keepax11391102014-02-18 15:22:14 +00004198 int ret;
4199
4200 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4201
4202 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
4203
4204 mutex_unlock(&dapm->card->dapm_mutex);
4205
4206 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02004207}
Liam Girdwooda5302182008-07-07 13:35:17 +01004208EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004209
4210/**
Charles Keepax11391102014-02-18 15:22:14 +00004211 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
4212 * @dapm: DAPM context
4213 * @pin: pin name
4214 *
4215 * Enables input/output pin regardless of any other state. This is
4216 * intended for use with microphone bias supplies used in microphone
4217 * jack detection.
4218 *
4219 * Requires external locking.
4220 *
4221 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4222 * do any widget power switching.
4223 */
4224int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4225 const char *pin)
4226{
4227 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
4228
4229 if (!w) {
4230 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
4231 return -EINVAL;
4232 }
4233
4234 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02004235 if (!w->connected) {
4236 /*
4237 * w->force does not affect the number of input or output paths,
4238 * so we only have to recheck if w->connected is changed
4239 */
4240 dapm_widget_invalidate_input_paths(w);
4241 dapm_widget_invalidate_output_paths(w);
4242 w->connected = 1;
4243 }
Charles Keepax11391102014-02-18 15:22:14 +00004244 w->force = 1;
4245 dapm_mark_dirty(w, "force enable");
4246
4247 return 0;
4248}
4249EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
4250
4251/**
Mark Brownda341832010-03-15 19:23:37 +00004252 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004253 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00004254 * @pin: pin name
4255 *
4256 * Enables input/output pin regardless of any other state. This is
4257 * intended for use with microphone bias supplies used in microphone
4258 * jack detection.
4259 *
4260 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4261 * do any widget power switching.
4262 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004263int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4264 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00004265{
Charles Keepax11391102014-02-18 15:22:14 +00004266 int ret;
Mark Brownda341832010-03-15 19:23:37 +00004267
Charles Keepax11391102014-02-18 15:22:14 +00004268 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00004269
Charles Keepax11391102014-02-18 15:22:14 +00004270 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09004271
Charles Keepax11391102014-02-18 15:22:14 +00004272 mutex_unlock(&dapm->card->dapm_mutex);
4273
4274 return ret;
Mark Brownda341832010-03-15 19:23:37 +00004275}
4276EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4277
4278/**
Charles Keepax11391102014-02-18 15:22:14 +00004279 * snd_soc_dapm_disable_pin_unlocked - disable pin.
4280 * @dapm: DAPM context
4281 * @pin: pin name
4282 *
4283 * Disables input/output pin and its parents or children widgets.
4284 *
4285 * Requires external locking.
4286 *
4287 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4288 * do any widget power switching.
4289 */
4290int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4291 const char *pin)
4292{
4293 return snd_soc_dapm_set_pin(dapm, pin, 0);
4294}
4295EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4296
4297/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004298 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004299 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004300 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004301 *
Mark Brown74b8f952009-06-06 11:26:15 +01004302 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004303 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004304 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4305 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004306 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004307int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4308 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004309{
Charles Keepax11391102014-02-18 15:22:14 +00004310 int ret;
4311
4312 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4313
4314 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4315
4316 mutex_unlock(&dapm->card->dapm_mutex);
4317
4318 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004319}
4320EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4321
4322/**
Charles Keepax11391102014-02-18 15:22:14 +00004323 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4324 * @dapm: DAPM context
4325 * @pin: pin name
4326 *
4327 * Marks the specified pin as being not connected, disabling it along
4328 * any parent or child widgets. At present this is identical to
4329 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4330 * additional things such as disabling controls which only affect
4331 * paths through the pin.
4332 *
4333 * Requires external locking.
4334 *
4335 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4336 * do any widget power switching.
4337 */
4338int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4339 const char *pin)
4340{
4341 return snd_soc_dapm_set_pin(dapm, pin, 0);
4342}
4343EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4344
4345/**
Mark Brown5817b522008-09-24 11:23:11 +01004346 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004347 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004348 * @pin: pin name
4349 *
4350 * Marks the specified pin as being not connected, disabling it along
4351 * any parent or child widgets. At present this is identical to
4352 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4353 * additional things such as disabling controls which only affect
4354 * paths through the pin.
4355 *
4356 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4357 * do any widget power switching.
4358 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004359int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004360{
Charles Keepax11391102014-02-18 15:22:14 +00004361 int ret;
4362
4363 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4364
4365 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4366
4367 mutex_unlock(&dapm->card->dapm_mutex);
4368
4369 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004370}
4371EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4372
4373/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004374 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004375 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004376 * @pin: audio signal pin endpoint (or start point)
4377 *
4378 * Get audio pin status - connected or disconnected.
4379 *
4380 * Returns 1 for connected otherwise 0.
4381 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004382int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4383 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004384{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004385 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004386
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004387 if (w)
4388 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004389
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004390 return 0;
4391}
Liam Girdwooda5302182008-07-07 13:35:17 +01004392EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004393
4394/**
Mark Brown1547aba2010-05-07 21:11:40 +01004395 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004396 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004397 * @pin: audio signal pin endpoint (or start point)
4398 *
4399 * Mark the given endpoint or pin as ignoring suspend. When the
4400 * system is disabled a path between two endpoints flagged as ignoring
4401 * suspend will not be disabled. The path must already be enabled via
4402 * normal means at suspend time, it will not be turned on if it was not
4403 * already enabled.
4404 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004405int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4406 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004407{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004408 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004409
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004410 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004411 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004412 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004413 }
4414
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004415 w->ignore_suspend = 1;
4416
4417 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004418}
4419EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4420
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004421/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004422 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004423 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004424 *
4425 * Free all dapm widgets and resources.
4426 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004427void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004428{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004429 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004430 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004431 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004432}
4433EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4434
Xiang Xiao57996352014-03-02 00:04:02 +08004435static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004436{
Liam Girdwood01005a72012-07-06 16:57:05 +01004437 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004438 struct snd_soc_dapm_widget *w;
4439 LIST_HEAD(down_list);
4440 int powerdown = 0;
4441
Liam Girdwood01005a72012-07-06 16:57:05 +01004442 mutex_lock(&card->dapm_mutex);
4443
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004444 list_for_each_entry(w, &dapm->card->widgets, list) {
4445 if (w->dapm != dapm)
4446 continue;
Mark Brown51737472009-06-22 13:16:51 +01004447 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004448 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004449 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004450 powerdown = 1;
4451 }
4452 }
4453
4454 /* If there were no widgets to power down we're already in
4455 * standby.
4456 */
4457 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004458 if (dapm->bias_level == SND_SOC_BIAS_ON)
4459 snd_soc_dapm_set_bias_level(dapm,
4460 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004461 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004462 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4463 snd_soc_dapm_set_bias_level(dapm,
4464 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004465 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004466
4467 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004468}
Mark Brown51737472009-06-22 13:16:51 +01004469
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004470/*
4471 * snd_soc_dapm_shutdown - callback for system shutdown
4472 */
4473void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4474{
Xiang Xiao57996352014-03-02 00:04:02 +08004475 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004476
Xiang Xiao57996352014-03-02 00:04:02 +08004477 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004478 if (dapm != &card->dapm) {
4479 soc_dapm_shutdown_dapm(dapm);
4480 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4481 snd_soc_dapm_set_bias_level(dapm,
4482 SND_SOC_BIAS_OFF);
4483 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004484 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004485
4486 soc_dapm_shutdown_dapm(&card->dapm);
4487 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4488 snd_soc_dapm_set_bias_level(&card->dapm,
4489 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004490}
4491
Richard Purdie2b97eab2006-10-06 18:32:18 +02004492/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004493MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004494MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4495MODULE_LICENSE("GPL");