blob: 27b7fd96e8197a58ccd2c0315f381ddbf5381e31 [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 Brown15e4c72f2008-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 Brown15e4c72f2008-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 Brown15e4c72f2008-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 Brown15e4c72f2008-07-02 11:51:20 +0100155 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200156
157 kfree(buf);
Mark Brown15e4c72f2008-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,
313 struct snd_kcontrol *kcontrol)
314{
315 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200316 struct soc_mixer_control *mc;
Charles Keepax561ed682015-05-01 12:37:26 +0100317 struct soc_enum *e;
Charles Keepax773da9b2015-05-01 12:37:25 +0100318 const char *name;
319 int ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200320
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200321 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100322 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200323 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200324
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200325 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200326
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200327 switch (widget->id) {
328 case snd_soc_dapm_switch:
329 case snd_soc_dapm_mixer:
330 case snd_soc_dapm_mixer_named_ctl:
331 mc = (struct soc_mixer_control *)kcontrol->private_value;
332
333 if (mc->autodisable) {
334 struct snd_soc_dapm_widget template;
335
Charles Keepax773da9b2015-05-01 12:37:25 +0100336 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
337 "Autodisable");
338 if (!name) {
339 ret = -ENOMEM;
340 goto err_data;
341 }
342
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200343 memset(&template, 0, sizeof(template));
344 template.reg = mc->reg;
345 template.mask = (1 << fls(mc->max)) - 1;
346 template.shift = mc->shift;
347 if (mc->invert)
348 template.off_val = mc->max;
349 else
350 template.off_val = 0;
351 template.on_val = template.off_val;
352 template.id = snd_soc_dapm_kcontrol;
Charles Keepax773da9b2015-05-01 12:37:25 +0100353 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200354
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200355 data->value = template.on_val;
356
Liam Girdwood02aa78a2015-05-25 18:21:17 +0100357 data->widget =
358 snd_soc_dapm_new_control_unlocked(widget->dapm,
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200359 &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200360 kfree(name);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200361 if (!data->widget) {
Charles Keepax773da9b2015-05-01 12:37:25 +0100362 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200363 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200364 }
365 }
366 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200367 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100368 case snd_soc_dapm_mux:
369 e = (struct soc_enum *)kcontrol->private_value;
370
371 if (e->autodisable) {
372 struct snd_soc_dapm_widget template;
373
374 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
375 "Autodisable");
376 if (!name) {
377 ret = -ENOMEM;
378 goto err_data;
379 }
380
381 memset(&template, 0, sizeof(template));
382 template.reg = e->reg;
383 template.mask = e->mask << e->shift_l;
384 template.shift = e->shift_l;
385 template.off_val = snd_soc_enum_item_to_val(e, 0);
386 template.on_val = template.off_val;
387 template.id = snd_soc_dapm_kcontrol;
388 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200389
390 data->value = template.on_val;
391
Charles Keepaxffacb482015-06-26 10:39:43 +0100392 data->widget = snd_soc_dapm_new_control_unlocked(
393 widget->dapm, &template);
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200394 kfree(name);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200395 if (!data->widget) {
Charles Keepax561ed682015-05-01 12:37:26 +0100396 ret = -ENOMEM;
Lars-Peter Clausene18077b2015-07-08 21:59:59 +0200397 goto err_data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200398 }
Charles Keepax561ed682015-05-01 12:37:26 +0100399
400 snd_soc_dapm_add_path(widget->dapm, data->widget,
401 widget, NULL, NULL);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200402 }
403 break;
404 default:
405 break;
406 }
407
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200408 kcontrol->private_data = data;
409
410 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100411
Charles Keepax773da9b2015-05-01 12:37:25 +0100412err_data:
413 kfree(data);
414 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200415}
416
417static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
418{
419 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200420 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200421 kfree(data);
422}
423
424static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
425 const struct snd_kcontrol *kcontrol)
426{
427 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
428
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200429 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200430}
431
432static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
433 struct snd_soc_dapm_widget *widget)
434{
435 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200436 struct snd_soc_dapm_widget_list *new_wlist;
437 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200438
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200439 if (data->wlist)
440 n = data->wlist->num_widgets + 1;
441 else
442 n = 1;
443
444 new_wlist = krealloc(data->wlist,
445 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
446 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200447 return -ENOMEM;
448
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200449 new_wlist->widgets[n - 1] = widget;
450 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200451
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200452 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200453
454 return 0;
455}
456
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200457static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
458 struct snd_soc_dapm_path *path)
459{
460 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
461
462 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200463}
464
465static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
466{
467 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
468
469 if (!data->widget)
470 return true;
471
472 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200473}
474
475static struct list_head *dapm_kcontrol_get_path_list(
476 const struct snd_kcontrol *kcontrol)
477{
478 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
479
480 return &data->paths;
481}
482
483#define dapm_kcontrol_for_each_path(path, kcontrol) \
484 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
485 list_kcontrol)
486
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530487unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200488{
489 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
490
491 return data->value;
492}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530493EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200494
495static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
496 unsigned int value)
497{
498 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
499
500 if (data->value == value)
501 return false;
502
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200503 if (data->widget)
504 data->widget->on_val = value;
505
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200506 data->value = value;
507
508 return true;
509}
510
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200511/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200512 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
513 * kcontrol
514 * @kcontrol: The kcontrol
515 *
516 * Note: This function must only be used on kcontrols that are known to have
517 * been registered for a CODEC. Otherwise the behaviour is undefined.
518 */
519struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
520 struct snd_kcontrol *kcontrol)
521{
522 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
523}
524EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
525
Liam Girdwood6c120e12012-02-15 15:15:34 +0000526static void dapm_reset(struct snd_soc_card *card)
527{
528 struct snd_soc_dapm_widget *w;
529
Mark Brownf9fa2b12014-03-06 16:49:11 +0800530 lockdep_assert_held(&card->dapm_mutex);
531
Liam Girdwood6c120e12012-02-15 15:15:34 +0000532 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
533
534 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200535 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000536 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000537 }
538}
539
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200540static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
541{
542 if (!dapm->component)
543 return NULL;
544 return dapm->component->name_prefix;
545}
546
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200547static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800548 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100549{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200550 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200551 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200552 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100553}
554
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200555static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800556 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100557{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200558 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200559 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000560 return snd_soc_component_update_bits(dapm->component, reg,
561 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000562}
563
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200564static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
565 int reg, unsigned int mask, unsigned int value)
566{
567 if (!dapm->component)
568 return -EIO;
569 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
570}
571
Mark Browneb270e92013-10-09 13:52:52 +0100572static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
573{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200574 if (dapm->component)
575 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100576}
577
Charles Keepax45a110a2015-05-11 13:50:30 +0100578static struct snd_soc_dapm_widget *
579dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
580{
581 struct snd_soc_dapm_widget *w = wcache->widget;
582 struct list_head *wlist;
583 const int depth = 2;
584 int i = 0;
585
586 if (w) {
587 wlist = &w->dapm->card->widgets;
588
589 list_for_each_entry_from(w, wlist, list) {
590 if (!strcmp(name, w->name))
591 return w;
592
593 if (++i == depth)
594 break;
595 }
596 }
597
598 return NULL;
599}
600
601static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
602 struct snd_soc_dapm_widget *w)
603{
604 wcache->widget = w;
605}
606
Mark Brown452c5ea2009-05-17 21:41:23 +0100607/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200608 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
609 * @dapm: The DAPM context for which to set the level
610 * @level: The level to set
611 *
612 * Forces the DAPM bias level to a specific state. It will call the bias level
613 * callback of DAPM context with the specified level. This will even happen if
614 * the context is already at the same level. Furthermore it will not go through
615 * the normal bias level sequencing, meaning any intermediate states between the
616 * current and the target state will not be entered.
617 *
618 * Note that the change in bias level is only temporary and the next time
619 * snd_soc_dapm_sync() is called the state will be set to the level as
620 * determined by the DAPM core. The function is mainly intended to be used to
621 * used during probe or resume from suspend to power up the device so
622 * initialization can be done, before the DAPM core takes over.
623 */
624int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
625 enum snd_soc_bias_level level)
626{
627 int ret = 0;
628
629 if (dapm->set_bias_level)
630 ret = dapm->set_bias_level(dapm, level);
631
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200632 if (ret == 0)
633 dapm->bias_level = level;
634
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200635 return ret;
636}
637EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
638
Mark Brown452c5ea2009-05-17 21:41:23 +0100639/**
640 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800641 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100642 * @level: level to configure
643 *
644 * Configure the bias (power) levels for the SoC audio device.
645 *
646 * Returns 0 for success else error.
647 */
Mark Browned5a4c42011-02-18 11:12:42 -0800648static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200649 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100650{
Mark Browned5a4c42011-02-18 11:12:42 -0800651 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100652 int ret = 0;
653
Mark Brown84e90932010-11-04 00:07:02 -0400654 trace_snd_soc_bias_level_start(card, level);
655
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000656 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100657 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100658 if (ret != 0)
659 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100660
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200661 if (!card || dapm != &card->dapm)
662 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100663
Mark Brown171ec6b2011-06-06 18:15:19 +0100664 if (ret != 0)
665 goto out;
666
667 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100668 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100669out:
Mark Brown84e90932010-11-04 00:07:02 -0400670 trace_snd_soc_bias_level_done(card, level);
671
Mark Brown452c5ea2009-05-17 21:41:23 +0100672 return ret;
673}
674
Mark Brown74b8f952009-06-06 11:26:15 +0100675/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200676static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200677 struct snd_soc_dapm_path *path, const char *control_name,
678 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200679{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200680 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200681 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100682 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200683 int i;
684
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100685 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200686 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100687 val = (val >> e->shift_l) & e->mask;
688 item = snd_soc_enum_val_to_item(e, val);
689 } else {
690 /* since a virtual mux has no backing registers to
691 * decide which path to connect, it will try to match
692 * with the first enumeration. This is to ensure
693 * that the default mux choice (the first) will be
694 * correctly powered up during initialization.
695 */
696 item = 0;
697 }
698
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100699 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200700 if (!(strcmp(control_name, e->texts[i]))) {
Rasmus Villemoes98ad73c2014-10-21 17:01:15 +0200701 path->name = e->texts[i];
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100702 if (i == item)
703 path->connect = 1;
704 else
705 path->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200706 return 0;
707 }
708 }
709
710 return -ENODEV;
711}
712
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100713/* set up initial codec paths */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200714static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100715{
716 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200717 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100718 unsigned int reg = mc->reg;
719 unsigned int shift = mc->shift;
720 unsigned int max = mc->max;
721 unsigned int mask = (1 << fls(max)) - 1;
722 unsigned int invert = mc->invert;
723 unsigned int val;
724
725 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200726 soc_dapm_read(p->sink->dapm, reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100727 val = (val >> shift) & mask;
728 if (invert)
729 val = max - val;
730 p->connect = !!val;
731 } else {
732 p->connect = 0;
733 }
734}
735
Mark Brown74b8f952009-06-06 11:26:15 +0100736/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200737static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200738 struct snd_soc_dapm_path *path, const char *control_name)
739{
740 int i;
741
742 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200743 for (i = 0; i < path->sink->num_kcontrols; i++) {
744 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
745 path->name = path->sink->kcontrol_news[i].name;
746 dapm_set_mixer_path_status(path, i);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200747 return 0;
748 }
749 }
750 return -ENODEV;
751}
752
Stephen Warrenaf468002011-04-28 17:38:01 -0600753static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600754 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600755 const struct snd_kcontrol_new *kcontrol_new,
756 struct snd_kcontrol **kcontrol)
757{
758 struct snd_soc_dapm_widget *w;
759 int i;
760
761 *kcontrol = NULL;
762
763 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600764 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
765 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600766 for (i = 0; i < w->num_kcontrols; i++) {
767 if (&w->kcontrol_news[i] == kcontrol_new) {
768 if (w->kcontrols)
769 *kcontrol = w->kcontrols[i];
770 return 1;
771 }
772 }
773 }
774
775 return 0;
776}
777
Stephen Warren85762e72013-03-29 15:40:10 -0600778/*
779 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
780 * create it. Either way, add the widget into the control's widget list
781 */
782static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100783 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200784{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200785 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000786 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000787 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600788 size_t prefix_len;
789 int shared;
790 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600791 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200792 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600793 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200794 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000795
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200796 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000797 if (prefix)
798 prefix_len = strlen(prefix) + 1;
799 else
800 prefix_len = 0;
801
Stephen Warren85762e72013-03-29 15:40:10 -0600802 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
803 &kcontrol);
804
Stephen Warren85762e72013-03-29 15:40:10 -0600805 if (!kcontrol) {
806 if (shared) {
807 wname_in_long_name = false;
808 kcname_in_long_name = true;
809 } else {
810 switch (w->id) {
811 case snd_soc_dapm_switch:
812 case snd_soc_dapm_mixer:
813 wname_in_long_name = true;
814 kcname_in_long_name = true;
815 break;
816 case snd_soc_dapm_mixer_named_ctl:
817 wname_in_long_name = false;
818 kcname_in_long_name = true;
819 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200820 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600821 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600822 wname_in_long_name = true;
823 kcname_in_long_name = false;
824 break;
825 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600826 return -EINVAL;
827 }
828 }
829
830 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600831 /*
832 * The control will get a prefix from the control
833 * creation process but we're also using the same
834 * prefix for widgets so cut the prefix off the
835 * front of the widget name.
836 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200837 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600838 w->name + prefix_len,
839 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200840 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200841 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600842
843 name = long_name;
844 } else if (wname_in_long_name) {
845 long_name = NULL;
846 name = w->name + prefix_len;
847 } else {
848 long_name = NULL;
849 name = w->kcontrol_news[kci].name;
850 }
851
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200852 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600853 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200854 if (!kcontrol) {
855 ret = -ENOMEM;
856 goto exit_free;
857 }
858
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200859 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200860
861 ret = dapm_kcontrol_data_alloc(w, kcontrol);
862 if (ret) {
863 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200864 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200865 }
866
Stephen Warren85762e72013-03-29 15:40:10 -0600867 ret = snd_ctl_add(card, kcontrol);
868 if (ret < 0) {
869 dev_err(dapm->dev,
870 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
871 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200872 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600873 }
Stephen Warren85762e72013-03-29 15:40:10 -0600874 }
875
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200876 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200877 if (ret == 0)
878 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200879
Daniel Macke5092c92014-10-07 13:41:24 +0200880exit_free:
881 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600882
Daniel Macke5092c92014-10-07 13:41:24 +0200883 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600884}
885
886/* create new dapm mixer control */
887static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
888{
889 int i, ret;
890 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100891 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600892
Richard Purdie2b97eab2006-10-06 18:32:18 +0200893 /* add kcontrol */
894 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200895 /* match name */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +0200896 snd_soc_dapm_widget_for_each_source_path(w, path) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200897 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600898 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200899 continue;
900
Charles Keepax561ed682015-05-01 12:37:26 +0100901 if (!w->kcontrols[i]) {
902 ret = dapm_create_or_share_mixmux_kcontrol(w, i);
903 if (ret < 0)
904 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200905 }
906
Mark Brown946d92a2013-08-12 23:28:42 +0100907 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100908
909 data = snd_kcontrol_chip(w->kcontrols[i]);
910 if (data->widget)
911 snd_soc_dapm_add_path(data->widget->dapm,
912 data->widget,
913 path->source,
914 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200915 }
916 }
Stephen Warren85762e72013-03-29 15:40:10 -0600917
918 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200919}
920
921/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200922static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200923{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200924 struct snd_soc_dapm_context *dapm = w->dapm;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200925 enum snd_soc_dapm_direction dir;
Stephen Warren85762e72013-03-29 15:40:10 -0600926 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200927 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600928 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200929
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200930 switch (w->id) {
931 case snd_soc_dapm_mux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200932 dir = SND_SOC_DAPM_DIR_OUT;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200933 type = "mux";
934 break;
935 case snd_soc_dapm_demux:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200936 dir = SND_SOC_DAPM_DIR_IN;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200937 type = "demux";
938 break;
939 default:
940 return -EINVAL;
941 }
942
Stephen Warrenaf468002011-04-28 17:38:01 -0600943 if (w->num_kcontrols != 1) {
944 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200945 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600946 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200947 return -EINVAL;
948 }
949
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200950 if (list_empty(&w->edges[dir])) {
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200951 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600952 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600953 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200954
Mark Brown946d92a2013-08-12 23:28:42 +0100955 ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600956 if (ret < 0)
957 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600958
Lars-Peter Clausena3423b02015-08-11 21:38:00 +0200959 snd_soc_dapm_widget_for_each_path(w, dir, path) {
960 if (path->name)
961 dapm_kcontrol_add_path(w->kcontrols[0], path);
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +0200962 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200963
Stephen Warrenaf468002011-04-28 17:38:01 -0600964 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200965}
966
967/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200968static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200969{
Mark Browna6c65732010-03-03 17:45:21 +0000970 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200971 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000972 "ASoC: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200973
Mark Browna6c65732010-03-03 17:45:21 +0000974 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200975}
976
Nikesh Oswalc6615082015-02-02 17:06:44 +0000977/* create new dapm dai link control */
978static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
979{
980 int i, ret;
981 struct snd_kcontrol *kcontrol;
982 struct snd_soc_dapm_context *dapm = w->dapm;
983 struct snd_card *card = dapm->card->snd_card;
984
985 /* create control for links with > 1 config */
986 if (w->num_params <= 1)
987 return 0;
988
989 /* add kcontrol */
990 for (i = 0; i < w->num_kcontrols; i++) {
991 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
992 w->name, NULL);
993 ret = snd_ctl_add(card, kcontrol);
994 if (ret < 0) {
995 dev_err(dapm->dev,
996 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
997 w->name, w->kcontrol_news[i].name, ret);
998 return ret;
999 }
1000 kcontrol->private_data = w;
1001 w->kcontrols[i] = kcontrol;
1002 }
1003
1004 return 0;
1005}
1006
Mark Brown9949788b2010-05-07 20:24:05 +01001007/* We implement power down on suspend by checking the power state of
1008 * the ALSA card - when we are suspending the ALSA state for the card
1009 * is set to D3.
1010 */
1011static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
1012{
Mark Brown12ea2c72011-03-02 18:17:32 +00001013 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown9949788b2010-05-07 20:24:05 +01001014
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001015 switch (level) {
Mark Brown9949788b2010-05-07 20:24:05 +01001016 case SNDRV_CTL_POWER_D3hot:
1017 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +01001018 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001019 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001020 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +01001021 return widget->ignore_suspend;
Mark Brown9949788b2010-05-07 20:24:05 +01001022 default:
1023 return 1;
1024 }
1025}
1026
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001027static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list,
1028 struct list_head *widgets)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001029{
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001030 struct snd_soc_dapm_widget *w;
1031 struct list_head *it;
1032 unsigned int size = 0;
1033 unsigned int i = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001034
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001035 list_for_each(it, widgets)
1036 size++;
1037
1038 *list = kzalloc(sizeof(**list) + size * sizeof(*w), GFP_KERNEL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001039 if (*list == NULL)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001040 return -ENOMEM;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001041
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001042 list_for_each_entry(w, widgets, work_list)
1043 (*list)->widgets[i++] = w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001044
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001045 (*list)->num_widgets = i;
1046
1047 return 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001048}
1049
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001050static void trace_snd_soc_dapm_path(struct snd_soc_dapm_widget *w,
1051 enum snd_soc_dapm_direction dir, struct snd_soc_dapm_path *p)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001052{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001053 if (dir == SND_SOC_DAPM_DIR_IN)
1054 trace_snd_soc_dapm_input_path(w, p);
1055 else
1056 trace_snd_soc_dapm_output_path(w, p);
1057}
1058
1059/*
1060 * Common implementation for is_connected_output_ep() and
1061 * is_connected_input_ep(). The function is inlined since the combined size of
1062 * the two specialized functions is only marginally larger then the size of the
1063 * generic function and at the same time the fast path of the specialized
1064 * functions is significantly smaller than the generic function.
1065 */
1066static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget,
1067 struct list_head *list, enum snd_soc_dapm_direction dir,
1068 int (*fn)(struct snd_soc_dapm_widget *, struct list_head *))
1069{
1070 enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001071 struct snd_soc_dapm_path *path;
1072 int con = 0;
1073
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001074 if (widget->endpoints[dir] >= 0)
1075 return widget->endpoints[dir];
Mark Brown024dc072011-10-09 11:52:05 +01001076
Mark Brownde02d072011-09-20 21:43:24 +01001077 DAPM_UPDATE_STAT(widget, path_checks);
1078
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001079 /* do we need to add this widget to the list ? */
1080 if (list)
1081 list_add_tail(&widget->work_list, list);
1082
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001083 if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) {
1084 widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget);
1085 return widget->endpoints[dir];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001086 }
1087
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001088 snd_soc_dapm_widget_for_each_path(widget, rdir, path) {
Mark Browne56235e02011-09-21 18:19:14 +01001089 DAPM_UPDATE_STAT(widget, neighbour_checks);
1090
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001091 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001092 continue;
1093
Mark Brown8af294b2013-02-22 17:48:15 +00001094 if (path->walking)
1095 return 1;
1096
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001097 trace_snd_soc_dapm_path(widget, dir, path);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001098
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001099 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001100 path->walking = 1;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001101 con += fn(path->node[dir], list);
Mark Brown8af294b2013-02-22 17:48:15 +00001102 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001103 }
1104 }
1105
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001106 widget->endpoints[dir] = con;
Mark Brown024dc072011-10-09 11:52:05 +01001107
Richard Purdie2b97eab2006-10-06 18:32:18 +02001108 return con;
1109}
1110
1111/*
1112 * Recursively check for a completed path to an active or physically connected
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001113 * output widget. Returns number of complete paths.
1114 */
1115static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
1116 struct list_head *list)
1117{
1118 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT,
1119 is_connected_output_ep);
1120}
1121
1122/*
1123 * Recursively check for a completed path to an active or physically connected
Richard Purdie2b97eab2006-10-06 18:32:18 +02001124 * input widget. Returns number of complete paths.
1125 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001126static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001127 struct list_head *list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001128{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001129 return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN,
1130 is_connected_input_ep);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001131}
1132
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001133/**
1134 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1135 * @dai: the soc DAI.
1136 * @stream: stream direction.
1137 * @list: list of active widgets for this stream.
1138 *
1139 * Queries DAPM graph as to whether an valid audio stream path exists for
1140 * the initial stream specified by name. This takes into account
1141 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1142 *
1143 * Returns the number of valid paths or negative error.
1144 */
1145int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1146 struct snd_soc_dapm_widget_list **list)
1147{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001148 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001149 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001150 LIST_HEAD(widgets);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001151 int paths;
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001152 int ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001153
1154 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001155
1156 /*
1157 * For is_connected_{output,input}_ep fully discover the graph we need
1158 * to reset the cached number of inputs and outputs.
1159 */
1160 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001161 w->endpoints[SND_SOC_DAPM_DIR_IN] = -1;
1162 w->endpoints[SND_SOC_DAPM_DIR_OUT] = -1;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001163 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001164
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001165 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001166 paths = is_connected_output_ep(dai->playback_widget, &widgets);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001167 else
Lars-Peter Clausen1ce43ac2015-07-26 19:04:59 +02001168 paths = is_connected_input_ep(dai->capture_widget, &widgets);
1169
1170 /* Drop starting point */
1171 list_del(widgets.next);
1172
1173 ret = dapm_widget_list_create(list, &widgets);
1174 if (ret)
Lars-Peter Clausen30abbe72015-08-11 21:37:59 +02001175 paths = ret;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001176
1177 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001178 mutex_unlock(&card->dapm_mutex);
1179
1180 return paths;
1181}
1182
Richard Purdie2b97eab2006-10-06 18:32:18 +02001183/*
Mark Brown62ea8742012-01-21 21:14:48 +00001184 * Handler for regulator supply widget.
1185 */
1186int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1187 struct snd_kcontrol *kcontrol, int event)
1188{
Mark Brownc05b84d2012-09-07 12:57:11 +08001189 int ret;
1190
Mark Browneb270e92013-10-09 13:52:52 +01001191 soc_dapm_async_complete(w->dapm);
1192
Mark Brownc05b84d2012-09-07 12:57:11 +08001193 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001194 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001195 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001196 if (ret != 0)
1197 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001198 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001199 w->name, ret);
1200 }
1201
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001202 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001203 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001204 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001205 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001206 if (ret != 0)
1207 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001208 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001209 w->name, ret);
1210 }
1211
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001212 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001213 }
Mark Brown62ea8742012-01-21 21:14:48 +00001214}
1215EXPORT_SYMBOL_GPL(dapm_regulator_event);
1216
Ola Liljad7e7eb92012-05-24 15:26:25 +02001217/*
1218 * Handler for clock supply widget.
1219 */
1220int dapm_clock_event(struct snd_soc_dapm_widget *w,
1221 struct snd_kcontrol *kcontrol, int event)
1222{
1223 if (!w->clk)
1224 return -EIO;
1225
Mark Browneb270e92013-10-09 13:52:52 +01001226 soc_dapm_async_complete(w->dapm);
1227
Mark Brownec029952012-06-04 08:16:20 +01001228#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001229 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001230 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001231 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001232 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001233 return 0;
1234 }
Mark Brownec029952012-06-04 08:16:20 +01001235#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001236 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001237}
1238EXPORT_SYMBOL_GPL(dapm_clock_event);
1239
Mark Brownd805002b2011-09-28 18:28:23 +01001240static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1241{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001242 if (w->power_checked)
1243 return w->new_power;
1244
Mark Brownd805002b2011-09-28 18:28:23 +01001245 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001246 w->new_power = 1;
Mark Brownd805002b2011-09-28 18:28:23 +01001247 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001248 w->new_power = w->power_check(w);
1249
1250 w->power_checked = true;
1251
1252 return w->new_power;
Mark Brownd805002b2011-09-28 18:28:23 +01001253}
1254
Mark Browncd0f2d42009-04-20 16:56:59 +01001255/* Generic check to see if a widget should be powered.
1256 */
1257static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1258{
1259 int in, out;
1260
Mark Brownde02d072011-09-20 21:43:24 +01001261 DAPM_UPDATE_STAT(w, power_checks);
1262
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001263 in = is_connected_input_ep(w, NULL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001264 out = is_connected_output_ep(w, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001265 return out != 0 && in != 0;
1266}
1267
Mark Brown246d0a12009-04-22 18:24:55 +01001268/* Check to see if a power supply is needed */
1269static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1270{
1271 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001272
Mark Brownde02d072011-09-20 21:43:24 +01001273 DAPM_UPDATE_STAT(w, power_checks);
1274
Mark Brown246d0a12009-04-22 18:24:55 +01001275 /* Check if one of our outputs is connected */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001276 snd_soc_dapm_widget_for_each_sink_path(w, path) {
Mark Browna8fdac82011-09-28 18:20:26 +01001277 DAPM_UPDATE_STAT(w, neighbour_checks);
1278
Mark Brownbf3a9e12011-06-13 16:42:29 +01001279 if (path->weak)
1280 continue;
1281
Mark Brown215edda2009-09-08 18:59:05 +01001282 if (path->connected &&
1283 !path->connected(path->source, path->sink))
1284 continue;
1285
Mark Brownf68d7e12011-10-04 22:57:50 +01001286 if (dapm_widget_power_check(path->sink))
1287 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001288 }
1289
Mark Brownf68d7e12011-10-04 22:57:50 +01001290 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001291}
1292
Mark Brown35c64bc2011-09-28 18:23:53 +01001293static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1294{
1295 return 1;
1296}
1297
Mark Brown38357ab2009-06-06 19:03:23 +01001298static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1299 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001300 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001301{
Mark Brown828a8422011-01-15 13:14:30 +00001302 int *sort;
1303
1304 if (power_up)
1305 sort = dapm_up_seq;
1306 else
1307 sort = dapm_down_seq;
1308
Mark Brown38357ab2009-06-06 19:03:23 +01001309 if (sort[a->id] != sort[b->id])
1310 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001311 if (a->subseq != b->subseq) {
1312 if (power_up)
1313 return a->subseq - b->subseq;
1314 else
1315 return b->subseq - a->subseq;
1316 }
Mark Brownb22ead22009-06-07 12:51:26 +01001317 if (a->reg != b->reg)
1318 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001319 if (a->dapm != b->dapm)
1320 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001321
Mark Brown38357ab2009-06-06 19:03:23 +01001322 return 0;
1323}
Mark Brown42aa3412009-03-01 19:21:10 +00001324
Mark Brown38357ab2009-06-06 19:03:23 +01001325/* Insert a widget in order into a DAPM power sequence. */
1326static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1327 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001328 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001329{
1330 struct snd_soc_dapm_widget *w;
1331
1332 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001333 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001334 list_add_tail(&new_widget->power_list, &w->power_list);
1335 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001336 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001337
Mark Brown38357ab2009-06-06 19:03:23 +01001338 list_add_tail(&new_widget->power_list, list);
1339}
Mark Brown42aa3412009-03-01 19:21:10 +00001340
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001341static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001342 struct snd_soc_dapm_widget *w, int event)
1343{
Mark Brown68f89ad2010-11-03 23:51:49 -04001344 const char *ev_name;
1345 int power, ret;
1346
1347 switch (event) {
1348 case SND_SOC_DAPM_PRE_PMU:
1349 ev_name = "PRE_PMU";
1350 power = 1;
1351 break;
1352 case SND_SOC_DAPM_POST_PMU:
1353 ev_name = "POST_PMU";
1354 power = 1;
1355 break;
1356 case SND_SOC_DAPM_PRE_PMD:
1357 ev_name = "PRE_PMD";
1358 power = 0;
1359 break;
1360 case SND_SOC_DAPM_POST_PMD:
1361 ev_name = "POST_PMD";
1362 power = 0;
1363 break;
Mark Brown80114122013-02-25 15:14:19 +00001364 case SND_SOC_DAPM_WILL_PMU:
1365 ev_name = "WILL_PMU";
1366 power = 1;
1367 break;
1368 case SND_SOC_DAPM_WILL_PMD:
1369 ev_name = "WILL_PMD";
1370 power = 0;
1371 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001372 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001373 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001374 return;
1375 }
1376
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001377 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001378 return;
1379
1380 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001381 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001382 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001383 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001384 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001385 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001386 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001387 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001388 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001389 ev_name, w->name, ret);
1390 }
1391}
1392
Mark Brownb22ead22009-06-07 12:51:26 +01001393/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001394static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001395 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001396{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001397 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001398 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001399 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001400 unsigned int value = 0;
1401 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001402
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001403 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1404 reg = w->reg;
1405 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001406
1407 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001408 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001409 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001410
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001411 mask |= w->mask << w->shift;
1412 if (w->power)
1413 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001414 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001415 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001416
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001417 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001418 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1419 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001420
Mark Brown68f89ad2010-11-03 23:51:49 -04001421 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001422 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1423 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001424 }
1425
Mark Brown81628102009-06-07 13:21:24 +01001426 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001427 /* Any widget will do, they should all be updating the
1428 * same register.
1429 */
Mark Brown29376bc2011-06-19 13:49:28 +01001430
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001431 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001432 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001433 value, mask, reg, card->pop_time);
1434 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001435 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001436 }
1437
1438 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001439 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1440 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001441 }
Mark Brown42aa3412009-03-01 19:21:10 +00001442}
1443
Mark Brownb22ead22009-06-07 12:51:26 +01001444/* Apply a DAPM power sequence.
1445 *
1446 * We walk over a pre-sorted list of widgets to apply power to. In
1447 * order to minimise the number of writes to the device required
1448 * multiple widgets will be updated in a single write where possible.
1449 * Currently anything that requires more than a single write is not
1450 * handled.
1451 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001452static void dapm_seq_run(struct snd_soc_card *card,
1453 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001454{
1455 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001456 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001457 LIST_HEAD(pending);
1458 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001459 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001460 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001461 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001462 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001463 int *sort;
1464
1465 if (power_up)
1466 sort = dapm_up_seq;
1467 else
1468 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001469
Mark Brownb22ead22009-06-07 12:51:26 +01001470 list_for_each_entry_safe(w, n, list, power_list) {
1471 ret = 0;
1472
1473 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001474 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001475 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001476 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001477 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001478
Mark Brown474b62d2011-01-18 16:14:44 +00001479 if (cur_dapm && cur_dapm->seq_notifier) {
1480 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1481 if (sort[i] == cur_sort)
1482 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001483 i,
1484 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001485 }
1486
Mark Browneb270e92013-10-09 13:52:52 +01001487 if (cur_dapm && w->dapm != cur_dapm)
1488 soc_dapm_async_complete(cur_dapm);
1489
Mark Brownb22ead22009-06-07 12:51:26 +01001490 INIT_LIST_HEAD(&pending);
1491 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001492 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001493 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001494 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001495 }
1496
Mark Brown163cac02009-06-07 10:12:52 +01001497 switch (w->id) {
1498 case snd_soc_dapm_pre:
1499 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001500 list_for_each_entry_safe_continue(w, n, list,
1501 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001502
Mark Brownb22ead22009-06-07 12:51:26 +01001503 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001504 ret = w->event(w,
1505 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001506 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001507 ret = w->event(w,
1508 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001509 break;
1510
1511 case snd_soc_dapm_post:
1512 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001513 list_for_each_entry_safe_continue(w, n, list,
1514 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001515
Mark Brownb22ead22009-06-07 12:51:26 +01001516 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001517 ret = w->event(w,
1518 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001519 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001520 ret = w->event(w,
1521 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001522 break;
1523
Mark Brown163cac02009-06-07 10:12:52 +01001524 default:
Mark Brown81628102009-06-07 13:21:24 +01001525 /* Queue it up for application */
1526 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001527 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001528 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001529 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001530 list_move(&w->power_list, &pending);
1531 break;
Mark Brown163cac02009-06-07 10:12:52 +01001532 }
Mark Brownb22ead22009-06-07 12:51:26 +01001533
1534 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001535 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001536 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001537 }
Mark Brownb22ead22009-06-07 12:51:26 +01001538
1539 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001540 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001541
1542 if (cur_dapm && cur_dapm->seq_notifier) {
1543 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1544 if (sort[i] == cur_sort)
1545 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001546 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001547 }
Mark Browneb270e92013-10-09 13:52:52 +01001548
1549 list_for_each_entry(d, &card->dapm_list, list) {
1550 soc_dapm_async_complete(d);
1551 }
Mark Brown163cac02009-06-07 10:12:52 +01001552}
1553
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001554static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001555{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001556 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001557 struct snd_soc_dapm_widget_list *wlist;
1558 struct snd_soc_dapm_widget *w = NULL;
1559 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001560 int ret;
1561
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001562 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001563 return;
1564
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001565 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001566
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001567 for (wi = 0; wi < wlist->num_widgets; wi++) {
1568 w = wlist->widgets[wi];
1569
1570 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1571 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1572 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001573 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001574 w->name, ret);
1575 }
Mark Brown97404f22010-12-14 16:13:57 +00001576 }
1577
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001578 if (!w)
1579 return;
1580
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001581 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1582 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001583 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001584 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001585 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001586
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001587 for (wi = 0; wi < wlist->num_widgets; wi++) {
1588 w = wlist->widgets[wi];
1589
1590 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1591 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1592 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001593 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001594 w->name, ret);
1595 }
Mark Brown97404f22010-12-14 16:13:57 +00001596 }
1597}
1598
Mark Brown9d0624a2011-02-18 11:49:43 -08001599/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1600 * they're changing state.
1601 */
1602static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1603{
1604 struct snd_soc_dapm_context *d = data;
1605 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001606
Mark Brown56fba412011-06-04 11:25:10 +01001607 /* If we're off and we're not supposed to be go into STANDBY */
1608 if (d->bias_level == SND_SOC_BIAS_OFF &&
1609 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001610 if (d->dev)
1611 pm_runtime_get_sync(d->dev);
1612
Mark Brown9d0624a2011-02-18 11:49:43 -08001613 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1614 if (ret != 0)
1615 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001616 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001617 }
1618
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001619 /* Prepare for a transition to ON or away from ON */
1620 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1621 d->bias_level != SND_SOC_BIAS_ON) ||
1622 (d->target_bias_level != SND_SOC_BIAS_ON &&
1623 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001624 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1625 if (ret != 0)
1626 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001627 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001628 }
1629}
1630
1631/* Async callback run prior to DAPM sequences - brings to their final
1632 * state.
1633 */
1634static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1635{
1636 struct snd_soc_dapm_context *d = data;
1637 int ret;
1638
1639 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001640 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1641 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1642 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001643 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1644 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001645 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001646 ret);
1647 }
1648
1649 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001650 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1651 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001652 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1653 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001654 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1655 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001656
1657 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001658 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001659 }
1660
1661 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001662 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1663 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001664 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1665 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001666 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001667 ret);
1668 }
1669}
Mark Brown97404f22010-12-14 16:13:57 +00001670
Mark Brownfe4fda52011-10-03 22:36:57 +01001671static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1672 bool power, bool connect)
1673{
1674 /* If a connection is being made or broken then that update
1675 * will have marked the peer dirty, otherwise the widgets are
1676 * not connected and this update has no impact. */
1677 if (!connect)
1678 return;
1679
1680 /* If the peer is already in the state we're moving to then we
1681 * won't have an impact on it. */
1682 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001683 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001684}
1685
Mark Brown05623c42011-09-28 17:02:31 +01001686static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1687 struct list_head *up_list,
1688 struct list_head *down_list)
1689{
Mark Browndb432b42011-10-03 21:06:40 +01001690 struct snd_soc_dapm_path *path;
1691
Mark Brown05623c42011-09-28 17:02:31 +01001692 if (w->power == power)
1693 return;
1694
1695 trace_snd_soc_dapm_widget_power(w, power);
1696
Mark Browndb432b42011-10-03 21:06:40 +01001697 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001698 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001699 */
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001700 snd_soc_dapm_widget_for_each_source_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001701 dapm_widget_set_peer_power(path->source, power, path->connect);
1702
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001703 /* Supplies can't affect their outputs, only their inputs */
1704 if (!w->is_supply) {
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02001705 snd_soc_dapm_widget_for_each_sink_path(w, path)
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001706 dapm_widget_set_peer_power(path->sink, power,
1707 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001708 }
1709
Mark Brown05623c42011-09-28 17:02:31 +01001710 if (power)
1711 dapm_seq_insert(w, up_list, true);
1712 else
1713 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001714}
1715
Mark Brown7c81beb2011-09-20 22:22:32 +01001716static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1717 struct list_head *up_list,
1718 struct list_head *down_list)
1719{
Mark Brown7c81beb2011-09-20 22:22:32 +01001720 int power;
1721
1722 switch (w->id) {
1723 case snd_soc_dapm_pre:
1724 dapm_seq_insert(w, down_list, false);
1725 break;
1726 case snd_soc_dapm_post:
1727 dapm_seq_insert(w, up_list, true);
1728 break;
1729
1730 default:
Mark Brownd805002b2011-09-28 18:28:23 +01001731 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001732
Mark Brown05623c42011-09-28 17:02:31 +01001733 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001734 break;
1735 }
1736}
1737
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001738static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1739{
1740 if (dapm->idle_bias_off)
1741 return true;
1742
1743 switch (snd_power_get_state(dapm->card->snd_card)) {
1744 case SNDRV_CTL_POWER_D3hot:
1745 case SNDRV_CTL_POWER_D3cold:
1746 return dapm->suspend_bias_off;
1747 default:
1748 break;
1749 }
1750
1751 return false;
1752}
1753
Mark Brown42aa3412009-03-01 19:21:10 +00001754/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001755 * Scan each dapm widget for complete audio path.
1756 * A complete path is a route that has valid endpoints i.e.:-
1757 *
1758 * o DAC to output pin.
1759 * o Input Pin to ADC.
1760 * o Input pin to Output pin (bypass, sidetone)
1761 * o DAC to ADC (loopback).
1762 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001763static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001764{
1765 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001766 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001767 LIST_HEAD(up_list);
1768 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001769 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001770 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001771
Mark Brownf9fa2b12014-03-06 16:49:11 +08001772 lockdep_assert_held(&card->dapm_mutex);
1773
Mark Brown84e90932010-11-04 00:07:02 -04001774 trace_snd_soc_dapm_start(card);
1775
Mark Brown56fba412011-06-04 11:25:10 +01001776 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001777 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001778 d->target_bias_level = SND_SOC_BIAS_OFF;
1779 else
1780 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001781 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001782
Liam Girdwood6c120e12012-02-15 15:15:34 +00001783 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001784
Mark Brown6d3ddc82009-05-16 17:47:29 +01001785 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001786 * lists indicating if they should be powered up or down. We
1787 * only check widgets that have been flagged as dirty but note
1788 * that new widgets may be added to the dirty list while we
1789 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001790 */
Mark Browndb432b42011-10-03 21:06:40 +01001791 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001792 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001793 }
1794
Mark Brownf9de6d72011-09-28 17:19:47 +01001795 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001796 switch (w->id) {
1797 case snd_soc_dapm_pre:
1798 case snd_soc_dapm_post:
1799 /* These widgets always need to be powered */
1800 break;
1801 default:
1802 list_del_init(&w->dirty);
1803 break;
1804 }
Mark Browndb432b42011-10-03 21:06:40 +01001805
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001806 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001807 d = w->dapm;
1808
1809 /* Supplies and micbiases only bring the
1810 * context up to STANDBY as unless something
1811 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001812 * generally don't require full power. Signal
1813 * generators are virtual pins and have no
1814 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001815 */
1816 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001817 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001818 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001819 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001820 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001821 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001822 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001823 case snd_soc_dapm_micbias:
1824 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1825 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1826 break;
1827 default:
1828 d->target_bias_level = SND_SOC_BIAS_ON;
1829 break;
1830 }
1831 }
1832
1833 }
1834
Mark Brown85a843c2011-09-21 21:29:47 +01001835 /* Force all contexts in the card to the same bias state if
1836 * they're not ground referenced.
1837 */
Mark Brown56fba412011-06-04 11:25:10 +01001838 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001839 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001840 if (d->target_bias_level > bias)
1841 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001842 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001843 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001844 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001845
Mark Brownde02d072011-09-20 21:43:24 +01001846 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001847
Xiang Xiao17282ba2014-03-02 00:04:03 +08001848 /* Run card bias changes at first */
1849 dapm_pre_sequence_async(&card->dapm, 0);
1850 /* Run other bias changes in parallel */
1851 list_for_each_entry(d, &card->dapm_list, list) {
1852 if (d != &card->dapm)
1853 async_schedule_domain(dapm_pre_sequence_async, d,
1854 &async_domain);
1855 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001856 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001857
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001858 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001859 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001860 }
1861
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001862 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001863 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001864 }
1865
Mark Brown6d3ddc82009-05-16 17:47:29 +01001866 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001867 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001868
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001869 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001870
Mark Brown6d3ddc82009-05-16 17:47:29 +01001871 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001872 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001873
Mark Brown9d0624a2011-02-18 11:49:43 -08001874 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001875 list_for_each_entry(d, &card->dapm_list, list) {
1876 if (d != &card->dapm)
1877 async_schedule_domain(dapm_post_sequence_async, d,
1878 &async_domain);
1879 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001880 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001881 /* Run card bias changes at last */
1882 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001883
Liam Girdwood8078d872012-02-15 15:15:35 +00001884 /* do we need to notify any clients that DAPM event is complete */
1885 list_for_each_entry(d, &card->dapm_list, list) {
1886 if (d->stream_event)
1887 d->stream_event(d, event);
1888 }
1889
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001890 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001891 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001892 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001893
Mark Brown84e90932010-11-04 00:07:02 -04001894 trace_snd_soc_dapm_done(card);
1895
Mark Brown42aa3412009-03-01 19:21:10 +00001896 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001897}
1898
Mark Brown79fb9382009-08-21 16:38:13 +01001899#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001900static ssize_t dapm_widget_power_read_file(struct file *file,
1901 char __user *user_buf,
1902 size_t count, loff_t *ppos)
1903{
1904 struct snd_soc_dapm_widget *w = file->private_data;
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001905 struct snd_soc_card *card = w->dapm->card;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001906 enum snd_soc_dapm_direction dir, rdir;
Mark Brown79fb9382009-08-21 16:38:13 +01001907 char *buf;
1908 int in, out;
1909 ssize_t ret;
1910 struct snd_soc_dapm_path *p = NULL;
1911
1912 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1913 if (!buf)
1914 return -ENOMEM;
1915
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001916 mutex_lock(&card->dapm_mutex);
1917
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001918 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
1919 if (w->is_supply) {
1920 in = 0;
1921 out = 0;
1922 } else {
1923 in = is_connected_input_ep(w, NULL);
1924 out = is_connected_output_ep(w, NULL);
1925 }
Mark Brown79fb9382009-08-21 16:38:13 +01001926
Mark Brownf13ebad2012-03-03 18:01:01 +00001927 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1928 w->name, w->power ? "On" : "Off",
1929 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001930
Mark Brownd033c362009-12-04 15:25:56 +00001931 if (w->reg >= 0)
1932 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001933 " - R%d(0x%x) mask 0x%x",
1934 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00001935
1936 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1937
Mark Brown3eef08b2009-09-14 16:49:00 +01001938 if (w->sname)
1939 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1940 w->sname,
1941 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001942
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001943 snd_soc_dapm_for_each_direction(dir) {
1944 rdir = SND_SOC_DAPM_DIR_REVERSE(dir);
1945 snd_soc_dapm_widget_for_each_path(w, dir, p) {
1946 if (p->connected && !p->connected(w, p->node[rdir]))
1947 continue;
Mark Brown215edda2009-09-08 18:59:05 +01001948
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001949 if (!p->connect)
1950 continue;
Mark Brown215edda2009-09-08 18:59:05 +01001951
Mark Brown79fb9382009-08-21 16:38:13 +01001952 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001953 " %s \"%s\" \"%s\"\n",
1954 (rdir == SND_SOC_DAPM_DIR_IN) ? "in" : "out",
Mark Brown79fb9382009-08-21 16:38:13 +01001955 p->name ? p->name : "static",
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02001956 p->node[rdir]->name);
1957 }
Mark Brown79fb9382009-08-21 16:38:13 +01001958 }
1959
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02001960 mutex_unlock(&card->dapm_mutex);
1961
Mark Brown79fb9382009-08-21 16:38:13 +01001962 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1963
1964 kfree(buf);
1965 return ret;
1966}
1967
1968static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001969 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01001970 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001971 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001972};
1973
Mark Brownef49e4f2011-04-04 20:48:13 +09001974static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1975 size_t count, loff_t *ppos)
1976{
1977 struct snd_soc_dapm_context *dapm = file->private_data;
1978 char *level;
1979
1980 switch (dapm->bias_level) {
1981 case SND_SOC_BIAS_ON:
1982 level = "On\n";
1983 break;
1984 case SND_SOC_BIAS_PREPARE:
1985 level = "Prepare\n";
1986 break;
1987 case SND_SOC_BIAS_STANDBY:
1988 level = "Standby\n";
1989 break;
1990 case SND_SOC_BIAS_OFF:
1991 level = "Off\n";
1992 break;
1993 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001994 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09001995 level = "Unknown\n";
1996 break;
1997 }
1998
1999 return simple_read_from_buffer(user_buf, count, ppos, level,
2000 strlen(level));
2001}
2002
2003static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002004 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002005 .read = dapm_bias_read_file,
2006 .llseek = default_llseek,
2007};
2008
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002009void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2010 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002011{
Mark Brown79fb9382009-08-21 16:38:13 +01002012 struct dentry *d;
2013
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002014 if (!parent)
2015 return;
2016
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002017 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2018
2019 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002020 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002021 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002022 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002023 }
Mark Brown79fb9382009-08-21 16:38:13 +01002024
Mark Brownef49e4f2011-04-04 20:48:13 +09002025 d = debugfs_create_file("bias_level", 0444,
2026 dapm->debugfs_dapm, dapm,
2027 &dapm_bias_fops);
2028 if (!d)
2029 dev_warn(dapm->dev,
2030 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002031}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002032
2033static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2034{
2035 struct snd_soc_dapm_context *dapm = w->dapm;
2036 struct dentry *d;
2037
2038 if (!dapm->debugfs_dapm || !w->name)
2039 return;
2040
2041 d = debugfs_create_file(w->name, 0444,
2042 dapm->debugfs_dapm, w,
2043 &dapm_widget_power_fops);
2044 if (!d)
2045 dev_warn(w->dapm->dev,
2046 "ASoC: Failed to create %s debugfs file\n",
2047 w->name);
2048}
2049
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002050static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2051{
2052 debugfs_remove_recursive(dapm->debugfs_dapm);
2053}
2054
Mark Brown79fb9382009-08-21 16:38:13 +01002055#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002056void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2057 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002058{
2059}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002060
2061static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2062{
2063}
2064
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002065static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2066{
2067}
2068
Mark Brown79fb9382009-08-21 16:38:13 +01002069#endif
2070
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002071/*
2072 * soc_dapm_connect_path() - Connects or disconnects a path
2073 * @path: The path to update
2074 * @connect: The new connect state of the path. True if the path is connected,
2075 * false if it is disconneted.
2076 * @reason: The reason why the path changed (for debugging only)
2077 */
2078static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2079 bool connect, const char *reason)
2080{
2081 if (path->connect == connect)
2082 return;
2083
2084 path->connect = connect;
2085 dapm_mark_dirty(path->source, reason);
2086 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002087 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002088}
2089
Richard Purdie2b97eab2006-10-06 18:32:18 +02002090/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002091static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002092 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002093{
2094 struct snd_soc_dapm_path *path;
2095 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002096 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002097
Mark Brownf9fa2b12014-03-06 16:49:11 +08002098 lockdep_assert_held(&card->dapm_mutex);
2099
Richard Purdie2b97eab2006-10-06 18:32:18 +02002100 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002101 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002102 found = 1;
2103 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002104 if (!(strcmp(path->name, e->texts[mux])))
2105 connect = true;
2106 else
2107 connect = false;
2108
2109 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002110 }
2111
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002112 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002113 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002114
Liam Girdwood618dae12012-04-25 12:12:51 +01002115 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002116}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002117
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002118int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002119 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2120 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002121{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002122 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002123 int ret;
2124
Liam Girdwood3cd04342012-03-09 12:02:08 +00002125 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002126 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002127 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002128 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002129 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002130 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002131 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002132 return ret;
2133}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002134EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002135
Milan plzik1b075e32008-01-10 14:39:46 +01002136/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002137static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Mark Brown283375c2009-12-07 18:09:03 +00002138 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002139{
2140 struct snd_soc_dapm_path *path;
2141 int found = 0;
2142
Mark Brownf9fa2b12014-03-06 16:49:11 +08002143 lockdep_assert_held(&card->dapm_mutex);
2144
Richard Purdie2b97eab2006-10-06 18:32:18 +02002145 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002146 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002147 found = 1;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002148 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002149 }
2150
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002151 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002152 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002153
Liam Girdwood618dae12012-04-25 12:12:51 +01002154 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002155}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002156
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002157int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002158 struct snd_kcontrol *kcontrol, int connect,
2159 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002160{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002161 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002162 int ret;
2163
Liam Girdwood3cd04342012-03-09 12:02:08 +00002164 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002165 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002166 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002167 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002168 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002169 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002170 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002171 return ret;
2172}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002173EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002174
Benoit Cousson44ba2642014-07-08 23:19:36 +02002175static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002176{
Richard Purdie2b97eab2006-10-06 18:32:18 +02002177 struct snd_soc_dapm_widget *w;
2178 int count = 0;
2179 char *state = "not set";
2180
Lars-Peter Clausen00200102014-07-17 22:01:07 +02002181 list_for_each_entry(w, &codec->component.card->widgets, list) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002182 if (w->dapm != &codec->dapm)
2183 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002184
2185 /* only display widgets that burnm power */
2186 switch (w->id) {
2187 case snd_soc_dapm_hp:
2188 case snd_soc_dapm_mic:
2189 case snd_soc_dapm_spk:
2190 case snd_soc_dapm_line:
2191 case snd_soc_dapm_micbias:
2192 case snd_soc_dapm_dac:
2193 case snd_soc_dapm_adc:
2194 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002195 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002196 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002197 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002198 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002199 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002200 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002201 if (w->name)
2202 count += sprintf(buf + count, "%s: %s\n",
2203 w->name, w->power ? "On":"Off");
2204 break;
2205 default:
2206 break;
2207 }
2208 }
2209
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002210 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02002211 case SND_SOC_BIAS_ON:
2212 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002213 break;
Mark Brown0be98982008-05-19 12:31:28 +02002214 case SND_SOC_BIAS_PREPARE:
2215 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002216 break;
Mark Brown0be98982008-05-19 12:31:28 +02002217 case SND_SOC_BIAS_STANDBY:
2218 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002219 break;
Mark Brown0be98982008-05-19 12:31:28 +02002220 case SND_SOC_BIAS_OFF:
2221 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002222 break;
2223 }
2224 count += sprintf(buf + count, "PM State: %s\n", state);
2225
2226 return count;
2227}
2228
Benoit Cousson44ba2642014-07-08 23:19:36 +02002229/* show dapm widget status in sys fs */
2230static ssize_t dapm_widget_show(struct device *dev,
2231 struct device_attribute *attr, char *buf)
2232{
2233 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2234 int i, count = 0;
2235
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002236 mutex_lock(&rtd->card->dapm_mutex);
2237
Benoit Cousson44ba2642014-07-08 23:19:36 +02002238 for (i = 0; i < rtd->num_codecs; i++) {
2239 struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
2240 count += dapm_widget_show_codec(codec, buf + count);
2241 }
2242
Lars-Peter Clausene50b1e02015-07-06 17:01:24 +02002243 mutex_unlock(&rtd->card->dapm_mutex);
2244
Benoit Cousson44ba2642014-07-08 23:19:36 +02002245 return count;
2246}
2247
Richard Purdie2b97eab2006-10-06 18:32:18 +02002248static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2249
Takashi Iwaid29697d2015-01-30 20:16:37 +01002250struct attribute *soc_dapm_dev_attrs[] = {
2251 &dev_attr_dapm_widget.attr,
2252 NULL
2253};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002254
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002255static void dapm_free_path(struct snd_soc_dapm_path *path)
2256{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002257 list_del(&path->list_node[SND_SOC_DAPM_DIR_IN]);
2258 list_del(&path->list_node[SND_SOC_DAPM_DIR_OUT]);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002259 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002260 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002261 kfree(path);
2262}
2263
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002264void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
2265{
2266 struct snd_soc_dapm_path *p, *next_p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002267 enum snd_soc_dapm_direction dir;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002268
2269 list_del(&w->list);
2270 /*
2271 * remove source and sink paths associated to this widget.
2272 * While removing the path, remove reference to it from both
2273 * source and sink widgets so that path is removed only once.
2274 */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002275 snd_soc_dapm_for_each_direction(dir) {
2276 snd_soc_dapm_widget_for_each_path_safe(w, dir, p, next_p)
2277 dapm_free_path(p);
2278 }
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002279
2280 kfree(w->kcontrols);
Lars-Peter Clausen48068962015-07-21 18:11:08 +02002281 kfree_const(w->name);
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002282 kfree(w);
2283}
2284
Richard Purdie2b97eab2006-10-06 18:32:18 +02002285/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002286static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002287{
2288 struct snd_soc_dapm_widget *w, *next_w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002289
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002290 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2291 if (w->dapm != dapm)
2292 continue;
Lars-Peter Clausenb97e2692015-07-21 18:11:07 +02002293 snd_soc_dapm_free_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002294 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002295}
2296
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002297static struct snd_soc_dapm_widget *dapm_find_widget(
2298 struct snd_soc_dapm_context *dapm, const char *pin,
2299 bool search_other_contexts)
2300{
2301 struct snd_soc_dapm_widget *w;
2302 struct snd_soc_dapm_widget *fallback = NULL;
2303
2304 list_for_each_entry(w, &dapm->card->widgets, list) {
2305 if (!strcmp(w->name, pin)) {
2306 if (w->dapm == dapm)
2307 return w;
2308 else
2309 fallback = w;
2310 }
2311 }
2312
2313 if (search_other_contexts)
2314 return fallback;
2315
2316 return NULL;
2317}
2318
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002319static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002320 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002321{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002322 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002323
Mark Brownf9fa2b12014-03-06 16:49:11 +08002324 dapm_assert_locked(dapm);
2325
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002326 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002327 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002328 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002329 }
2330
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002331 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002332 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002333 dapm_widget_invalidate_input_paths(w);
2334 dapm_widget_invalidate_output_paths(w);
2335 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002336
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002337 w->connected = status;
2338 if (status == 0)
2339 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002340
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002341 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002342}
2343
Richard Purdie2b97eab2006-10-06 18:32:18 +02002344/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002345 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2346 * @dapm: DAPM context
2347 *
2348 * Walks all dapm audio paths and powers widgets according to their
2349 * stream or path usage.
2350 *
2351 * Requires external locking.
2352 *
2353 * Returns 0 for success.
2354 */
2355int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2356{
2357 /*
2358 * Suppress early reports (eg, jacks syncing their state) to avoid
2359 * silly DAPM runs during card startup.
2360 */
2361 if (!dapm->card || !dapm->card->instantiated)
2362 return 0;
2363
2364 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2365}
2366EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2367
2368/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002369 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002370 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002371 *
2372 * Walks all dapm audio paths and powers widgets according to their
2373 * stream or path usage.
2374 *
2375 * Returns 0 for success.
2376 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002377int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002378{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002379 int ret;
2380
Liam Girdwood3cd04342012-03-09 12:02:08 +00002381 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002382 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002383 mutex_unlock(&dapm->card->dapm_mutex);
2384 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002385}
Liam Girdwooda5302182008-07-07 13:35:17 +01002386EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002387
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002388/*
2389 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2390 * @w: The widget for which to update the flags
2391 *
2392 * Some widgets have a dynamic category which depends on which neighbors they
2393 * are connected to. This function update the category for these widgets.
2394 *
2395 * This function must be called whenever a path is added or removed to a widget.
2396 */
2397static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2398{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002399 enum snd_soc_dapm_direction dir;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002400 struct snd_soc_dapm_path *p;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002401 unsigned int ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002402
2403 switch (w->id) {
2404 case snd_soc_dapm_input:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002405 /* On a fully routed card a input is never a source */
2406 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002407 return;
2408 ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002409 snd_soc_dapm_widget_for_each_source_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002410 if (p->source->id == snd_soc_dapm_micbias ||
2411 p->source->id == snd_soc_dapm_mic ||
2412 p->source->id == snd_soc_dapm_line ||
2413 p->source->id == snd_soc_dapm_output) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002414 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002415 break;
2416 }
2417 }
2418 break;
2419 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002420 /* On a fully routed card a output is never a sink */
2421 if (w->dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002422 return;
2423 ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002424 snd_soc_dapm_widget_for_each_sink_path(w, p) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002425 if (p->sink->id == snd_soc_dapm_spk ||
2426 p->sink->id == snd_soc_dapm_hp ||
2427 p->sink->id == snd_soc_dapm_line ||
2428 p->sink->id == snd_soc_dapm_input) {
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002429 ep = 0;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002430 break;
2431 }
2432 }
2433 break;
2434 case snd_soc_dapm_line:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002435 ep = 0;
2436 snd_soc_dapm_for_each_direction(dir) {
2437 if (!list_empty(&w->edges[dir]))
2438 ep |= SND_SOC_DAPM_DIR_TO_EP(dir);
2439 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002440 break;
2441 default:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002442 return;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002443 }
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002444
2445 w->is_ep = ep;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002446}
2447
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002448static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2449 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2450 const char *control)
2451{
2452 bool dynamic_source = false;
2453 bool dynamic_sink = false;
2454
2455 if (!control)
2456 return 0;
2457
2458 switch (source->id) {
2459 case snd_soc_dapm_demux:
2460 dynamic_source = true;
2461 break;
2462 default:
2463 break;
2464 }
2465
2466 switch (sink->id) {
2467 case snd_soc_dapm_mux:
2468 case snd_soc_dapm_switch:
2469 case snd_soc_dapm_mixer:
2470 case snd_soc_dapm_mixer_named_ctl:
2471 dynamic_sink = true;
2472 break;
2473 default:
2474 break;
2475 }
2476
2477 if (dynamic_source && dynamic_sink) {
2478 dev_err(dapm->dev,
2479 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2480 source->name, control, sink->name);
2481 return -EINVAL;
2482 } else if (!dynamic_source && !dynamic_sink) {
2483 dev_err(dapm->dev,
2484 "Control not supported for path %s -> [%s] -> %s\n",
2485 source->name, control, sink->name);
2486 return -EINVAL;
2487 }
2488
2489 return 0;
2490}
2491
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002492static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2493 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2494 const char *control,
2495 int (*connected)(struct snd_soc_dapm_widget *source,
2496 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002497{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002498 struct snd_soc_dapm_widget *widgets[2];
2499 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002500 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002501 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002502
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002503 if (wsink->is_supply && !wsource->is_supply) {
2504 dev_err(dapm->dev,
2505 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2506 wsource->name, wsink->name);
2507 return -EINVAL;
2508 }
2509
2510 if (connected && !wsource->is_supply) {
2511 dev_err(dapm->dev,
2512 "connected() callback only supported for supply widgets (%s -> %s)\n",
2513 wsource->name, wsink->name);
2514 return -EINVAL;
2515 }
2516
2517 if (wsource->is_supply && control) {
2518 dev_err(dapm->dev,
2519 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2520 wsource->name, control, wsink->name);
2521 return -EINVAL;
2522 }
2523
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002524 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2525 if (ret)
2526 return ret;
2527
Richard Purdie2b97eab2006-10-06 18:32:18 +02002528 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2529 if (!path)
2530 return -ENOMEM;
2531
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002532 path->node[SND_SOC_DAPM_DIR_IN] = wsource;
2533 path->node[SND_SOC_DAPM_DIR_OUT] = wsink;
2534 widgets[SND_SOC_DAPM_DIR_IN] = wsource;
2535 widgets[SND_SOC_DAPM_DIR_OUT] = wsink;
2536
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002537 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002538 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002539 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002540
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002541 if (wsource->is_supply || wsink->is_supply)
2542 path->is_supply = 1;
2543
Richard Purdie2b97eab2006-10-06 18:32:18 +02002544 /* connect static paths */
2545 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002546 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002547 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002548 switch (wsource->id) {
2549 case snd_soc_dapm_demux:
2550 ret = dapm_connect_mux(dapm, path, control, wsource);
2551 if (ret)
2552 goto err;
2553 break;
2554 default:
2555 break;
2556 }
2557
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002558 switch (wsink->id) {
2559 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002560 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002561 if (ret != 0)
2562 goto err;
2563 break;
2564 case snd_soc_dapm_switch:
2565 case snd_soc_dapm_mixer:
2566 case snd_soc_dapm_mixer_named_ctl:
2567 ret = dapm_connect_mixer(dapm, path, control);
2568 if (ret != 0)
2569 goto err;
2570 break;
2571 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002572 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002573 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002574 }
2575
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002576 list_add(&path->list, &dapm->card->paths);
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002577 snd_soc_dapm_for_each_direction(dir)
2578 list_add(&path->list_node[dir], &widgets[dir]->edges[dir]);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002579
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02002580 snd_soc_dapm_for_each_direction(dir) {
2581 dapm_update_widget_flags(widgets[dir]);
2582 dapm_mark_dirty(widgets[dir], "Route added");
2583 }
Mark Brownfabd0382012-07-05 17:20:06 +01002584
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002585 if (dapm->card->instantiated && path->connect)
2586 dapm_path_invalidate(path);
2587
Richard Purdie2b97eab2006-10-06 18:32:18 +02002588 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002589err:
2590 kfree(path);
2591 return ret;
2592}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002593
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002594static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002595 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002596{
2597 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2598 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2599 const char *sink;
2600 const char *source;
2601 char prefixed_sink[80];
2602 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002603 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002604 int ret;
2605
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002606 prefix = soc_dapm_prefix(dapm);
2607 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002608 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002609 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002610 sink = prefixed_sink;
2611 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002612 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002613 source = prefixed_source;
2614 } else {
2615 sink = route->sink;
2616 source = route->source;
2617 }
2618
Charles Keepax45a110a2015-05-11 13:50:30 +01002619 wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
2620 wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
2621
2622 if (wsink && wsource)
2623 goto skip_search;
2624
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002625 /*
2626 * find src and dest widgets over all widgets but favor a widget from
2627 * current DAPM context
2628 */
2629 list_for_each_entry(w, &dapm->card->widgets, list) {
2630 if (!wsink && !(strcmp(w->name, sink))) {
2631 wtsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002632 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002633 wsink = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002634 if (wsource)
2635 break;
2636 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002637 continue;
2638 }
2639 if (!wsource && !(strcmp(w->name, source))) {
2640 wtsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002641 if (w->dapm == dapm) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002642 wsource = w;
Charles Keepax70c75102015-05-07 11:33:58 +01002643 if (wsink)
2644 break;
2645 }
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002646 }
2647 }
2648 /* use widget from another DAPM context if not found from this */
2649 if (!wsink)
2650 wsink = wtsink;
2651 if (!wsource)
2652 wsource = wtsource;
2653
2654 if (wsource == NULL) {
2655 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2656 route->source);
2657 return -ENODEV;
2658 }
2659 if (wsink == NULL) {
2660 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2661 route->sink);
2662 return -ENODEV;
2663 }
2664
Charles Keepax45a110a2015-05-11 13:50:30 +01002665skip_search:
2666 dapm_wcache_update(&dapm->path_sink_cache, wsink);
2667 dapm_wcache_update(&dapm->path_source_cache, wsource);
2668
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002669 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2670 route->connected);
2671 if (ret)
2672 goto err;
2673
2674 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002675err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002676 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002677 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002678 return ret;
2679}
Mark Brown105f1c22008-05-13 14:52:19 +02002680
Mark Brownefcc3c62012-07-05 17:24:19 +01002681static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2682 const struct snd_soc_dapm_route *route)
2683{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002684 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002685 struct snd_soc_dapm_path *path, *p;
2686 const char *sink;
2687 const char *source;
2688 char prefixed_sink[80];
2689 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002690 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002691
2692 if (route->control) {
2693 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002694 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002695 return -EINVAL;
2696 }
2697
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002698 prefix = soc_dapm_prefix(dapm);
2699 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002700 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002701 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002702 sink = prefixed_sink;
2703 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002704 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002705 source = prefixed_source;
2706 } else {
2707 sink = route->sink;
2708 source = route->source;
2709 }
2710
2711 path = NULL;
2712 list_for_each_entry(p, &dapm->card->paths, list) {
2713 if (strcmp(p->source->name, source) != 0)
2714 continue;
2715 if (strcmp(p->sink->name, sink) != 0)
2716 continue;
2717 path = p;
2718 break;
2719 }
2720
2721 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002722 wsource = path->source;
2723 wsink = path->sink;
2724
2725 dapm_mark_dirty(wsource, "Route removed");
2726 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002727 if (path->connect)
2728 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002729
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002730 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002731
2732 /* Update any path related flags */
2733 dapm_update_widget_flags(wsource);
2734 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002735 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002736 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002737 source, sink);
2738 }
2739
2740 return 0;
2741}
2742
Mark Brown105f1c22008-05-13 14:52:19 +02002743/**
Mark Brown105f1c22008-05-13 14:52:19 +02002744 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002745 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002746 * @route: audio routes
2747 * @num: number of routes
2748 *
2749 * Connects 2 dapm widgets together via a named audio path. The sink is
2750 * the widget receiving the audio signal, whilst the source is the sender
2751 * of the audio signal.
2752 *
2753 * Returns 0 for success else error. On error all resources can be freed
2754 * with a call to snd_soc_card_free().
2755 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002756int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002757 const struct snd_soc_dapm_route *route, int num)
2758{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002759 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002760
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002761 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002762 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002763 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002764 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002765 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2766 route->source,
2767 route->control ? route->control : "direct",
2768 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002769 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002770 }
2771 route++;
2772 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002773 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002774
Dan Carpenter60884c22012-04-13 22:25:43 +03002775 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002776}
2777EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2778
Mark Brownefcc3c62012-07-05 17:24:19 +01002779/**
2780 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2781 * @dapm: DAPM context
2782 * @route: audio routes
2783 * @num: number of routes
2784 *
2785 * Removes routes from the DAPM context.
2786 */
2787int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2788 const struct snd_soc_dapm_route *route, int num)
2789{
2790 int i, ret = 0;
2791
2792 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2793 for (i = 0; i < num; i++) {
2794 snd_soc_dapm_del_route(dapm, route);
2795 route++;
2796 }
2797 mutex_unlock(&dapm->card->dapm_mutex);
2798
2799 return ret;
2800}
2801EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2802
Mark Brownbf3a9e12011-06-13 16:42:29 +01002803static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2804 const struct snd_soc_dapm_route *route)
2805{
2806 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2807 route->source,
2808 true);
2809 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2810 route->sink,
2811 true);
2812 struct snd_soc_dapm_path *path;
2813 int count = 0;
2814
2815 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002816 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002817 route->source);
2818 return -ENODEV;
2819 }
2820
2821 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002822 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002823 route->sink);
2824 return -ENODEV;
2825 }
2826
2827 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002828 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002829 route->source, route->sink);
2830
Lars-Peter Clausene63bfd42015-07-26 19:05:00 +02002831 snd_soc_dapm_widget_for_each_sink_path(source, path) {
Mark Brownbf3a9e12011-06-13 16:42:29 +01002832 if (path->sink == sink) {
2833 path->weak = 1;
2834 count++;
2835 }
2836 }
2837
2838 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002839 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002840 route->source, route->sink);
2841 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002842 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002843 count, route->source, route->sink);
2844
2845 return 0;
2846}
2847
2848/**
2849 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2850 * @dapm: DAPM context
2851 * @route: audio routes
2852 * @num: number of routes
2853 *
2854 * Mark existing routes matching those specified in the passed array
2855 * as being weak, meaning that they are ignored for the purpose of
2856 * power decisions. The main intended use case is for sidetone paths
2857 * which couple audio between other independent paths if they are both
2858 * active in order to make the combination work better at the user
2859 * level but which aren't intended to be "used".
2860 *
2861 * Note that CODEC drivers should not use this as sidetone type paths
2862 * can frequently also be used as bypass paths.
2863 */
2864int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2865 const struct snd_soc_dapm_route *route, int num)
2866{
2867 int i, err;
2868 int ret = 0;
2869
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002870 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002871 for (i = 0; i < num; i++) {
2872 err = snd_soc_dapm_weak_route(dapm, route);
2873 if (err)
2874 ret = err;
2875 route++;
2876 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002877 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002878
2879 return ret;
2880}
2881EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2882
Mark Brown105f1c22008-05-13 14:52:19 +02002883/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002884 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002885 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002886 *
2887 * Checks the codec for any new dapm widgets and creates them if found.
2888 *
2889 * Returns 0 for success.
2890 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02002891int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002892{
2893 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002894 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002895
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002896 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002897
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002898 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002899 {
2900 if (w->new)
2901 continue;
2902
Stephen Warrenfad59882011-04-28 17:37:59 -06002903 if (w->num_kcontrols) {
2904 w->kcontrols = kzalloc(w->num_kcontrols *
2905 sizeof(struct snd_kcontrol *),
2906 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002907 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002908 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002909 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002910 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002911 }
2912
Richard Purdie2b97eab2006-10-06 18:32:18 +02002913 switch(w->id) {
2914 case snd_soc_dapm_switch:
2915 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002916 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002917 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002918 break;
2919 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002920 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002921 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002922 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002923 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002924 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002925 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002926 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00002927 case snd_soc_dapm_dai_link:
2928 dapm_new_dai_link(w);
2929 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002930 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002931 break;
2932 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002933
2934 /* Read the initial power state from the device */
2935 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002936 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08002937 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002938 val &= w->mask;
2939 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00002940 w->power = 1;
2941 }
2942
Richard Purdie2b97eab2006-10-06 18:32:18 +02002943 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002944
Mark Brown7508b122011-10-05 12:09:12 +01002945 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002946 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002947 }
2948
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002949 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2950 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002951 return 0;
2952}
2953EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2954
2955/**
2956 * snd_soc_dapm_get_volsw - dapm mixer get callback
2957 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002958 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002959 *
2960 * Callback to get the value of a dapm mixer control.
2961 *
2962 * Returns 0 for success.
2963 */
2964int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2965 struct snd_ctl_elem_value *ucontrol)
2966{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002967 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2968 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002969 struct soc_mixer_control *mc =
2970 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002971 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002972 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002973 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002974 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002975 unsigned int invert = mc->invert;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002976 unsigned int val;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002977 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002978
2979 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002980 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002981 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002982 kcontrol->id.name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002983
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002984 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002985 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
2986 ret = soc_dapm_read(dapm, reg, &val);
2987 val = (val >> shift) & mask;
2988 } else {
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002989 val = dapm_kcontrol_get_value(kcontrol);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002990 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002991 mutex_unlock(&card->dapm_mutex);
2992
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002993 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002994 ucontrol->value.integer.value[0] = max - val;
2995 else
2996 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002997
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002998 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002999}
3000EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
3001
3002/**
3003 * snd_soc_dapm_put_volsw - dapm mixer set callback
3004 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003005 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003006 *
3007 * Callback to set the value of a dapm mixer control.
3008 *
3009 * Returns 0 for success.
3010 */
3011int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
3012 struct snd_ctl_elem_value *ucontrol)
3013{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003014 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3015 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003016 struct soc_mixer_control *mc =
3017 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003018 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003019 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01003020 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04003021 unsigned int mask = (1 << fls(max)) - 1;
3022 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07003023 unsigned int val;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003024 int connect, change, reg_change = 0;
Mark Brown97404f22010-12-14 16:13:57 +00003025 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003026 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003027
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003028 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003029 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003030 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003031 kcontrol->id.name);
3032
Richard Purdie2b97eab2006-10-06 18:32:18 +02003033 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003034 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003035
3036 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003037 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003038
Liam Girdwood3cd04342012-03-09 12:02:08 +00003039 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003040
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003041 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown283375c2009-12-07 18:09:03 +00003042
Jarkko Nikula18626c72014-06-09 14:20:29 +03003043 if (reg != SND_SOC_NOPM) {
3044 mask = mask << shift;
3045 val = val << shift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003046
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003047 reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003048 }
3049
3050 if (change || reg_change) {
3051 if (reg_change) {
3052 update.kcontrol = kcontrol;
3053 update.reg = reg;
3054 update.mask = mask;
3055 update.val = val;
3056 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003057 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003058 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003059
Nenghua Cao52765972013-12-13 20:13:49 +08003060 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Mark Brown97404f22010-12-14 16:13:57 +00003061
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003062 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003063 }
3064
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003065 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003066
3067 if (ret > 0)
3068 soc_dpcm_runtime_update(card);
3069
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003070 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003071}
3072EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3073
3074/**
3075 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3076 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003077 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003078 *
3079 * Callback to get the value of a dapm enumerated double mixer control.
3080 *
3081 * Returns 0 for success.
3082 */
3083int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3084 struct snd_ctl_elem_value *ucontrol)
3085{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003086 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003087 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003088 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003089 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003090
Charles Keepax561ed682015-05-01 12:37:26 +01003091 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3092 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003093 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003094 if (ret) {
3095 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003096 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003097 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003098 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003099 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003100 }
Charles Keepax561ed682015-05-01 12:37:26 +01003101 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003102
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003103 val = (reg_val >> e->shift_l) & e->mask;
3104 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3105 if (e->shift_l != e->shift_r) {
3106 val = (reg_val >> e->shift_r) & e->mask;
3107 val = snd_soc_enum_val_to_item(e, val);
3108 ucontrol->value.enumerated.item[1] = val;
3109 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003110
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003111 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003112}
3113EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3114
3115/**
3116 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3117 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003118 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003119 *
3120 * Callback to set the value of a dapm enumerated double mixer control.
3121 *
3122 * Returns 0 for success.
3123 */
3124int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3125 struct snd_ctl_elem_value *ucontrol)
3126{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003127 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3128 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003129 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003130 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003131 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003132 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00003133 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003134 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003135
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003136 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003137 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003138
3139 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003140 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003141 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003142 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003143 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003144 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003145 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003146 }
3147
Liam Girdwood3cd04342012-03-09 12:02:08 +00003148 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003149
Charles Keepax561ed682015-05-01 12:37:26 +01003150 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003151
Charles Keepax561ed682015-05-01 12:37:26 +01003152 if (e->reg != SND_SOC_NOPM)
3153 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3154
3155 if (change || reg_change) {
3156 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003157 update.kcontrol = kcontrol;
3158 update.reg = e->reg;
3159 update.mask = mask;
3160 update.val = val;
3161 card->update = &update;
3162 }
Charles Keepax561ed682015-05-01 12:37:26 +01003163 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003164
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003165 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003166
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003167 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003168 }
3169
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003170 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003171
3172 if (ret > 0)
3173 soc_dpcm_runtime_update(card);
3174
Mark Brown97404f22010-12-14 16:13:57 +00003175 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003176}
3177EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3178
3179/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003180 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3181 *
3182 * @kcontrol: mixer control
3183 * @uinfo: control element information
3184 *
3185 * Callback to provide information about a pin switch control.
3186 */
3187int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3188 struct snd_ctl_elem_info *uinfo)
3189{
3190 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3191 uinfo->count = 1;
3192 uinfo->value.integer.min = 0;
3193 uinfo->value.integer.max = 1;
3194
3195 return 0;
3196}
3197EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3198
3199/**
3200 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3201 *
3202 * @kcontrol: mixer control
3203 * @ucontrol: Value
3204 */
3205int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3206 struct snd_ctl_elem_value *ucontrol)
3207{
Mark Brown48a8c392012-02-14 17:11:15 -08003208 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003209 const char *pin = (const char *)kcontrol->private_value;
3210
Liam Girdwood3cd04342012-03-09 12:02:08 +00003211 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003212
3213 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003214 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003215
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003216 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003217
3218 return 0;
3219}
3220EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3221
3222/**
3223 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3224 *
3225 * @kcontrol: mixer control
3226 * @ucontrol: Value
3227 */
3228int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3229 struct snd_ctl_elem_value *ucontrol)
3230{
Mark Brown48a8c392012-02-14 17:11:15 -08003231 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003232 const char *pin = (const char *)kcontrol->private_value;
3233
Mark Brown8b37dbd2009-02-28 21:14:20 +00003234 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003235 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003236 else
Mark Brown48a8c392012-02-14 17:11:15 -08003237 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003238
Mark Brown48a8c392012-02-14 17:11:15 -08003239 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003240 return 0;
3241}
3242EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3243
Liam Girdwoodcc76e7d2015-06-04 15:13:09 +01003244struct snd_soc_dapm_widget *
Mark Brown5ba06fc2012-02-16 11:07:13 -08003245snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003246 const struct snd_soc_dapm_widget *widget)
3247{
3248 struct snd_soc_dapm_widget *w;
3249
3250 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3251 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
3252 if (!w)
3253 dev_err(dapm->dev,
3254 "ASoC: Failed to create DAPM control %s\n",
3255 widget->name);
3256
3257 mutex_unlock(&dapm->card->dapm_mutex);
3258 return w;
3259}
3260
3261struct snd_soc_dapm_widget *
3262snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003263 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003264{
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003265 enum snd_soc_dapm_direction dir;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003266 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003267 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003268 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003269
3270 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003271 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003272
Mark Brown62ea8742012-01-21 21:14:48 +00003273 switch (w->id) {
3274 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003275 w->regulator = devm_regulator_get(dapm->dev, w->name);
3276 if (IS_ERR(w->regulator)) {
3277 ret = PTR_ERR(w->regulator);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003278 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003279 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003280 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003281 }
Mark Brown8784c772013-01-10 19:33:47 +00003282
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003283 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003284 ret = regulator_allow_bypass(w->regulator, true);
3285 if (ret != 0)
3286 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003287 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003288 w->name, ret);
3289 }
Mark Brown62ea8742012-01-21 21:14:48 +00003290 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003291 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003292#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003293 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003294 if (IS_ERR(w->clk)) {
3295 ret = PTR_ERR(w->clk);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003296 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003297 w->name, ret);
3298 return NULL;
3299 }
Mark Brownec029952012-06-04 08:16:20 +01003300#else
3301 return NULL;
3302#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003303 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003304 default:
3305 break;
3306 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003307
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003308 prefix = soc_dapm_prefix(dapm);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003309 if (prefix)
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003310 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003311 else
Lars-Peter Clausen48068962015-07-21 18:11:08 +02003312 w->name = kstrdup_const(widget->name, GFP_KERNEL);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003313 if (w->name == NULL) {
3314 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003315 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003316 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003317
Mark Brown7ca3a182011-10-08 14:04:50 +01003318 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003319 case snd_soc_dapm_mic:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003320 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003321 w->power_check = dapm_generic_check_power;
3322 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003323 case snd_soc_dapm_input:
3324 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003325 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003326 w->power_check = dapm_generic_check_power;
3327 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003328 case snd_soc_dapm_spk:
3329 case snd_soc_dapm_hp:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003330 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003331 w->power_check = dapm_generic_check_power;
3332 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003333 case snd_soc_dapm_output:
3334 if (!dapm->card->fully_routed)
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003335 w->is_ep = SND_SOC_DAPM_EP_SINK;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003336 w->power_check = dapm_generic_check_power;
3337 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003338 case snd_soc_dapm_vmid:
3339 case snd_soc_dapm_siggen:
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003340 w->is_ep = SND_SOC_DAPM_EP_SOURCE;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003341 w->power_check = dapm_always_on_check_power;
3342 break;
3343 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003344 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003345 case snd_soc_dapm_switch:
3346 case snd_soc_dapm_mixer:
3347 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003348 case snd_soc_dapm_adc:
3349 case snd_soc_dapm_aif_out:
3350 case snd_soc_dapm_dac:
3351 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003352 case snd_soc_dapm_pga:
3353 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003354 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003355 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003356 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003357 case snd_soc_dapm_dai_out:
3358 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003359 w->power_check = dapm_generic_check_power;
3360 break;
3361 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003362 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003363 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003364 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003365 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003366 w->power_check = dapm_supply_check_power;
3367 break;
3368 default:
3369 w->power_check = dapm_always_on_check_power;
3370 break;
3371 }
3372
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003373 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003374 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003375 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003376 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003377
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003378 snd_soc_dapm_for_each_direction(dir) {
3379 INIT_LIST_HEAD(&w->edges[dir]);
3380 w->endpoints[dir] = -1;
3381 }
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003382
Richard Purdie2b97eab2006-10-06 18:32:18 +02003383 /* machine layer set ups unconnected pins and insertions */
3384 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003385 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003386}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003387
3388/**
Mark Brown4ba13272008-05-13 14:51:19 +02003389 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003390 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003391 * @widget: widget array
3392 * @num: number of widgets
3393 *
3394 * Creates new DAPM controls based upon the templates.
3395 *
3396 * Returns 0 for success else error.
3397 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003398int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003399 const struct snd_soc_dapm_widget *widget,
3400 int num)
3401{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003402 struct snd_soc_dapm_widget *w;
3403 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003404 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003405
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003406 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003407 for (i = 0; i < num; i++) {
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003408 w = snd_soc_dapm_new_control_unlocked(dapm, widget);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003409 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003410 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003411 "ASoC: Failed to create DAPM control %s\n",
3412 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003413 ret = -ENOMEM;
3414 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003415 }
Mark Brown4ba13272008-05-13 14:51:19 +02003416 widget++;
3417 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003418 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003419 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003420}
3421EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3422
Mark Brownc74184e2012-04-04 22:12:09 +01003423static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3424 struct snd_kcontrol *kcontrol, int event)
3425{
3426 struct snd_soc_dapm_path *source_p, *sink_p;
3427 struct snd_soc_dai *source, *sink;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003428 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003429 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003430 struct snd_pcm_hw_params *params = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003431 u64 fmt;
3432 int ret;
3433
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003434 if (WARN_ON(!config) ||
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003435 WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3436 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003437 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003438
3439 /* We only support a single source and sink, pick the first */
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003440 source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
3441 struct snd_soc_dapm_path,
3442 list_node[SND_SOC_DAPM_DIR_OUT]);
3443 sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
3444 struct snd_soc_dapm_path,
3445 list_node[SND_SOC_DAPM_DIR_IN]);
Mark Brownc74184e2012-04-04 22:12:09 +01003446
Mark Brownc74184e2012-04-04 22:12:09 +01003447 source = source_p->source->priv;
3448 sink = sink_p->sink->priv;
3449
3450 /* Be a little careful as we don't want to overflow the mask array */
3451 if (config->formats) {
3452 fmt = ffs(config->formats) - 1;
3453 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003454 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003455 config->formats);
3456 fmt = 0;
3457 }
3458
3459 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003460 params = kzalloc(sizeof(*params), GFP_KERNEL);
3461 if (!params) {
3462 ret = -ENOMEM;
3463 goto out;
3464 }
3465 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003466
Mark Brown9747cec2012-04-26 19:12:21 +01003467 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003468 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003469 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003470 config->rate_max;
3471
Mark Brown9747cec2012-04-26 19:12:21 +01003472 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003473 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003474 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003475 = config->channels_max;
3476
3477 memset(&substream, 0, sizeof(substream));
3478
3479 switch (event) {
3480 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003481 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3482 ret = soc_dai_hw_params(&substream, params, source);
3483 if (ret < 0)
3484 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003485
Benoit Cousson93e69582014-07-08 23:19:38 +02003486 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3487 ret = soc_dai_hw_params(&substream, params, sink);
3488 if (ret < 0)
3489 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003490 break;
3491
3492 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003493 ret = snd_soc_dai_digital_mute(sink, 0,
3494 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003495 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003496 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003497 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003498 break;
3499
3500 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003501 ret = snd_soc_dai_digital_mute(sink, 1,
3502 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003503 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003504 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003505 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003506 break;
3507
3508 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003509 WARN(1, "Unknown event %d\n", event);
Mark Brownc74184e2012-04-04 22:12:09 +01003510 return -EINVAL;
3511 }
3512
Mark Brown9747cec2012-04-26 19:12:21 +01003513out:
3514 kfree(params);
3515 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003516}
3517
Nikesh Oswalc6615082015-02-02 17:06:44 +00003518static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3519 struct snd_ctl_elem_value *ucontrol)
3520{
3521 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3522
3523 ucontrol->value.integer.value[0] = w->params_select;
3524
3525 return 0;
3526}
3527
3528static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3529 struct snd_ctl_elem_value *ucontrol)
3530{
3531 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3532
3533 /* Can't change the config when widget is already powered */
3534 if (w->power)
3535 return -EBUSY;
3536
3537 if (ucontrol->value.integer.value[0] == w->params_select)
3538 return 0;
3539
3540 if (ucontrol->value.integer.value[0] >= w->num_params)
3541 return -EINVAL;
3542
3543 w->params_select = ucontrol->value.integer.value[0];
3544
3545 return 0;
3546}
3547
Mark Brownc74184e2012-04-04 22:12:09 +01003548int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3549 const struct snd_soc_pcm_stream *params,
Nikesh Oswalc6615082015-02-02 17:06:44 +00003550 unsigned int num_params,
Mark Brownc74184e2012-04-04 22:12:09 +01003551 struct snd_soc_dapm_widget *source,
3552 struct snd_soc_dapm_widget *sink)
3553{
Mark Brownc74184e2012-04-04 22:12:09 +01003554 struct snd_soc_dapm_widget template;
3555 struct snd_soc_dapm_widget *w;
Mark Brownc74184e2012-04-04 22:12:09 +01003556 char *link_name;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003557 int ret, count;
3558 unsigned long private_value;
3559 const char **w_param_text;
3560 struct soc_enum w_param_enum[] = {
3561 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3562 };
3563 struct snd_kcontrol_new kcontrol_dai_link[] = {
3564 SOC_ENUM_EXT(NULL, w_param_enum[0],
3565 snd_soc_dapm_dai_link_get,
3566 snd_soc_dapm_dai_link_put),
3567 };
3568 const struct snd_soc_pcm_stream *config = params;
Mark Brownc74184e2012-04-04 22:12:09 +01003569
Nikesh Oswalc6615082015-02-02 17:06:44 +00003570 w_param_text = devm_kcalloc(card->dev, num_params,
3571 sizeof(char *), GFP_KERNEL);
3572 if (!w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003573 return -ENOMEM;
Mark Brownc74184e2012-04-04 22:12:09 +01003574
Charles Keepax46172b62015-03-25 11:22:35 +00003575 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3576 source->name, sink->name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003577 if (!link_name) {
3578 ret = -ENOMEM;
3579 goto outfree_w_param;
3580 }
Mark Brownc74184e2012-04-04 22:12:09 +01003581
Nikesh Oswalc6615082015-02-02 17:06:44 +00003582 for (count = 0 ; count < num_params; count++) {
3583 if (!config->stream_name) {
3584 dev_warn(card->dapm.dev,
3585 "ASoC: anonymous config %d for dai link %s\n",
3586 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003587 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003588 devm_kasprintf(card->dev, GFP_KERNEL,
3589 "Anonymous Configuration %d",
3590 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003591 if (!w_param_text[count]) {
3592 ret = -ENOMEM;
3593 goto outfree_link_name;
3594 }
Nikesh Oswalc6615082015-02-02 17:06:44 +00003595 } else {
3596 w_param_text[count] = devm_kmemdup(card->dev,
3597 config->stream_name,
3598 strlen(config->stream_name) + 1,
3599 GFP_KERNEL);
3600 if (!w_param_text[count]) {
3601 ret = -ENOMEM;
3602 goto outfree_link_name;
3603 }
3604 }
3605 config++;
3606 }
3607 w_param_enum[0].items = num_params;
3608 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003609
3610 memset(&template, 0, sizeof(template));
3611 template.reg = SND_SOC_NOPM;
3612 template.id = snd_soc_dapm_dai_link;
3613 template.name = link_name;
3614 template.event = snd_soc_dai_link_event;
3615 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3616 SND_SOC_DAPM_PRE_PMD;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003617 template.num_kcontrols = 1;
3618 /* duplicate w_param_enum on heap so that memory persists */
3619 private_value =
3620 (unsigned long) devm_kmemdup(card->dev,
3621 (void *)(kcontrol_dai_link[0].private_value),
3622 sizeof(struct soc_enum), GFP_KERNEL);
3623 if (!private_value) {
3624 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3625 link_name);
3626 ret = -ENOMEM;
3627 goto outfree_link_name;
3628 }
3629 kcontrol_dai_link[0].private_value = private_value;
3630 /* duplicate kcontrol_dai_link on heap so that memory persists */
3631 template.kcontrol_news =
3632 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3633 sizeof(struct snd_kcontrol_new),
3634 GFP_KERNEL);
3635 if (!template.kcontrol_news) {
3636 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3637 link_name);
3638 ret = -ENOMEM;
3639 goto outfree_private_value;
3640 }
Mark Brownc74184e2012-04-04 22:12:09 +01003641
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003642 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003643
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003644 w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
Mark Brownc74184e2012-04-04 22:12:09 +01003645 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003646 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003647 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003648 ret = -ENOMEM;
3649 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003650 }
3651
3652 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003653 w->num_params = num_params;
Mark Brownc74184e2012-04-04 22:12:09 +01003654
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003655 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3656 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003657 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003658 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003659
3660outfree_w:
3661 devm_kfree(card->dev, w);
3662outfree_kcontrol_news:
3663 devm_kfree(card->dev, (void *)template.kcontrol_news);
3664outfree_private_value:
3665 devm_kfree(card->dev, (void *)private_value);
3666outfree_link_name:
3667 devm_kfree(card->dev, link_name);
3668outfree_w_param:
3669 for (count = 0 ; count < num_params; count++)
3670 devm_kfree(card->dev, (void *)w_param_text[count]);
3671 devm_kfree(card->dev, w_param_text);
3672
3673 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003674}
3675
Mark Brown888df392012-02-16 19:37:51 -08003676int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3677 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003678{
Mark Brown888df392012-02-16 19:37:51 -08003679 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003680 struct snd_soc_dapm_widget *w;
3681
Mark Brown888df392012-02-16 19:37:51 -08003682 WARN_ON(dapm->dev != dai->dev);
3683
3684 memset(&template, 0, sizeof(template));
3685 template.reg = SND_SOC_NOPM;
3686
3687 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003688 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003689 template.name = dai->driver->playback.stream_name;
3690 template.sname = dai->driver->playback.stream_name;
3691
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003692 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003693 template.name);
3694
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003695 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Mark Brown888df392012-02-16 19:37:51 -08003696 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003697 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003698 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003699 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003700 }
3701
3702 w->priv = dai;
3703 dai->playback_widget = w;
3704 }
3705
3706 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003707 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003708 template.name = dai->driver->capture.stream_name;
3709 template.sname = dai->driver->capture.stream_name;
3710
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003711 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003712 template.name);
3713
Liam Girdwood02aa78a2015-05-25 18:21:17 +01003714 w = snd_soc_dapm_new_control_unlocked(dapm, &template);
Mark Brown888df392012-02-16 19:37:51 -08003715 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003716 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003717 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003718 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003719 }
3720
3721 w->priv = dai;
3722 dai->capture_widget = w;
3723 }
3724
3725 return 0;
3726}
3727
3728int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3729{
3730 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003731 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08003732 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003733
3734 /* For each DAI widget... */
3735 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003736 switch (dai_w->id) {
3737 case snd_soc_dapm_dai_in:
3738 case snd_soc_dapm_dai_out:
3739 break;
3740 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003741 continue;
Mark Brown46162742013-06-05 19:36:11 +01003742 }
Mark Brown888df392012-02-16 19:37:51 -08003743
3744 dai = dai_w->priv;
3745
3746 /* ...find all widgets with the same stream and link them */
3747 list_for_each_entry(w, &card->widgets, list) {
3748 if (w->dapm != dai_w->dapm)
3749 continue;
3750
Mark Brown46162742013-06-05 19:36:11 +01003751 switch (w->id) {
3752 case snd_soc_dapm_dai_in:
3753 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08003754 continue;
Mark Brown46162742013-06-05 19:36:11 +01003755 default:
3756 break;
3757 }
Mark Brown888df392012-02-16 19:37:51 -08003758
Lars-Peter Clausena798c242015-07-21 11:51:35 +02003759 if (!w->sname || !strstr(w->sname, dai_w->sname))
Mark Brown888df392012-02-16 19:37:51 -08003760 continue;
3761
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003762 if (dai_w->id == snd_soc_dapm_dai_in) {
3763 src = dai_w;
3764 sink = w;
3765 } else {
3766 src = w;
3767 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08003768 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003769 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
3770 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003771 }
3772 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003773
Mark Brown888df392012-02-16 19:37:51 -08003774 return 0;
3775}
Liam Girdwood64a648c2011-07-25 11:15:15 +01003776
Benoit Cousson44ba2642014-07-08 23:19:36 +02003777static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
3778 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003779{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003780 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003781 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003782 int i;
3783
Benoit Cousson44ba2642014-07-08 23:19:36 +02003784 for (i = 0; i < rtd->num_codecs; i++) {
3785 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003786
3787 /* there is no point in connecting BE DAI links with dummies */
3788 if (snd_soc_dai_is_dummy(codec_dai) ||
3789 snd_soc_dai_is_dummy(cpu_dai))
3790 continue;
3791
3792 /* connect BE DAI playback if widgets are valid */
3793 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003794 source = cpu_dai->playback_widget;
3795 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003796 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003797 cpu_dai->component->name, source->name,
3798 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003799
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003800 snd_soc_dapm_add_path(&card->dapm, source, sink,
3801 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003802 }
3803
3804 /* connect BE DAI capture if widgets are valid */
3805 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003806 source = codec_dai->capture_widget;
3807 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003808 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003809 codec_dai->component->name, source->name,
3810 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003811
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003812 snd_soc_dapm_add_path(&card->dapm, source, sink,
3813 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003814 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003815 }
3816}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003817
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003818static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3819 int event)
3820{
3821 struct snd_soc_dapm_widget *w;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003822 unsigned int ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003823
3824 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3825 w = dai->playback_widget;
3826 else
3827 w = dai->capture_widget;
3828
3829 if (w) {
3830 dapm_mark_dirty(w, "stream event");
3831
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003832 if (w->id == snd_soc_dapm_dai_in) {
3833 ep = SND_SOC_DAPM_EP_SOURCE;
3834 dapm_widget_invalidate_input_paths(w);
3835 } else {
3836 ep = SND_SOC_DAPM_EP_SINK;
3837 dapm_widget_invalidate_output_paths(w);
3838 }
3839
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003840 switch (event) {
3841 case SND_SOC_DAPM_STREAM_START:
3842 w->active = 1;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003843 w->is_ep = ep;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003844 break;
3845 case SND_SOC_DAPM_STREAM_STOP:
3846 w->active = 0;
Lars-Peter Clausena3423b02015-08-11 21:38:00 +02003847 w->is_ep = 0;
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003848 break;
3849 case SND_SOC_DAPM_STREAM_SUSPEND:
3850 case SND_SOC_DAPM_STREAM_RESUME:
3851 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3852 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3853 break;
3854 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003855 }
3856}
3857
Benoit Cousson44ba2642014-07-08 23:19:36 +02003858void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3859{
3860 struct snd_soc_pcm_runtime *rtd = card->rtd;
3861 int i;
3862
3863 /* for each BE DAI link... */
3864 for (i = 0; i < card->num_rtd; i++) {
3865 rtd = &card->rtd[i];
3866
3867 /*
3868 * dynamic FE links have no fixed DAI mapping.
3869 * CODEC<->CODEC links have no direct connection.
3870 */
3871 if (rtd->dai_link->dynamic || rtd->dai_link->params)
3872 continue;
3873
3874 dapm_connect_dai_link_widgets(card, rtd);
3875 }
3876}
3877
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003878static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3879 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003880{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003881 int i;
3882
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003883 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02003884 for (i = 0; i < rtd->num_codecs; i++)
3885 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003886
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003887 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003888}
3889
3890/**
3891 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3892 * @rtd: PCM runtime data
3893 * @stream: stream name
3894 * @event: stream event
3895 *
3896 * Sends a stream event to the dapm core. The core then makes any
3897 * necessary widget power changes.
3898 *
3899 * Returns 0 for success else error.
3900 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003901void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3902 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003903{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003904 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003905
Liam Girdwood3cd04342012-03-09 12:02:08 +00003906 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003907 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003908 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003909}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003910
3911/**
Charles Keepax11391102014-02-18 15:22:14 +00003912 * snd_soc_dapm_enable_pin_unlocked - enable pin.
3913 * @dapm: DAPM context
3914 * @pin: pin name
3915 *
3916 * Enables input/output pin and its parents or children widgets iff there is
3917 * a valid audio route and active audio stream.
3918 *
3919 * Requires external locking.
3920 *
3921 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3922 * do any widget power switching.
3923 */
3924int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3925 const char *pin)
3926{
3927 return snd_soc_dapm_set_pin(dapm, pin, 1);
3928}
3929EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
3930
3931/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003932 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003933 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003934 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02003935 *
Mark Brown74b8f952009-06-06 11:26:15 +01003936 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01003937 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00003938 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003939 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3940 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02003941 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003942int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003943{
Charles Keepax11391102014-02-18 15:22:14 +00003944 int ret;
3945
3946 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3947
3948 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
3949
3950 mutex_unlock(&dapm->card->dapm_mutex);
3951
3952 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003953}
Liam Girdwooda5302182008-07-07 13:35:17 +01003954EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003955
3956/**
Charles Keepax11391102014-02-18 15:22:14 +00003957 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
3958 * @dapm: DAPM context
3959 * @pin: pin name
3960 *
3961 * Enables input/output pin regardless of any other state. This is
3962 * intended for use with microphone bias supplies used in microphone
3963 * jack detection.
3964 *
3965 * Requires external locking.
3966 *
3967 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3968 * do any widget power switching.
3969 */
3970int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3971 const char *pin)
3972{
3973 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
3974
3975 if (!w) {
3976 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
3977 return -EINVAL;
3978 }
3979
3980 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003981 if (!w->connected) {
3982 /*
3983 * w->force does not affect the number of input or output paths,
3984 * so we only have to recheck if w->connected is changed
3985 */
3986 dapm_widget_invalidate_input_paths(w);
3987 dapm_widget_invalidate_output_paths(w);
3988 w->connected = 1;
3989 }
Charles Keepax11391102014-02-18 15:22:14 +00003990 w->force = 1;
3991 dapm_mark_dirty(w, "force enable");
3992
3993 return 0;
3994}
3995EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
3996
3997/**
Mark Brownda341832010-03-15 19:23:37 +00003998 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003999 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00004000 * @pin: pin name
4001 *
4002 * Enables input/output pin regardless of any other state. This is
4003 * intended for use with microphone bias supplies used in microphone
4004 * jack detection.
4005 *
4006 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4007 * do any widget power switching.
4008 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004009int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
4010 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00004011{
Charles Keepax11391102014-02-18 15:22:14 +00004012 int ret;
Mark Brownda341832010-03-15 19:23:37 +00004013
Charles Keepax11391102014-02-18 15:22:14 +00004014 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00004015
Charles Keepax11391102014-02-18 15:22:14 +00004016 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09004017
Charles Keepax11391102014-02-18 15:22:14 +00004018 mutex_unlock(&dapm->card->dapm_mutex);
4019
4020 return ret;
Mark Brownda341832010-03-15 19:23:37 +00004021}
4022EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
4023
4024/**
Charles Keepax11391102014-02-18 15:22:14 +00004025 * snd_soc_dapm_disable_pin_unlocked - disable pin.
4026 * @dapm: DAPM context
4027 * @pin: pin name
4028 *
4029 * Disables input/output pin and its parents or children widgets.
4030 *
4031 * Requires external locking.
4032 *
4033 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4034 * do any widget power switching.
4035 */
4036int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
4037 const char *pin)
4038{
4039 return snd_soc_dapm_set_pin(dapm, pin, 0);
4040}
4041EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4042
4043/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004044 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004045 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004046 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004047 *
Mark Brown74b8f952009-06-06 11:26:15 +01004048 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004049 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004050 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4051 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004052 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004053int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4054 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004055{
Charles Keepax11391102014-02-18 15:22:14 +00004056 int ret;
4057
4058 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4059
4060 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4061
4062 mutex_unlock(&dapm->card->dapm_mutex);
4063
4064 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004065}
4066EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4067
4068/**
Charles Keepax11391102014-02-18 15:22:14 +00004069 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4070 * @dapm: DAPM context
4071 * @pin: pin name
4072 *
4073 * Marks the specified pin as being not connected, disabling it along
4074 * any parent or child widgets. At present this is identical to
4075 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4076 * additional things such as disabling controls which only affect
4077 * paths through the pin.
4078 *
4079 * Requires external locking.
4080 *
4081 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4082 * do any widget power switching.
4083 */
4084int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4085 const char *pin)
4086{
4087 return snd_soc_dapm_set_pin(dapm, pin, 0);
4088}
4089EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4090
4091/**
Mark Brown5817b522008-09-24 11:23:11 +01004092 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004093 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004094 * @pin: pin name
4095 *
4096 * Marks the specified pin as being not connected, disabling it along
4097 * any parent or child widgets. At present this is identical to
4098 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4099 * additional things such as disabling controls which only affect
4100 * paths through the pin.
4101 *
4102 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4103 * do any widget power switching.
4104 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004105int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004106{
Charles Keepax11391102014-02-18 15:22:14 +00004107 int ret;
4108
4109 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4110
4111 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4112
4113 mutex_unlock(&dapm->card->dapm_mutex);
4114
4115 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004116}
4117EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4118
4119/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004120 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004121 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004122 * @pin: audio signal pin endpoint (or start point)
4123 *
4124 * Get audio pin status - connected or disconnected.
4125 *
4126 * Returns 1 for connected otherwise 0.
4127 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004128int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4129 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004130{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004131 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004132
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004133 if (w)
4134 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004135
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004136 return 0;
4137}
Liam Girdwooda5302182008-07-07 13:35:17 +01004138EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004139
4140/**
Mark Brown1547aba2010-05-07 21:11:40 +01004141 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004142 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004143 * @pin: audio signal pin endpoint (or start point)
4144 *
4145 * Mark the given endpoint or pin as ignoring suspend. When the
4146 * system is disabled a path between two endpoints flagged as ignoring
4147 * suspend will not be disabled. The path must already be enabled via
4148 * normal means at suspend time, it will not be turned on if it was not
4149 * already enabled.
4150 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004151int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4152 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004153{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004154 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004155
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004156 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004157 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004158 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004159 }
4160
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004161 w->ignore_suspend = 1;
4162
4163 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004164}
4165EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4166
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004167/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004168 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004169 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004170 *
4171 * Free all dapm widgets and resources.
4172 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004173void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004174{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004175 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004176 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004177 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004178}
4179EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4180
Xiang Xiao57996352014-03-02 00:04:02 +08004181static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004182{
Liam Girdwood01005a72012-07-06 16:57:05 +01004183 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004184 struct snd_soc_dapm_widget *w;
4185 LIST_HEAD(down_list);
4186 int powerdown = 0;
4187
Liam Girdwood01005a72012-07-06 16:57:05 +01004188 mutex_lock(&card->dapm_mutex);
4189
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004190 list_for_each_entry(w, &dapm->card->widgets, list) {
4191 if (w->dapm != dapm)
4192 continue;
Mark Brown51737472009-06-22 13:16:51 +01004193 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004194 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004195 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004196 powerdown = 1;
4197 }
4198 }
4199
4200 /* If there were no widgets to power down we're already in
4201 * standby.
4202 */
4203 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004204 if (dapm->bias_level == SND_SOC_BIAS_ON)
4205 snd_soc_dapm_set_bias_level(dapm,
4206 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004207 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004208 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4209 snd_soc_dapm_set_bias_level(dapm,
4210 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004211 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004212
4213 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004214}
Mark Brown51737472009-06-22 13:16:51 +01004215
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004216/*
4217 * snd_soc_dapm_shutdown - callback for system shutdown
4218 */
4219void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4220{
Xiang Xiao57996352014-03-02 00:04:02 +08004221 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004222
Xiang Xiao57996352014-03-02 00:04:02 +08004223 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004224 if (dapm != &card->dapm) {
4225 soc_dapm_shutdown_dapm(dapm);
4226 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4227 snd_soc_dapm_set_bias_level(dapm,
4228 SND_SOC_BIAS_OFF);
4229 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004230 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004231
4232 soc_dapm_shutdown_dapm(&card->dapm);
4233 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4234 snd_soc_dapm_set_bias_level(&card->dapm,
4235 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004236}
4237
Richard Purdie2b97eab2006-10-06 18:32:18 +02004238/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004239MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004240MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4241MODULE_LICENSE("GPL");