blob: 765416174388edfcd64cac5f599c005faa6c3aa1 [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 Clausen57295072013-08-05 11:27:31 +020050static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
51 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
52 const char *control,
53 int (*connected)(struct snd_soc_dapm_widget *source,
54 struct snd_soc_dapm_widget *sink));
55static struct snd_soc_dapm_widget *
56snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
57 const struct snd_soc_dapm_widget *widget);
58
Richard Purdie2b97eab2006-10-06 18:32:18 +020059/* dapm power sequences - make this per codec in the future */
60static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010061 [snd_soc_dapm_pre] = 0,
Mark Brown62ea8742012-01-21 21:14:48 +000062 [snd_soc_dapm_regulator_supply] = 1,
Ola Liljad7e7eb92012-05-24 15:26:25 +020063 [snd_soc_dapm_clock_supply] = 1,
Mark Brown1dd275b2013-10-09 13:56:37 +010064 [snd_soc_dapm_supply] = 2,
65 [snd_soc_dapm_micbias] = 3,
Mark Brownc74184e2012-04-04 22:12:09 +010066 [snd_soc_dapm_dai_link] = 2,
Mark Brown1dd275b2013-10-09 13:56:37 +010067 [snd_soc_dapm_dai_in] = 4,
68 [snd_soc_dapm_dai_out] = 4,
69 [snd_soc_dapm_aif_in] = 4,
70 [snd_soc_dapm_aif_out] = 4,
71 [snd_soc_dapm_mic] = 5,
72 [snd_soc_dapm_mux] = 6,
Lars-Peter Clausend714f972015-05-01 18:02:43 +020073 [snd_soc_dapm_demux] = 6,
Mark Brown1dd275b2013-10-09 13:56:37 +010074 [snd_soc_dapm_dac] = 7,
75 [snd_soc_dapm_switch] = 8,
76 [snd_soc_dapm_mixer] = 8,
77 [snd_soc_dapm_mixer_named_ctl] = 8,
78 [snd_soc_dapm_pga] = 9,
79 [snd_soc_dapm_adc] = 10,
80 [snd_soc_dapm_out_drv] = 11,
81 [snd_soc_dapm_hp] = 11,
82 [snd_soc_dapm_spk] = 11,
83 [snd_soc_dapm_line] = 11,
84 [snd_soc_dapm_kcontrol] = 12,
85 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020086};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000087
Richard Purdie2b97eab2006-10-06 18:32:18 +020088static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010089 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +020090 [snd_soc_dapm_kcontrol] = 1,
91 [snd_soc_dapm_adc] = 2,
92 [snd_soc_dapm_hp] = 3,
93 [snd_soc_dapm_spk] = 3,
94 [snd_soc_dapm_line] = 3,
95 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +010096 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +020097 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +010098 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +010099 [snd_soc_dapm_mixer] = 5,
100 [snd_soc_dapm_dac] = 6,
101 [snd_soc_dapm_mic] = 7,
102 [snd_soc_dapm_micbias] = 8,
103 [snd_soc_dapm_mux] = 9,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200104 [snd_soc_dapm_demux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100105 [snd_soc_dapm_aif_in] = 10,
106 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100107 [snd_soc_dapm_dai_in] = 10,
108 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100109 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100110 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100111 [snd_soc_dapm_clock_supply] = 13,
112 [snd_soc_dapm_regulator_supply] = 13,
113 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200114};
115
Mark Brownf9fa2b12014-03-06 16:49:11 +0800116static void dapm_assert_locked(struct snd_soc_dapm_context *dapm)
117{
118 if (dapm->card && dapm->card->instantiated)
119 lockdep_assert_held(&dapm->card->dapm_mutex);
120}
121
Troy Kisky12ef1932008-10-13 17:42:14 -0700122static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100123{
124 if (pop_time)
125 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
126}
127
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200128static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100129{
130 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200131 char *buf;
132
133 if (!pop_time)
134 return;
135
136 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
137 if (buf == NULL)
138 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100139
140 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200141 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100142 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100143 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200144
145 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100146}
147
Mark Browndb432b42011-10-03 21:06:40 +0100148static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
149{
150 return !list_empty(&w->dirty);
151}
152
Mark Brown492c0a12014-03-06 16:15:48 +0800153static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100154{
Mark Brownf9fa2b12014-03-06 16:49:11 +0800155 dapm_assert_locked(w->dapm);
156
Mark Brown75c1f892011-10-04 22:28:08 +0100157 if (!dapm_dirty_widget(w)) {
158 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
159 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100160 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100161 }
Mark Browndb432b42011-10-03 21:06:40 +0100162}
163
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200164/*
165 * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
166 * paths
167 * @w: The widget for which to invalidate the cached number of input paths
168 *
169 * The function resets the cached number of inputs for the specified widget and
170 * all widgets that can be reached via outgoing paths from the widget.
171 *
172 * This function must be called if the number of input paths for a widget might
173 * have changed. E.g. if the source state of a widget changes or a path is added
174 * or activated with the widget as the sink.
175 */
176static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
177{
178 struct snd_soc_dapm_widget *sink;
179 struct snd_soc_dapm_path *p;
180 LIST_HEAD(list);
181
182 dapm_assert_locked(w->dapm);
183
184 if (w->inputs == -1)
185 return;
186
187 w->inputs = -1;
188 list_add_tail(&w->work_list, &list);
189
190 list_for_each_entry(w, &list, work_list) {
191 list_for_each_entry(p, &w->sinks, list_source) {
192 if (p->is_supply || p->weak || !p->connect)
193 continue;
194 sink = p->sink;
195 if (sink->inputs != -1) {
196 sink->inputs = -1;
197 list_add_tail(&sink->work_list, &list);
198 }
199 }
200 }
201}
202
203/*
204 * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
205 * output paths
206 * @w: The widget for which to invalidate the cached number of output paths
207 *
208 * Resets the cached number of outputs for the specified widget and all widgets
209 * that can be reached via incoming paths from the widget.
210 *
211 * This function must be called if the number of output paths for a widget might
212 * have changed. E.g. if the sink state of a widget changes or a path is added
213 * or activated with the widget as the source.
214 */
215static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
216{
217 struct snd_soc_dapm_widget *source;
218 struct snd_soc_dapm_path *p;
219 LIST_HEAD(list);
220
221 dapm_assert_locked(w->dapm);
222
223 if (w->outputs == -1)
224 return;
225
226 w->outputs = -1;
227 list_add_tail(&w->work_list, &list);
228
229 list_for_each_entry(w, &list, work_list) {
230 list_for_each_entry(p, &w->sources, list_sink) {
231 if (p->is_supply || p->weak || !p->connect)
232 continue;
233 source = p->source;
234 if (source->outputs != -1) {
235 source->outputs = -1;
236 list_add_tail(&source->work_list, &list);
237 }
238 }
239 }
240}
241
242/*
243 * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
244 * for the widgets connected to a path
245 * @p: The path to invalidate
246 *
247 * Resets the cached number of inputs for the sink of the path and the cached
248 * number of outputs for the source of the path.
249 *
250 * This function must be called when a path is added, removed or the connected
251 * state changes.
252 */
253static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
254{
255 /*
256 * Weak paths or supply paths do not influence the number of input or
257 * output paths of their neighbors.
258 */
259 if (p->weak || p->is_supply)
260 return;
261
262 /*
263 * The number of connected endpoints is the sum of the number of
264 * connected endpoints of all neighbors. If a node with 0 connected
265 * endpoints is either connected or disconnected that sum won't change,
266 * so there is no need to re-check the path.
267 */
268 if (p->source->inputs != 0)
269 dapm_widget_invalidate_input_paths(p->sink);
270 if (p->sink->outputs != 0)
271 dapm_widget_invalidate_output_paths(p->source);
272}
273
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200274void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
Mark Browne2d32ff2012-08-31 17:38:32 -0700275{
Mark Browne2d32ff2012-08-31 17:38:32 -0700276 struct snd_soc_dapm_widget *w;
277
278 mutex_lock(&card->dapm_mutex);
279
280 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200281 if (w->is_sink || w->is_source) {
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200282 dapm_mark_dirty(w, "Rechecking endpoints");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +0200283 if (w->is_sink)
284 dapm_widget_invalidate_output_paths(w);
285 if (w->is_source)
286 dapm_widget_invalidate_input_paths(w);
287 }
Mark Browne2d32ff2012-08-31 17:38:32 -0700288 }
289
290 mutex_unlock(&card->dapm_mutex);
291}
Lars-Peter Clausen8be4da22014-10-25 17:42:01 +0200292EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
Mark Browne2d32ff2012-08-31 17:38:32 -0700293
Richard Purdie2b97eab2006-10-06 18:32:18 +0200294/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100295static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200296 const struct snd_soc_dapm_widget *_widget)
297{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100298 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200299}
300
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200301struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200302 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200303 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200304 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200305 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200306};
307
308static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
309 struct snd_kcontrol *kcontrol)
310{
311 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200312 struct soc_mixer_control *mc;
Charles Keepax561ed682015-05-01 12:37:26 +0100313 struct soc_enum *e;
Charles Keepax773da9b2015-05-01 12:37:25 +0100314 const char *name;
315 int ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200316
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200317 data = kzalloc(sizeof(*data), GFP_KERNEL);
Charles Keepax40b7bea2015-05-01 12:37:24 +0100318 if (!data)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200319 return -ENOMEM;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200320
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200321 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200322
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200323 switch (widget->id) {
324 case snd_soc_dapm_switch:
325 case snd_soc_dapm_mixer:
326 case snd_soc_dapm_mixer_named_ctl:
327 mc = (struct soc_mixer_control *)kcontrol->private_value;
328
329 if (mc->autodisable) {
330 struct snd_soc_dapm_widget template;
331
Charles Keepax773da9b2015-05-01 12:37:25 +0100332 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
333 "Autodisable");
334 if (!name) {
335 ret = -ENOMEM;
336 goto err_data;
337 }
338
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200339 memset(&template, 0, sizeof(template));
340 template.reg = mc->reg;
341 template.mask = (1 << fls(mc->max)) - 1;
342 template.shift = mc->shift;
343 if (mc->invert)
344 template.off_val = mc->max;
345 else
346 template.off_val = 0;
347 template.on_val = template.off_val;
348 template.id = snd_soc_dapm_kcontrol;
Charles Keepax773da9b2015-05-01 12:37:25 +0100349 template.name = name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200350
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200351 data->value = template.on_val;
352
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200353 data->widget = snd_soc_dapm_new_control(widget->dapm,
354 &template);
355 if (!data->widget) {
Charles Keepax773da9b2015-05-01 12:37:25 +0100356 ret = -ENOMEM;
357 goto err_name;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200358 }
359 }
360 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200361 case snd_soc_dapm_demux:
Charles Keepax561ed682015-05-01 12:37:26 +0100362 case snd_soc_dapm_mux:
363 e = (struct soc_enum *)kcontrol->private_value;
364
365 if (e->autodisable) {
366 struct snd_soc_dapm_widget template;
367
368 name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
369 "Autodisable");
370 if (!name) {
371 ret = -ENOMEM;
372 goto err_data;
373 }
374
375 memset(&template, 0, sizeof(template));
376 template.reg = e->reg;
377 template.mask = e->mask << e->shift_l;
378 template.shift = e->shift_l;
379 template.off_val = snd_soc_enum_item_to_val(e, 0);
380 template.on_val = template.off_val;
381 template.id = snd_soc_dapm_kcontrol;
382 template.name = name;
383
384 data->value = template.on_val;
385
386 data->widget = snd_soc_dapm_new_control(widget->dapm,
387 &template);
388 if (!data->widget) {
389 ret = -ENOMEM;
390 goto err_name;
391 }
392
393 snd_soc_dapm_add_path(widget->dapm, data->widget,
394 widget, NULL, NULL);
395 }
396 break;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200397 default:
398 break;
399 }
400
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200401 kcontrol->private_data = data;
402
403 return 0;
Charles Keepax773da9b2015-05-01 12:37:25 +0100404
405err_name:
406 kfree(name);
407err_data:
408 kfree(data);
409 return ret;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200410}
411
412static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
413{
414 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Charles Keepax773da9b2015-05-01 12:37:25 +0100415 if (data->widget)
416 kfree(data->widget->name);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200417 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200418 kfree(data);
419}
420
421static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
422 const struct snd_kcontrol *kcontrol)
423{
424 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
425
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200426 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200427}
428
429static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
430 struct snd_soc_dapm_widget *widget)
431{
432 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200433 struct snd_soc_dapm_widget_list *new_wlist;
434 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200435
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200436 if (data->wlist)
437 n = data->wlist->num_widgets + 1;
438 else
439 n = 1;
440
441 new_wlist = krealloc(data->wlist,
442 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
443 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200444 return -ENOMEM;
445
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200446 new_wlist->widgets[n - 1] = widget;
447 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200448
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200449 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200450
451 return 0;
452}
453
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200454static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
455 struct snd_soc_dapm_path *path)
456{
457 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
458
459 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200460}
461
462static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
463{
464 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
465
466 if (!data->widget)
467 return true;
468
469 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200470}
471
472static struct list_head *dapm_kcontrol_get_path_list(
473 const struct snd_kcontrol *kcontrol)
474{
475 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
476
477 return &data->paths;
478}
479
480#define dapm_kcontrol_for_each_path(path, kcontrol) \
481 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
482 list_kcontrol)
483
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530484unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200485{
486 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
487
488 return data->value;
489}
Subhransu S. Prusty5dc0158a2014-09-19 16:46:05 +0530490EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value);
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200491
492static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
493 unsigned int value)
494{
495 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
496
497 if (data->value == value)
498 return false;
499
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200500 if (data->widget)
501 data->widget->on_val = value;
502
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200503 data->value = value;
504
505 return true;
506}
507
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200508/**
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200509 * snd_soc_dapm_kcontrol_dapm() - Returns the dapm context associated to a
510 * kcontrol
511 * @kcontrol: The kcontrol
512 *
513 * Note: This function must only be used on kcontrols that are known to have
514 * been registered for a CODEC. Otherwise the behaviour is undefined.
515 */
516struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
517 struct snd_kcontrol *kcontrol)
518{
519 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->dapm;
520}
521EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_dapm);
522
Liam Girdwood6c120e12012-02-15 15:15:34 +0000523static void dapm_reset(struct snd_soc_card *card)
524{
525 struct snd_soc_dapm_widget *w;
526
Mark Brownf9fa2b12014-03-06 16:49:11 +0800527 lockdep_assert_held(&card->dapm_mutex);
528
Liam Girdwood6c120e12012-02-15 15:15:34 +0000529 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
530
531 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200532 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000533 w->power_checked = false;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000534 }
535}
536
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200537static const char *soc_dapm_prefix(struct snd_soc_dapm_context *dapm)
538{
539 if (!dapm->component)
540 return NULL;
541 return dapm->component->name_prefix;
542}
543
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200544static int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg,
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800545 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100546{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200547 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200548 return -EIO;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200549 return snd_soc_component_read(dapm->component, reg, value);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100550}
551
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200552static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
Bard Liao34775012014-04-17 20:12:56 +0800553 int reg, unsigned int mask, unsigned int value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100554{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200555 if (!dapm->component)
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200556 return -EIO;
Mark Brownfcf6c5e2014-12-15 13:08:48 +0000557 return snd_soc_component_update_bits(dapm->component, reg,
558 mask, value);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000559}
560
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200561static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
562 int reg, unsigned int mask, unsigned int value)
563{
564 if (!dapm->component)
565 return -EIO;
566 return snd_soc_component_test_bits(dapm->component, reg, mask, value);
567}
568
Mark Browneb270e92013-10-09 13:52:52 +0100569static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
570{
Lars-Peter Clausene2c330b2014-04-22 13:23:13 +0200571 if (dapm->component)
572 snd_soc_component_async_complete(dapm->component);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100573}
574
Mark Brown452c5ea2009-05-17 21:41:23 +0100575/**
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200576 * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
577 * @dapm: The DAPM context for which to set the level
578 * @level: The level to set
579 *
580 * Forces the DAPM bias level to a specific state. It will call the bias level
581 * callback of DAPM context with the specified level. This will even happen if
582 * the context is already at the same level. Furthermore it will not go through
583 * the normal bias level sequencing, meaning any intermediate states between the
584 * current and the target state will not be entered.
585 *
586 * Note that the change in bias level is only temporary and the next time
587 * snd_soc_dapm_sync() is called the state will be set to the level as
588 * determined by the DAPM core. The function is mainly intended to be used to
589 * used during probe or resume from suspend to power up the device so
590 * initialization can be done, before the DAPM core takes over.
591 */
592int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
593 enum snd_soc_bias_level level)
594{
595 int ret = 0;
596
597 if (dapm->set_bias_level)
598 ret = dapm->set_bias_level(dapm, level);
599
Lars-Peter Clausenf4bf8d72015-04-27 22:13:25 +0200600 if (ret == 0)
601 dapm->bias_level = level;
602
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200603 return ret;
604}
605EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
606
607/**
Mark Brown452c5ea2009-05-17 21:41:23 +0100608 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800609 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100610 * @level: level to configure
611 *
612 * Configure the bias (power) levels for the SoC audio device.
613 *
614 * Returns 0 for success else error.
615 */
Mark Browned5a4c42011-02-18 11:12:42 -0800616static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200617 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100618{
Mark Browned5a4c42011-02-18 11:12:42 -0800619 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100620 int ret = 0;
621
Mark Brown84e90932010-11-04 00:07:02 -0400622 trace_snd_soc_bias_level_start(card, level);
623
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000624 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100625 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100626 if (ret != 0)
627 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100628
Lars-Peter Clausenfa880772015-04-27 22:13:23 +0200629 if (!card || dapm != &card->dapm)
630 ret = snd_soc_dapm_force_bias_level(dapm, level);
Liam Girdwood41231282012-07-06 16:56:16 +0100631
Mark Brown171ec6b2011-06-06 18:15:19 +0100632 if (ret != 0)
633 goto out;
634
635 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100636 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100637out:
Mark Brown84e90932010-11-04 00:07:02 -0400638 trace_snd_soc_bias_level_done(card, level);
639
Mark Brown452c5ea2009-05-17 21:41:23 +0100640 return ret;
641}
642
Mark Brown74b8f952009-06-06 11:26:15 +0100643/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200644static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200645 struct snd_soc_dapm_path *path, const char *control_name,
646 struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200647{
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200648 const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +0200649 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100650 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200651 int i;
652
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100653 if (e->reg != SND_SOC_NOPM) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +0200654 soc_dapm_read(dapm, e->reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100655 val = (val >> e->shift_l) & e->mask;
656 item = snd_soc_enum_val_to_item(e, val);
657 } else {
658 /* since a virtual mux has no backing registers to
659 * decide which path to connect, it will try to match
660 * with the first enumeration. This is to ensure
661 * that the default mux choice (the first) will be
662 * correctly powered up during initialization.
663 */
664 item = 0;
665 }
666
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100667 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200668 if (!(strcmp(control_name, e->texts[i]))) {
Rasmus Villemoes98ad73c2014-10-21 17:01:15 +0200669 path->name = e->texts[i];
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100670 if (i == item)
671 path->connect = 1;
672 else
673 path->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200674 return 0;
675 }
676 }
677
678 return -ENODEV;
679}
680
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100681/* set up initial codec paths */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200682static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100683{
684 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200685 p->sink->kcontrol_news[i].private_value;
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100686 unsigned int reg = mc->reg;
687 unsigned int shift = mc->shift;
688 unsigned int max = mc->max;
689 unsigned int mask = (1 << fls(max)) - 1;
690 unsigned int invert = mc->invert;
691 unsigned int val;
692
693 if (reg != SND_SOC_NOPM) {
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200694 soc_dapm_read(p->sink->dapm, reg, &val);
Lars-Peter Clausen234c0b82014-02-28 08:31:12 +0100695 val = (val >> shift) & mask;
696 if (invert)
697 val = max - val;
698 p->connect = !!val;
699 } else {
700 p->connect = 0;
701 }
702}
703
Mark Brown74b8f952009-06-06 11:26:15 +0100704/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200705static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200706 struct snd_soc_dapm_path *path, const char *control_name)
707{
708 int i;
709
710 /* search for mixer kcontrol */
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +0200711 for (i = 0; i < path->sink->num_kcontrols; i++) {
712 if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
713 path->name = path->sink->kcontrol_news[i].name;
714 dapm_set_mixer_path_status(path, i);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200715 return 0;
716 }
717 }
718 return -ENODEV;
719}
720
Stephen Warrenaf468002011-04-28 17:38:01 -0600721static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600722 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600723 const struct snd_kcontrol_new *kcontrol_new,
724 struct snd_kcontrol **kcontrol)
725{
726 struct snd_soc_dapm_widget *w;
727 int i;
728
729 *kcontrol = NULL;
730
731 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600732 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
733 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600734 for (i = 0; i < w->num_kcontrols; i++) {
735 if (&w->kcontrol_news[i] == kcontrol_new) {
736 if (w->kcontrols)
737 *kcontrol = w->kcontrols[i];
738 return 1;
739 }
740 }
741 }
742
743 return 0;
744}
745
Stephen Warren85762e72013-03-29 15:40:10 -0600746/*
747 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
748 * create it. Either way, add the widget into the control's widget list
749 */
750static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100751 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200752{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200753 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000754 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000755 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600756 size_t prefix_len;
757 int shared;
758 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600759 bool wname_in_long_name, kcname_in_long_name;
Daniel Macke5092c92014-10-07 13:41:24 +0200760 char *long_name = NULL;
Stephen Warren85762e72013-03-29 15:40:10 -0600761 const char *name;
Daniel Macke5092c92014-10-07 13:41:24 +0200762 int ret = 0;
Mark Brownefb7ac32011-03-08 17:23:24 +0000763
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +0200764 prefix = soc_dapm_prefix(dapm);
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000765 if (prefix)
766 prefix_len = strlen(prefix) + 1;
767 else
768 prefix_len = 0;
769
Stephen Warren85762e72013-03-29 15:40:10 -0600770 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
771 &kcontrol);
772
Stephen Warren85762e72013-03-29 15:40:10 -0600773 if (!kcontrol) {
774 if (shared) {
775 wname_in_long_name = false;
776 kcname_in_long_name = true;
777 } else {
778 switch (w->id) {
779 case snd_soc_dapm_switch:
780 case snd_soc_dapm_mixer:
781 wname_in_long_name = true;
782 kcname_in_long_name = true;
783 break;
784 case snd_soc_dapm_mixer_named_ctl:
785 wname_in_long_name = false;
786 kcname_in_long_name = true;
787 break;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200788 case snd_soc_dapm_demux:
Stephen Warren85762e72013-03-29 15:40:10 -0600789 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600790 wname_in_long_name = true;
791 kcname_in_long_name = false;
792 break;
793 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600794 return -EINVAL;
795 }
796 }
797
798 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600799 /*
800 * The control will get a prefix from the control
801 * creation process but we're also using the same
802 * prefix for widgets so cut the prefix off the
803 * front of the widget name.
804 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200805 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600806 w->name + prefix_len,
807 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200808 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200809 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600810
811 name = long_name;
812 } else if (wname_in_long_name) {
813 long_name = NULL;
814 name = w->name + prefix_len;
815 } else {
816 long_name = NULL;
817 name = w->kcontrol_news[kci].name;
818 }
819
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200820 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600821 prefix);
Daniel Macke5092c92014-10-07 13:41:24 +0200822 if (!kcontrol) {
823 ret = -ENOMEM;
824 goto exit_free;
825 }
826
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200827 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200828
829 ret = dapm_kcontrol_data_alloc(w, kcontrol);
830 if (ret) {
831 snd_ctl_free_one(kcontrol);
Daniel Macke5092c92014-10-07 13:41:24 +0200832 goto exit_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200833 }
834
Stephen Warren85762e72013-03-29 15:40:10 -0600835 ret = snd_ctl_add(card, kcontrol);
836 if (ret < 0) {
837 dev_err(dapm->dev,
838 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
839 w->name, name, ret);
Daniel Macke5092c92014-10-07 13:41:24 +0200840 goto exit_free;
Stephen Warren85762e72013-03-29 15:40:10 -0600841 }
Stephen Warren85762e72013-03-29 15:40:10 -0600842 }
843
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200844 ret = dapm_kcontrol_add_widget(kcontrol, w);
Daniel Macke5092c92014-10-07 13:41:24 +0200845 if (ret == 0)
846 w->kcontrols[kci] = kcontrol;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200847
Daniel Macke5092c92014-10-07 13:41:24 +0200848exit_free:
849 kfree(long_name);
Stephen Warren85762e72013-03-29 15:40:10 -0600850
Daniel Macke5092c92014-10-07 13:41:24 +0200851 return ret;
Stephen Warren85762e72013-03-29 15:40:10 -0600852}
853
854/* create new dapm mixer control */
855static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
856{
857 int i, ret;
858 struct snd_soc_dapm_path *path;
Charles Keepax561ed682015-05-01 12:37:26 +0100859 struct dapm_kcontrol_data *data;
Stephen Warren85762e72013-03-29 15:40:10 -0600860
Richard Purdie2b97eab2006-10-06 18:32:18 +0200861 /* add kcontrol */
862 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200863 /* match name */
864 list_for_each_entry(path, &w->sources, list_sink) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200865 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600866 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200867 continue;
868
Charles Keepax561ed682015-05-01 12:37:26 +0100869 if (!w->kcontrols[i]) {
870 ret = dapm_create_or_share_mixmux_kcontrol(w, i);
871 if (ret < 0)
872 return ret;
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200873 }
874
Mark Brown946d92a2013-08-12 23:28:42 +0100875 dapm_kcontrol_add_path(w->kcontrols[i], path);
Charles Keepax561ed682015-05-01 12:37:26 +0100876
877 data = snd_kcontrol_chip(w->kcontrols[i]);
878 if (data->widget)
879 snd_soc_dapm_add_path(data->widget->dapm,
880 data->widget,
881 path->source,
882 NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200883 }
884 }
Stephen Warren85762e72013-03-29 15:40:10 -0600885
886 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200887}
888
889/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200890static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200891{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200892 struct snd_soc_dapm_context *dapm = w->dapm;
Stephen Warren85762e72013-03-29 15:40:10 -0600893 struct snd_soc_dapm_path *path;
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200894 struct list_head *paths;
895 const char *type;
Stephen Warrenaf468002011-04-28 17:38:01 -0600896 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200897
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200898 switch (w->id) {
899 case snd_soc_dapm_mux:
900 paths = &w->sources;
901 type = "mux";
902 break;
903 case snd_soc_dapm_demux:
904 paths = &w->sinks;
905 type = "demux";
906 break;
907 default:
908 return -EINVAL;
909 }
910
Stephen Warrenaf468002011-04-28 17:38:01 -0600911 if (w->num_kcontrols != 1) {
912 dev_err(dapm->dev,
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200913 "ASoC: %s %s has incorrect number of controls\n", type,
Stephen Warrenaf468002011-04-28 17:38:01 -0600914 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200915 return -EINVAL;
916 }
917
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200918 if (list_empty(paths)) {
919 dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
Stephen Warren85762e72013-03-29 15:40:10 -0600920 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600921 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200922
Mark Brown946d92a2013-08-12 23:28:42 +0100923 ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600924 if (ret < 0)
925 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600926
Lars-Peter Clausend714f972015-05-01 18:02:43 +0200927 if (w->id == snd_soc_dapm_mux) {
928 list_for_each_entry(path, &w->sources, list_sink) {
929 if (path->name)
930 dapm_kcontrol_add_path(w->kcontrols[0], path);
931 }
932 } else {
933 list_for_each_entry(path, &w->sinks, list_source) {
934 if (path->name)
935 dapm_kcontrol_add_path(w->kcontrols[0], path);
936 }
Lars-Peter Clausen98407ef2014-10-25 17:41:57 +0200937 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200938
Stephen Warrenaf468002011-04-28 17:38:01 -0600939 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200940}
941
942/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200943static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200944{
Mark Browna6c65732010-03-03 17:45:21 +0000945 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200946 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000947 "ASoC: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200948
Mark Browna6c65732010-03-03 17:45:21 +0000949 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200950}
951
Nikesh Oswalc6615082015-02-02 17:06:44 +0000952/* create new dapm dai link control */
953static int dapm_new_dai_link(struct snd_soc_dapm_widget *w)
954{
955 int i, ret;
956 struct snd_kcontrol *kcontrol;
957 struct snd_soc_dapm_context *dapm = w->dapm;
958 struct snd_card *card = dapm->card->snd_card;
959
960 /* create control for links with > 1 config */
961 if (w->num_params <= 1)
962 return 0;
963
964 /* add kcontrol */
965 for (i = 0; i < w->num_kcontrols; i++) {
966 kcontrol = snd_soc_cnew(&w->kcontrol_news[i], w,
967 w->name, NULL);
968 ret = snd_ctl_add(card, kcontrol);
969 if (ret < 0) {
970 dev_err(dapm->dev,
971 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
972 w->name, w->kcontrol_news[i].name, ret);
973 return ret;
974 }
975 kcontrol->private_data = w;
976 w->kcontrols[i] = kcontrol;
977 }
978
979 return 0;
980}
981
Mark Brown99497882010-05-07 20:24:05 +0100982/* We implement power down on suspend by checking the power state of
983 * the ALSA card - when we are suspending the ALSA state for the card
984 * is set to D3.
985 */
986static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
987{
Mark Brown12ea2c72011-03-02 18:17:32 +0000988 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +0100989
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000990 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +0100991 case SNDRV_CTL_POWER_D3hot:
992 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +0100993 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000994 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200995 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +0100996 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +0100997 default:
998 return 1;
999 }
1000}
1001
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001002/* add widget to list if it's not already in the list */
1003static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
1004 struct snd_soc_dapm_widget *w)
1005{
1006 struct snd_soc_dapm_widget_list *wlist;
1007 int wlistsize, wlistentries, i;
1008
1009 if (*list == NULL)
1010 return -EINVAL;
1011
1012 wlist = *list;
1013
1014 /* is this widget already in the list */
1015 for (i = 0; i < wlist->num_widgets; i++) {
1016 if (wlist->widgets[i] == w)
1017 return 0;
1018 }
1019
1020 /* allocate some new space */
1021 wlistentries = wlist->num_widgets + 1;
1022 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
1023 wlistentries * sizeof(struct snd_soc_dapm_widget *);
1024 *list = krealloc(wlist, wlistsize, GFP_KERNEL);
1025 if (*list == NULL) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001026 dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001027 w->name);
1028 return -ENOMEM;
1029 }
1030 wlist = *list;
1031
1032 /* insert the widget */
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001033 dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001034 w->name, wlist->num_widgets);
1035
1036 wlist->widgets[wlist->num_widgets] = w;
1037 wlist->num_widgets++;
1038 return 1;
1039}
1040
Richard Purdie2b97eab2006-10-06 18:32:18 +02001041/*
1042 * Recursively check for a completed path to an active or physically connected
1043 * output widget. Returns number of complete paths.
1044 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001045static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
1046 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001047{
1048 struct snd_soc_dapm_path *path;
1049 int con = 0;
1050
Mark Brown024dc072011-10-09 11:52:05 +01001051 if (widget->outputs >= 0)
1052 return widget->outputs;
1053
Mark Brownde02d072011-09-20 21:43:24 +01001054 DAPM_UPDATE_STAT(widget, path_checks);
1055
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001056 if (widget->is_sink && widget->connected) {
1057 widget->outputs = snd_soc_dapm_suspend_check(widget);
1058 return widget->outputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001059 }
1060
1061 list_for_each_entry(path, &widget->sinks, list_source) {
Mark Browne56235e2011-09-21 18:19:14 +01001062 DAPM_UPDATE_STAT(widget, neighbour_checks);
1063
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001064 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001065 continue;
1066
Mark Brown8af294b2013-02-22 17:48:15 +00001067 if (path->walking)
1068 return 1;
1069
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001070 trace_snd_soc_dapm_output_path(widget, path);
1071
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001072 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001073 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001074
1075 /* do we need to add this widget to the list ? */
1076 if (list) {
1077 int err;
1078 err = dapm_list_add_widget(list, path->sink);
1079 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001080 dev_err(widget->dapm->dev,
1081 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001082 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +00001083 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001084 return con;
1085 }
1086 }
1087
1088 con += is_connected_output_ep(path->sink, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001089
1090 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001091 }
1092 }
1093
Mark Brown024dc072011-10-09 11:52:05 +01001094 widget->outputs = con;
1095
Richard Purdie2b97eab2006-10-06 18:32:18 +02001096 return con;
1097}
1098
1099/*
1100 * Recursively check for a completed path to an active or physically connected
1101 * input widget. Returns number of complete paths.
1102 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001103static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
1104 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001105{
1106 struct snd_soc_dapm_path *path;
1107 int con = 0;
1108
Mark Brown024dc072011-10-09 11:52:05 +01001109 if (widget->inputs >= 0)
1110 return widget->inputs;
1111
Mark Brownde02d072011-09-20 21:43:24 +01001112 DAPM_UPDATE_STAT(widget, path_checks);
1113
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001114 if (widget->is_source && widget->connected) {
1115 widget->inputs = snd_soc_dapm_suspend_check(widget);
1116 return widget->inputs;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001117 }
1118
1119 list_for_each_entry(path, &widget->sources, list_sink) {
Mark Browne56235e2011-09-21 18:19:14 +01001120 DAPM_UPDATE_STAT(widget, neighbour_checks);
1121
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001122 if (path->weak || path->is_supply)
Mark Brownbf3a9e12011-06-13 16:42:29 +01001123 continue;
1124
Mark Brown8af294b2013-02-22 17:48:15 +00001125 if (path->walking)
1126 return 1;
1127
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001128 trace_snd_soc_dapm_input_path(widget, path);
1129
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001130 if (path->connect) {
Mark Brown8af294b2013-02-22 17:48:15 +00001131 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001132
1133 /* do we need to add this widget to the list ? */
1134 if (list) {
1135 int err;
Liam Girdwood90c6ce02012-06-05 19:27:15 +01001136 err = dapm_list_add_widget(list, path->source);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001137 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001138 dev_err(widget->dapm->dev,
1139 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001140 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +00001141 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001142 return con;
1143 }
1144 }
1145
1146 con += is_connected_input_ep(path->source, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001147
1148 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001149 }
1150 }
1151
Mark Brown024dc072011-10-09 11:52:05 +01001152 widget->inputs = con;
1153
Richard Purdie2b97eab2006-10-06 18:32:18 +02001154 return con;
1155}
1156
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001157/**
1158 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1159 * @dai: the soc DAI.
1160 * @stream: stream direction.
1161 * @list: list of active widgets for this stream.
1162 *
1163 * Queries DAPM graph as to whether an valid audio stream path exists for
1164 * the initial stream specified by name. This takes into account
1165 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1166 *
1167 * Returns the number of valid paths or negative error.
1168 */
1169int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1170 struct snd_soc_dapm_widget_list **list)
1171{
Lars-Peter Clausen313665b2014-11-04 11:30:58 +01001172 struct snd_soc_card *card = dai->component->card;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001173 struct snd_soc_dapm_widget *w;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001174 int paths;
1175
1176 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02001177
1178 /*
1179 * For is_connected_{output,input}_ep fully discover the graph we need
1180 * to reset the cached number of inputs and outputs.
1181 */
1182 list_for_each_entry(w, &card->widgets, list) {
1183 w->inputs = -1;
1184 w->outputs = -1;
1185 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001186
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001187 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001188 paths = is_connected_output_ep(dai->playback_widget, list);
Lars-Peter Clausen130897a2014-10-20 19:36:39 +02001189 else
Liam Girdwoodd298caa2012-06-01 18:03:00 +01001190 paths = is_connected_input_ep(dai->capture_widget, list);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001191
1192 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001193 mutex_unlock(&card->dapm_mutex);
1194
1195 return paths;
1196}
1197
Richard Purdie2b97eab2006-10-06 18:32:18 +02001198/*
Mark Brown62ea8742012-01-21 21:14:48 +00001199 * Handler for regulator supply widget.
1200 */
1201int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1202 struct snd_kcontrol *kcontrol, int event)
1203{
Mark Brownc05b84d2012-09-07 12:57:11 +08001204 int ret;
1205
Mark Browneb270e92013-10-09 13:52:52 +01001206 soc_dapm_async_complete(w->dapm);
1207
Mark Brownc05b84d2012-09-07 12:57:11 +08001208 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001209 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001210 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001211 if (ret != 0)
1212 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001213 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001214 w->name, ret);
1215 }
1216
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001217 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001218 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001219 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001220 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001221 if (ret != 0)
1222 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001223 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001224 w->name, ret);
1225 }
1226
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001227 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001228 }
Mark Brown62ea8742012-01-21 21:14:48 +00001229}
1230EXPORT_SYMBOL_GPL(dapm_regulator_event);
1231
Ola Liljad7e7eb92012-05-24 15:26:25 +02001232/*
1233 * Handler for clock supply widget.
1234 */
1235int dapm_clock_event(struct snd_soc_dapm_widget *w,
1236 struct snd_kcontrol *kcontrol, int event)
1237{
1238 if (!w->clk)
1239 return -EIO;
1240
Mark Browneb270e92013-10-09 13:52:52 +01001241 soc_dapm_async_complete(w->dapm);
1242
Mark Brownec029952012-06-04 08:16:20 +01001243#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001244 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001245 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001246 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001247 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001248 return 0;
1249 }
Mark Brownec029952012-06-04 08:16:20 +01001250#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001251 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001252}
1253EXPORT_SYMBOL_GPL(dapm_clock_event);
1254
Mark Brownd8050022011-09-28 18:28:23 +01001255static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1256{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001257 if (w->power_checked)
1258 return w->new_power;
1259
Mark Brownd8050022011-09-28 18:28:23 +01001260 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001261 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001262 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001263 w->new_power = w->power_check(w);
1264
1265 w->power_checked = true;
1266
1267 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001268}
1269
Mark Browncd0f2d42009-04-20 16:56:59 +01001270/* Generic check to see if a widget should be powered.
1271 */
1272static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1273{
1274 int in, out;
1275
Mark Brownde02d072011-09-20 21:43:24 +01001276 DAPM_UPDATE_STAT(w, power_checks);
1277
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001278 in = is_connected_input_ep(w, NULL);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001279 out = is_connected_output_ep(w, NULL);
Mark Browncd0f2d42009-04-20 16:56:59 +01001280 return out != 0 && in != 0;
1281}
1282
Mark Brown246d0a12009-04-22 18:24:55 +01001283/* Check to see if a power supply is needed */
1284static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1285{
1286 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001287
Mark Brownde02d072011-09-20 21:43:24 +01001288 DAPM_UPDATE_STAT(w, power_checks);
1289
Mark Brown246d0a12009-04-22 18:24:55 +01001290 /* Check if one of our outputs is connected */
1291 list_for_each_entry(path, &w->sinks, list_source) {
Mark Browna8fdac82011-09-28 18:20:26 +01001292 DAPM_UPDATE_STAT(w, neighbour_checks);
1293
Mark Brownbf3a9e12011-06-13 16:42:29 +01001294 if (path->weak)
1295 continue;
1296
Mark Brown215edda2009-09-08 18:59:05 +01001297 if (path->connected &&
1298 !path->connected(path->source, path->sink))
1299 continue;
1300
Mark Brownf68d7e12011-10-04 22:57:50 +01001301 if (dapm_widget_power_check(path->sink))
1302 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001303 }
1304
Mark Brownf68d7e12011-10-04 22:57:50 +01001305 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001306}
1307
Mark Brown35c64bc2011-09-28 18:23:53 +01001308static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1309{
1310 return 1;
1311}
1312
Mark Brown38357ab2009-06-06 19:03:23 +01001313static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1314 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001315 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001316{
Mark Brown828a8422011-01-15 13:14:30 +00001317 int *sort;
1318
1319 if (power_up)
1320 sort = dapm_up_seq;
1321 else
1322 sort = dapm_down_seq;
1323
Mark Brown38357ab2009-06-06 19:03:23 +01001324 if (sort[a->id] != sort[b->id])
1325 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001326 if (a->subseq != b->subseq) {
1327 if (power_up)
1328 return a->subseq - b->subseq;
1329 else
1330 return b->subseq - a->subseq;
1331 }
Mark Brownb22ead22009-06-07 12:51:26 +01001332 if (a->reg != b->reg)
1333 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001334 if (a->dapm != b->dapm)
1335 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001336
Mark Brown38357ab2009-06-06 19:03:23 +01001337 return 0;
1338}
Mark Brown42aa3412009-03-01 19:21:10 +00001339
Mark Brown38357ab2009-06-06 19:03:23 +01001340/* Insert a widget in order into a DAPM power sequence. */
1341static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1342 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001343 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001344{
1345 struct snd_soc_dapm_widget *w;
1346
1347 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001348 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001349 list_add_tail(&new_widget->power_list, &w->power_list);
1350 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001351 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001352
Mark Brown38357ab2009-06-06 19:03:23 +01001353 list_add_tail(&new_widget->power_list, list);
1354}
Mark Brown42aa3412009-03-01 19:21:10 +00001355
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001356static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001357 struct snd_soc_dapm_widget *w, int event)
1358{
Mark Brown68f89ad2010-11-03 23:51:49 -04001359 const char *ev_name;
1360 int power, ret;
1361
1362 switch (event) {
1363 case SND_SOC_DAPM_PRE_PMU:
1364 ev_name = "PRE_PMU";
1365 power = 1;
1366 break;
1367 case SND_SOC_DAPM_POST_PMU:
1368 ev_name = "POST_PMU";
1369 power = 1;
1370 break;
1371 case SND_SOC_DAPM_PRE_PMD:
1372 ev_name = "PRE_PMD";
1373 power = 0;
1374 break;
1375 case SND_SOC_DAPM_POST_PMD:
1376 ev_name = "POST_PMD";
1377 power = 0;
1378 break;
Mark Brown80114122013-02-25 15:14:19 +00001379 case SND_SOC_DAPM_WILL_PMU:
1380 ev_name = "WILL_PMU";
1381 power = 1;
1382 break;
1383 case SND_SOC_DAPM_WILL_PMD:
1384 ev_name = "WILL_PMD";
1385 power = 0;
1386 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001387 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001388 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001389 return;
1390 }
1391
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001392 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001393 return;
1394
1395 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001396 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001397 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001398 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001399 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001400 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001401 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001402 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001403 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001404 ev_name, w->name, ret);
1405 }
1406}
1407
Mark Brownb22ead22009-06-07 12:51:26 +01001408/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001409static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001410 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001411{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001412 struct snd_soc_dapm_context *dapm;
Mark Brown68f89ad2010-11-03 23:51:49 -04001413 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001414 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001415 unsigned int value = 0;
1416 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001417
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001418 w = list_first_entry(pending, struct snd_soc_dapm_widget, power_list);
1419 reg = w->reg;
1420 dapm = w->dapm;
Mark Brownb22ead22009-06-07 12:51:26 +01001421
1422 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001423 WARN_ON(reg != w->reg || dapm != w->dapm);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001424 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001425
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001426 mask |= w->mask << w->shift;
1427 if (w->power)
1428 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001429 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001430 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001431
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001432 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001433 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1434 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001435
Mark Brown68f89ad2010-11-03 23:51:49 -04001436 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001437 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1438 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001439 }
1440
Mark Brown81628102009-06-07 13:21:24 +01001441 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001442 /* Any widget will do, they should all be updating the
1443 * same register.
1444 */
Mark Brown29376bc2011-06-19 13:49:28 +01001445
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001446 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001447 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001448 value, mask, reg, card->pop_time);
1449 pop_wait(card->pop_time);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001450 soc_dapm_update_bits(dapm, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001451 }
1452
1453 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001454 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1455 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001456 }
Mark Brown42aa3412009-03-01 19:21:10 +00001457}
1458
Mark Brownb22ead22009-06-07 12:51:26 +01001459/* Apply a DAPM power sequence.
1460 *
1461 * We walk over a pre-sorted list of widgets to apply power to. In
1462 * order to minimise the number of writes to the device required
1463 * multiple widgets will be updated in a single write where possible.
1464 * Currently anything that requires more than a single write is not
1465 * handled.
1466 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001467static void dapm_seq_run(struct snd_soc_card *card,
1468 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001469{
1470 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001471 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001472 LIST_HEAD(pending);
1473 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001474 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001475 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001476 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001477 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001478 int *sort;
1479
1480 if (power_up)
1481 sort = dapm_up_seq;
1482 else
1483 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001484
Mark Brownb22ead22009-06-07 12:51:26 +01001485 list_for_each_entry_safe(w, n, list, power_list) {
1486 ret = 0;
1487
1488 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001489 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001490 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001491 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001492 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001493
Mark Brown474b62d2011-01-18 16:14:44 +00001494 if (cur_dapm && cur_dapm->seq_notifier) {
1495 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1496 if (sort[i] == cur_sort)
1497 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001498 i,
1499 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001500 }
1501
Mark Browneb270e92013-10-09 13:52:52 +01001502 if (cur_dapm && w->dapm != cur_dapm)
1503 soc_dapm_async_complete(cur_dapm);
1504
Mark Brownb22ead22009-06-07 12:51:26 +01001505 INIT_LIST_HEAD(&pending);
1506 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001507 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001508 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001509 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001510 }
1511
Mark Brown163cac02009-06-07 10:12:52 +01001512 switch (w->id) {
1513 case snd_soc_dapm_pre:
1514 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001515 list_for_each_entry_safe_continue(w, n, list,
1516 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001517
Mark Brownb22ead22009-06-07 12:51:26 +01001518 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001519 ret = w->event(w,
1520 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001521 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001522 ret = w->event(w,
1523 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001524 break;
1525
1526 case snd_soc_dapm_post:
1527 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001528 list_for_each_entry_safe_continue(w, n, list,
1529 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001530
Mark Brownb22ead22009-06-07 12:51:26 +01001531 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001532 ret = w->event(w,
1533 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001534 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001535 ret = w->event(w,
1536 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001537 break;
1538
Mark Brown163cac02009-06-07 10:12:52 +01001539 default:
Mark Brown81628102009-06-07 13:21:24 +01001540 /* Queue it up for application */
1541 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001542 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001543 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001544 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001545 list_move(&w->power_list, &pending);
1546 break;
Mark Brown163cac02009-06-07 10:12:52 +01001547 }
Mark Brownb22ead22009-06-07 12:51:26 +01001548
1549 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001550 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001551 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001552 }
Mark Brownb22ead22009-06-07 12:51:26 +01001553
1554 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001555 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001556
1557 if (cur_dapm && cur_dapm->seq_notifier) {
1558 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1559 if (sort[i] == cur_sort)
1560 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001561 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001562 }
Mark Browneb270e92013-10-09 13:52:52 +01001563
1564 list_for_each_entry(d, &card->dapm_list, list) {
1565 soc_dapm_async_complete(d);
1566 }
Mark Brown163cac02009-06-07 10:12:52 +01001567}
1568
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001569static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001570{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001571 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001572 struct snd_soc_dapm_widget_list *wlist;
1573 struct snd_soc_dapm_widget *w = NULL;
1574 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001575 int ret;
1576
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001577 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001578 return;
1579
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001580 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001581
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001582 for (wi = 0; wi < wlist->num_widgets; wi++) {
1583 w = wlist->widgets[wi];
1584
1585 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1586 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1587 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001588 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001589 w->name, ret);
1590 }
Mark Brown97404f22010-12-14 16:13:57 +00001591 }
1592
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001593 if (!w)
1594 return;
1595
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02001596 ret = soc_dapm_update_bits(w->dapm, update->reg, update->mask,
1597 update->val);
Mark Brown97404f22010-12-14 16:13:57 +00001598 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001599 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001600 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001601
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001602 for (wi = 0; wi < wlist->num_widgets; wi++) {
1603 w = wlist->widgets[wi];
1604
1605 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1606 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1607 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001608 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001609 w->name, ret);
1610 }
Mark Brown97404f22010-12-14 16:13:57 +00001611 }
1612}
1613
Mark Brown9d0624a2011-02-18 11:49:43 -08001614/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1615 * they're changing state.
1616 */
1617static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1618{
1619 struct snd_soc_dapm_context *d = data;
1620 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001621
Mark Brown56fba412011-06-04 11:25:10 +01001622 /* If we're off and we're not supposed to be go into STANDBY */
1623 if (d->bias_level == SND_SOC_BIAS_OFF &&
1624 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001625 if (d->dev)
1626 pm_runtime_get_sync(d->dev);
1627
Mark Brown9d0624a2011-02-18 11:49:43 -08001628 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1629 if (ret != 0)
1630 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001631 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001632 }
1633
Lars-Peter Clausence85a4d2014-05-06 10:32:15 +02001634 /* Prepare for a transition to ON or away from ON */
1635 if ((d->target_bias_level == SND_SOC_BIAS_ON &&
1636 d->bias_level != SND_SOC_BIAS_ON) ||
1637 (d->target_bias_level != SND_SOC_BIAS_ON &&
1638 d->bias_level == SND_SOC_BIAS_ON)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001639 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1640 if (ret != 0)
1641 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001642 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001643 }
1644}
1645
1646/* Async callback run prior to DAPM sequences - brings to their final
1647 * state.
1648 */
1649static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1650{
1651 struct snd_soc_dapm_context *d = data;
1652 int ret;
1653
1654 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001655 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1656 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1657 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001658 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1659 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001660 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001661 ret);
1662 }
1663
1664 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001665 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1666 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001667 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1668 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001669 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1670 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001671
1672 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001673 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001674 }
1675
1676 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001677 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1678 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001679 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1680 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001681 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001682 ret);
1683 }
1684}
Mark Brown97404f22010-12-14 16:13:57 +00001685
Mark Brownfe4fda52011-10-03 22:36:57 +01001686static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1687 bool power, bool connect)
1688{
1689 /* If a connection is being made or broken then that update
1690 * will have marked the peer dirty, otherwise the widgets are
1691 * not connected and this update has no impact. */
1692 if (!connect)
1693 return;
1694
1695 /* If the peer is already in the state we're moving to then we
1696 * won't have an impact on it. */
1697 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001698 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001699}
1700
Mark Brown05623c42011-09-28 17:02:31 +01001701static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1702 struct list_head *up_list,
1703 struct list_head *down_list)
1704{
Mark Browndb432b42011-10-03 21:06:40 +01001705 struct snd_soc_dapm_path *path;
1706
Mark Brown05623c42011-09-28 17:02:31 +01001707 if (w->power == power)
1708 return;
1709
1710 trace_snd_soc_dapm_widget_power(w, power);
1711
Mark Browndb432b42011-10-03 21:06:40 +01001712 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001713 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001714 */
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001715 list_for_each_entry(path, &w->sources, list_sink)
1716 dapm_widget_set_peer_power(path->source, power, path->connect);
1717
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02001718 /* Supplies can't affect their outputs, only their inputs */
1719 if (!w->is_supply) {
Lars-Peter Clausen7ddd4cd2014-10-20 19:36:34 +02001720 list_for_each_entry(path, &w->sinks, list_source)
1721 dapm_widget_set_peer_power(path->sink, power,
1722 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001723 }
1724
Mark Brown05623c42011-09-28 17:02:31 +01001725 if (power)
1726 dapm_seq_insert(w, up_list, true);
1727 else
1728 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001729}
1730
Mark Brown7c81beb2011-09-20 22:22:32 +01001731static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1732 struct list_head *up_list,
1733 struct list_head *down_list)
1734{
Mark Brown7c81beb2011-09-20 22:22:32 +01001735 int power;
1736
1737 switch (w->id) {
1738 case snd_soc_dapm_pre:
1739 dapm_seq_insert(w, down_list, false);
1740 break;
1741 case snd_soc_dapm_post:
1742 dapm_seq_insert(w, up_list, true);
1743 break;
1744
1745 default:
Mark Brownd8050022011-09-28 18:28:23 +01001746 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001747
Mark Brown05623c42011-09-28 17:02:31 +01001748 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001749 break;
1750 }
1751}
1752
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001753static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm)
1754{
1755 if (dapm->idle_bias_off)
1756 return true;
1757
1758 switch (snd_power_get_state(dapm->card->snd_card)) {
1759 case SNDRV_CTL_POWER_D3hot:
1760 case SNDRV_CTL_POWER_D3cold:
1761 return dapm->suspend_bias_off;
1762 default:
1763 break;
1764 }
1765
1766 return false;
1767}
1768
Mark Brown42aa3412009-03-01 19:21:10 +00001769/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001770 * Scan each dapm widget for complete audio path.
1771 * A complete path is a route that has valid endpoints i.e.:-
1772 *
1773 * o DAC to output pin.
1774 * o Input Pin to ADC.
1775 * o Input pin to Output pin (bypass, sidetone)
1776 * o DAC to ADC (loopback).
1777 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001778static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001779{
1780 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001781 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001782 LIST_HEAD(up_list);
1783 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001784 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001785 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001786
Mark Brownf9fa2b12014-03-06 16:49:11 +08001787 lockdep_assert_held(&card->dapm_mutex);
1788
Mark Brown84e90932010-11-04 00:07:02 -04001789 trace_snd_soc_dapm_start(card);
1790
Mark Brown56fba412011-06-04 11:25:10 +01001791 list_for_each_entry(d, &card->dapm_list, list) {
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001792 if (dapm_idle_bias_off(d))
Mark Brown497098be2012-03-08 15:06:09 +00001793 d->target_bias_level = SND_SOC_BIAS_OFF;
1794 else
1795 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001796 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001797
Liam Girdwood6c120e12012-02-15 15:15:34 +00001798 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001799
Mark Brown6d3ddc82009-05-16 17:47:29 +01001800 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001801 * lists indicating if they should be powered up or down. We
1802 * only check widgets that have been flagged as dirty but note
1803 * that new widgets may be added to the dirty list while we
1804 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001805 */
Mark Browndb432b42011-10-03 21:06:40 +01001806 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001807 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001808 }
1809
Mark Brownf9de6d72011-09-28 17:19:47 +01001810 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001811 switch (w->id) {
1812 case snd_soc_dapm_pre:
1813 case snd_soc_dapm_post:
1814 /* These widgets always need to be powered */
1815 break;
1816 default:
1817 list_del_init(&w->dirty);
1818 break;
1819 }
Mark Browndb432b42011-10-03 21:06:40 +01001820
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001821 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001822 d = w->dapm;
1823
1824 /* Supplies and micbiases only bring the
1825 * context up to STANDBY as unless something
1826 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001827 * generally don't require full power. Signal
1828 * generators are virtual pins and have no
1829 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001830 */
1831 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001832 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001833 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001834 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001835 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001836 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001837 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001838 case snd_soc_dapm_micbias:
1839 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1840 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1841 break;
1842 default:
1843 d->target_bias_level = SND_SOC_BIAS_ON;
1844 break;
1845 }
1846 }
1847
1848 }
1849
Mark Brown85a843c2011-09-21 21:29:47 +01001850 /* Force all contexts in the card to the same bias state if
1851 * they're not ground referenced.
1852 */
Mark Brown56fba412011-06-04 11:25:10 +01001853 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001854 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001855 if (d->target_bias_level > bias)
1856 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001857 list_for_each_entry(d, &card->dapm_list, list)
Lars-Peter Clausen86dbf2a2014-09-04 19:44:06 +02001858 if (!dapm_idle_bias_off(d))
Mark Brown85a843c2011-09-21 21:29:47 +01001859 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001860
Mark Brownde02d072011-09-20 21:43:24 +01001861 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001862
Xiang Xiao17282ba2014-03-02 00:04:03 +08001863 /* Run card bias changes at first */
1864 dapm_pre_sequence_async(&card->dapm, 0);
1865 /* Run other bias changes in parallel */
1866 list_for_each_entry(d, &card->dapm_list, list) {
1867 if (d != &card->dapm)
1868 async_schedule_domain(dapm_pre_sequence_async, d,
1869 &async_domain);
1870 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001871 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001872
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001873 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001874 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001875 }
1876
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001877 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001878 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001879 }
1880
Mark Brown6d3ddc82009-05-16 17:47:29 +01001881 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001882 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001883
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001884 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001885
Mark Brown6d3ddc82009-05-16 17:47:29 +01001886 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001887 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001888
Mark Brown9d0624a2011-02-18 11:49:43 -08001889 /* Run all the bias changes in parallel */
Xiang Xiao17282ba2014-03-02 00:04:03 +08001890 list_for_each_entry(d, &card->dapm_list, list) {
1891 if (d != &card->dapm)
1892 async_schedule_domain(dapm_post_sequence_async, d,
1893 &async_domain);
1894 }
Mark Brown9d0624a2011-02-18 11:49:43 -08001895 async_synchronize_full_domain(&async_domain);
Xiang Xiao17282ba2014-03-02 00:04:03 +08001896 /* Run card bias changes at last */
1897 dapm_post_sequence_async(&card->dapm, 0);
Mark Brown452c5ea2009-05-17 21:41:23 +01001898
Liam Girdwood8078d872012-02-15 15:15:35 +00001899 /* do we need to notify any clients that DAPM event is complete */
1900 list_for_each_entry(d, &card->dapm_list, list) {
1901 if (d->stream_event)
1902 d->stream_event(d, event);
1903 }
1904
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001905 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001906 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001907 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001908
Mark Brown84e90932010-11-04 00:07:02 -04001909 trace_snd_soc_dapm_done(card);
1910
Mark Brown42aa3412009-03-01 19:21:10 +00001911 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001912}
1913
Mark Brown79fb9382009-08-21 16:38:13 +01001914#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001915static ssize_t dapm_widget_power_read_file(struct file *file,
1916 char __user *user_buf,
1917 size_t count, loff_t *ppos)
1918{
1919 struct snd_soc_dapm_widget *w = file->private_data;
1920 char *buf;
1921 int in, out;
1922 ssize_t ret;
1923 struct snd_soc_dapm_path *p = NULL;
1924
1925 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1926 if (!buf)
1927 return -ENOMEM;
1928
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02001929 /* Supply widgets are not handled by is_connected_{input,output}_ep() */
1930 if (w->is_supply) {
1931 in = 0;
1932 out = 0;
1933 } else {
1934 in = is_connected_input_ep(w, NULL);
1935 out = is_connected_output_ep(w, NULL);
1936 }
Mark Brown79fb9382009-08-21 16:38:13 +01001937
Mark Brownf13ebad2012-03-03 18:01:01 +00001938 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1939 w->name, w->power ? "On" : "Off",
1940 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001941
Mark Brownd033c362009-12-04 15:25:56 +00001942 if (w->reg >= 0)
1943 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001944 " - R%d(0x%x) mask 0x%x",
1945 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00001946
1947 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1948
Mark Brown3eef08b2009-09-14 16:49:00 +01001949 if (w->sname)
1950 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1951 w->sname,
1952 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001953
1954 list_for_each_entry(p, &w->sources, list_sink) {
Takashi Iwaiff186202013-10-28 14:21:49 +01001955 if (p->connected && !p->connected(w, p->source))
Mark Brown215edda2009-09-08 18:59:05 +01001956 continue;
1957
Mark Brown79fb9382009-08-21 16:38:13 +01001958 if (p->connect)
1959 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001960 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001961 p->name ? p->name : "static",
1962 p->source->name);
1963 }
1964 list_for_each_entry(p, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001965 if (p->connected && !p->connected(w, p->sink))
1966 continue;
1967
Mark Brown79fb9382009-08-21 16:38:13 +01001968 if (p->connect)
1969 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001970 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001971 p->name ? p->name : "static",
1972 p->sink->name);
1973 }
1974
1975 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1976
1977 kfree(buf);
1978 return ret;
1979}
1980
1981static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001982 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01001983 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001984 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001985};
1986
Mark Brownef49e4f2011-04-04 20:48:13 +09001987static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1988 size_t count, loff_t *ppos)
1989{
1990 struct snd_soc_dapm_context *dapm = file->private_data;
1991 char *level;
1992
1993 switch (dapm->bias_level) {
1994 case SND_SOC_BIAS_ON:
1995 level = "On\n";
1996 break;
1997 case SND_SOC_BIAS_PREPARE:
1998 level = "Prepare\n";
1999 break;
2000 case SND_SOC_BIAS_STANDBY:
2001 level = "Standby\n";
2002 break;
2003 case SND_SOC_BIAS_OFF:
2004 level = "Off\n";
2005 break;
2006 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002007 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002008 level = "Unknown\n";
2009 break;
2010 }
2011
2012 return simple_read_from_buffer(user_buf, count, ppos, level,
2013 strlen(level));
2014}
2015
2016static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002017 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002018 .read = dapm_bias_read_file,
2019 .llseek = default_llseek,
2020};
2021
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002022void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2023 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002024{
Mark Brown79fb9382009-08-21 16:38:13 +01002025 struct dentry *d;
2026
Lars-Peter Clausen6553bf062015-04-09 10:52:38 +02002027 if (!parent)
2028 return;
2029
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002030 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2031
2032 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002033 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002034 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002035 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002036 }
Mark Brown79fb9382009-08-21 16:38:13 +01002037
Mark Brownef49e4f2011-04-04 20:48:13 +09002038 d = debugfs_create_file("bias_level", 0444,
2039 dapm->debugfs_dapm, dapm,
2040 &dapm_bias_fops);
2041 if (!d)
2042 dev_warn(dapm->dev,
2043 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002044}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002045
2046static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2047{
2048 struct snd_soc_dapm_context *dapm = w->dapm;
2049 struct dentry *d;
2050
2051 if (!dapm->debugfs_dapm || !w->name)
2052 return;
2053
2054 d = debugfs_create_file(w->name, 0444,
2055 dapm->debugfs_dapm, w,
2056 &dapm_widget_power_fops);
2057 if (!d)
2058 dev_warn(w->dapm->dev,
2059 "ASoC: Failed to create %s debugfs file\n",
2060 w->name);
2061}
2062
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002063static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2064{
2065 debugfs_remove_recursive(dapm->debugfs_dapm);
2066}
2067
Mark Brown79fb9382009-08-21 16:38:13 +01002068#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002069void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2070 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002071{
2072}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002073
2074static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2075{
2076}
2077
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002078static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2079{
2080}
2081
Mark Brown79fb9382009-08-21 16:38:13 +01002082#endif
2083
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002084/*
2085 * soc_dapm_connect_path() - Connects or disconnects a path
2086 * @path: The path to update
2087 * @connect: The new connect state of the path. True if the path is connected,
2088 * false if it is disconneted.
2089 * @reason: The reason why the path changed (for debugging only)
2090 */
2091static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
2092 bool connect, const char *reason)
2093{
2094 if (path->connect == connect)
2095 return;
2096
2097 path->connect = connect;
2098 dapm_mark_dirty(path->source, reason);
2099 dapm_mark_dirty(path->sink, reason);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002100 dapm_path_invalidate(path);
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002101}
2102
Richard Purdie2b97eab2006-10-06 18:32:18 +02002103/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002104static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002105 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002106{
2107 struct snd_soc_dapm_path *path;
2108 int found = 0;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002109 bool connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002110
Mark Brownf9fa2b12014-03-06 16:49:11 +08002111 lockdep_assert_held(&card->dapm_mutex);
2112
Richard Purdie2b97eab2006-10-06 18:32:18 +02002113 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002114 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002115 found = 1;
2116 /* we now need to match the string in the enum to the path */
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002117 if (!(strcmp(path->name, e->texts[mux])))
2118 connect = true;
2119 else
2120 connect = false;
2121
2122 soc_dapm_connect_path(path, connect, "mux update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002123 }
2124
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002125 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002126 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002127
Liam Girdwood618dae12012-04-25 12:12:51 +01002128 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002129}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002130
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002131int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002132 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2133 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002134{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002135 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002136 int ret;
2137
Liam Girdwood3cd04342012-03-09 12:02:08 +00002138 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002139 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002140 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002141 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002142 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002143 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002144 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002145 return ret;
2146}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002147EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002148
Milan plzik1b075e32008-01-10 14:39:46 +01002149/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002150static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Mark Brown283375c2009-12-07 18:09:03 +00002151 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002152{
2153 struct snd_soc_dapm_path *path;
2154 int found = 0;
2155
Mark Brownf9fa2b12014-03-06 16:49:11 +08002156 lockdep_assert_held(&card->dapm_mutex);
2157
Richard Purdie2b97eab2006-10-06 18:32:18 +02002158 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002159 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002160 found = 1;
Lars-Peter Clausen4a201942014-10-25 17:41:56 +02002161 soc_dapm_connect_path(path, connect, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002162 }
2163
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002164 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002165 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002166
Liam Girdwood618dae12012-04-25 12:12:51 +01002167 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002168}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002169
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002170int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002171 struct snd_kcontrol *kcontrol, int connect,
2172 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002173{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002174 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002175 int ret;
2176
Liam Girdwood3cd04342012-03-09 12:02:08 +00002177 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002178 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002179 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002180 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002181 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002182 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002183 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002184 return ret;
2185}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002186EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002187
Benoit Cousson44ba2642014-07-08 23:19:36 +02002188static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002189{
Richard Purdie2b97eab2006-10-06 18:32:18 +02002190 struct snd_soc_dapm_widget *w;
2191 int count = 0;
2192 char *state = "not set";
2193
Lars-Peter Clausen00200102014-07-17 22:01:07 +02002194 list_for_each_entry(w, &codec->component.card->widgets, list) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002195 if (w->dapm != &codec->dapm)
2196 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002197
2198 /* only display widgets that burnm power */
2199 switch (w->id) {
2200 case snd_soc_dapm_hp:
2201 case snd_soc_dapm_mic:
2202 case snd_soc_dapm_spk:
2203 case snd_soc_dapm_line:
2204 case snd_soc_dapm_micbias:
2205 case snd_soc_dapm_dac:
2206 case snd_soc_dapm_adc:
2207 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002208 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002209 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002210 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002211 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002212 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002213 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002214 if (w->name)
2215 count += sprintf(buf + count, "%s: %s\n",
2216 w->name, w->power ? "On":"Off");
2217 break;
2218 default:
2219 break;
2220 }
2221 }
2222
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002223 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02002224 case SND_SOC_BIAS_ON:
2225 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002226 break;
Mark Brown0be98982008-05-19 12:31:28 +02002227 case SND_SOC_BIAS_PREPARE:
2228 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002229 break;
Mark Brown0be98982008-05-19 12:31:28 +02002230 case SND_SOC_BIAS_STANDBY:
2231 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002232 break;
Mark Brown0be98982008-05-19 12:31:28 +02002233 case SND_SOC_BIAS_OFF:
2234 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002235 break;
2236 }
2237 count += sprintf(buf + count, "PM State: %s\n", state);
2238
2239 return count;
2240}
2241
Benoit Cousson44ba2642014-07-08 23:19:36 +02002242/* show dapm widget status in sys fs */
2243static ssize_t dapm_widget_show(struct device *dev,
2244 struct device_attribute *attr, char *buf)
2245{
2246 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
2247 int i, count = 0;
2248
2249 for (i = 0; i < rtd->num_codecs; i++) {
2250 struct snd_soc_codec *codec = rtd->codec_dais[i]->codec;
2251 count += dapm_widget_show_codec(codec, buf + count);
2252 }
2253
2254 return count;
2255}
2256
Richard Purdie2b97eab2006-10-06 18:32:18 +02002257static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2258
Takashi Iwaid29697d2015-01-30 20:16:37 +01002259struct attribute *soc_dapm_dev_attrs[] = {
2260 &dev_attr_dapm_widget.attr,
2261 NULL
2262};
Richard Purdie2b97eab2006-10-06 18:32:18 +02002263
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002264static void dapm_free_path(struct snd_soc_dapm_path *path)
2265{
2266 list_del(&path->list_sink);
2267 list_del(&path->list_source);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002268 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002269 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002270 kfree(path);
2271}
2272
Richard Purdie2b97eab2006-10-06 18:32:18 +02002273/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002274static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002275{
2276 struct snd_soc_dapm_widget *w, *next_w;
2277 struct snd_soc_dapm_path *p, *next_p;
2278
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002279 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2280 if (w->dapm != dapm)
2281 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002282 list_del(&w->list);
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002283 /*
2284 * remove source and sink paths associated to this widget.
2285 * While removing the path, remove reference to it from both
2286 * source and sink widgets so that path is removed only once.
2287 */
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002288 list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
2289 dapm_free_path(p);
2290
2291 list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
2292 dapm_free_path(p);
2293
Stephen Warrenfad59882011-04-28 17:37:59 -06002294 kfree(w->kcontrols);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002295 kfree(w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002296 kfree(w);
2297 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002298}
2299
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002300static struct snd_soc_dapm_widget *dapm_find_widget(
2301 struct snd_soc_dapm_context *dapm, const char *pin,
2302 bool search_other_contexts)
2303{
2304 struct snd_soc_dapm_widget *w;
2305 struct snd_soc_dapm_widget *fallback = NULL;
2306
2307 list_for_each_entry(w, &dapm->card->widgets, list) {
2308 if (!strcmp(w->name, pin)) {
2309 if (w->dapm == dapm)
2310 return w;
2311 else
2312 fallback = w;
2313 }
2314 }
2315
2316 if (search_other_contexts)
2317 return fallback;
2318
2319 return NULL;
2320}
2321
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002322static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002323 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002324{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002325 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002326
Mark Brownf9fa2b12014-03-06 16:49:11 +08002327 dapm_assert_locked(dapm);
2328
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002329 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002330 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002331 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002332 }
2333
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002334 if (w->connected != status) {
Mark Brown1a8b2d92012-02-16 11:50:07 -08002335 dapm_mark_dirty(w, "pin configuration");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002336 dapm_widget_invalidate_input_paths(w);
2337 dapm_widget_invalidate_output_paths(w);
2338 }
Mark Brown1a8b2d92012-02-16 11:50:07 -08002339
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002340 w->connected = status;
2341 if (status == 0)
2342 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002343
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002344 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002345}
2346
Richard Purdie2b97eab2006-10-06 18:32:18 +02002347/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002348 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2349 * @dapm: DAPM context
2350 *
2351 * Walks all dapm audio paths and powers widgets according to their
2352 * stream or path usage.
2353 *
2354 * Requires external locking.
2355 *
2356 * Returns 0 for success.
2357 */
2358int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2359{
2360 /*
2361 * Suppress early reports (eg, jacks syncing their state) to avoid
2362 * silly DAPM runs during card startup.
2363 */
2364 if (!dapm->card || !dapm->card->instantiated)
2365 return 0;
2366
2367 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2368}
2369EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2370
2371/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002372 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002373 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002374 *
2375 * Walks all dapm audio paths and powers widgets according to their
2376 * stream or path usage.
2377 *
2378 * Returns 0 for success.
2379 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002380int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002381{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002382 int ret;
2383
Liam Girdwood3cd04342012-03-09 12:02:08 +00002384 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002385 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002386 mutex_unlock(&dapm->card->dapm_mutex);
2387 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002388}
Liam Girdwooda5302182008-07-07 13:35:17 +01002389EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002390
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002391/*
2392 * dapm_update_widget_flags() - Re-compute widget sink and source flags
2393 * @w: The widget for which to update the flags
2394 *
2395 * Some widgets have a dynamic category which depends on which neighbors they
2396 * are connected to. This function update the category for these widgets.
2397 *
2398 * This function must be called whenever a path is added or removed to a widget.
2399 */
2400static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
2401{
2402 struct snd_soc_dapm_path *p;
2403
2404 switch (w->id) {
2405 case snd_soc_dapm_input:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002406 /* On a fully routed card a input is never a source */
2407 if (w->dapm->card->fully_routed)
2408 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002409 w->is_source = 1;
2410 list_for_each_entry(p, &w->sources, list_sink) {
2411 if (p->source->id == snd_soc_dapm_micbias ||
2412 p->source->id == snd_soc_dapm_mic ||
2413 p->source->id == snd_soc_dapm_line ||
2414 p->source->id == snd_soc_dapm_output) {
2415 w->is_source = 0;
2416 break;
2417 }
2418 }
2419 break;
2420 case snd_soc_dapm_output:
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01002421 /* On a fully routed card a output is never a sink */
2422 if (w->dapm->card->fully_routed)
2423 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002424 w->is_sink = 1;
2425 list_for_each_entry(p, &w->sinks, list_source) {
2426 if (p->sink->id == snd_soc_dapm_spk ||
2427 p->sink->id == snd_soc_dapm_hp ||
2428 p->sink->id == snd_soc_dapm_line ||
2429 p->sink->id == snd_soc_dapm_input) {
2430 w->is_sink = 0;
2431 break;
2432 }
2433 }
2434 break;
2435 case snd_soc_dapm_line:
2436 w->is_sink = !list_empty(&w->sources);
2437 w->is_source = !list_empty(&w->sinks);
2438 break;
2439 default:
2440 break;
2441 }
2442}
2443
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002444static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
2445 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
2446 const char *control)
2447{
2448 bool dynamic_source = false;
2449 bool dynamic_sink = false;
2450
2451 if (!control)
2452 return 0;
2453
2454 switch (source->id) {
2455 case snd_soc_dapm_demux:
2456 dynamic_source = true;
2457 break;
2458 default:
2459 break;
2460 }
2461
2462 switch (sink->id) {
2463 case snd_soc_dapm_mux:
2464 case snd_soc_dapm_switch:
2465 case snd_soc_dapm_mixer:
2466 case snd_soc_dapm_mixer_named_ctl:
2467 dynamic_sink = true;
2468 break;
2469 default:
2470 break;
2471 }
2472
2473 if (dynamic_source && dynamic_sink) {
2474 dev_err(dapm->dev,
2475 "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
2476 source->name, control, sink->name);
2477 return -EINVAL;
2478 } else if (!dynamic_source && !dynamic_sink) {
2479 dev_err(dapm->dev,
2480 "Control not supported for path %s -> [%s] -> %s\n",
2481 source->name, control, sink->name);
2482 return -EINVAL;
2483 }
2484
2485 return 0;
2486}
2487
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002488static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2489 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2490 const char *control,
2491 int (*connected)(struct snd_soc_dapm_widget *source,
2492 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002493{
2494 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002495 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002496
Lars-Peter Clausene409dfb2014-10-25 17:42:02 +02002497 if (wsink->is_supply && !wsource->is_supply) {
2498 dev_err(dapm->dev,
2499 "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
2500 wsource->name, wsink->name);
2501 return -EINVAL;
2502 }
2503
2504 if (connected && !wsource->is_supply) {
2505 dev_err(dapm->dev,
2506 "connected() callback only supported for supply widgets (%s -> %s)\n",
2507 wsource->name, wsink->name);
2508 return -EINVAL;
2509 }
2510
2511 if (wsource->is_supply && control) {
2512 dev_err(dapm->dev,
2513 "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
2514 wsource->name, control, wsink->name);
2515 return -EINVAL;
2516 }
2517
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002518 ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
2519 if (ret)
2520 return ret;
2521
Richard Purdie2b97eab2006-10-06 18:32:18 +02002522 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2523 if (!path)
2524 return -ENOMEM;
2525
2526 path->source = wsource;
2527 path->sink = wsink;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002528 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002529 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002530 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002531 INIT_LIST_HEAD(&path->list_source);
2532 INIT_LIST_HEAD(&path->list_sink);
2533
Lars-Peter Clausenc1862c82014-10-25 17:42:00 +02002534 if (wsource->is_supply || wsink->is_supply)
2535 path->is_supply = 1;
2536
Richard Purdie2b97eab2006-10-06 18:32:18 +02002537 /* connect static paths */
2538 if (control == NULL) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002539 path->connect = 1;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002540 } else {
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002541 switch (wsource->id) {
2542 case snd_soc_dapm_demux:
2543 ret = dapm_connect_mux(dapm, path, control, wsource);
2544 if (ret)
2545 goto err;
2546 break;
2547 default:
2548 break;
2549 }
2550
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002551 switch (wsink->id) {
2552 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002553 ret = dapm_connect_mux(dapm, path, control, wsink);
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002554 if (ret != 0)
2555 goto err;
2556 break;
2557 case snd_soc_dapm_switch:
2558 case snd_soc_dapm_mixer:
2559 case snd_soc_dapm_mixer_named_ctl:
2560 ret = dapm_connect_mixer(dapm, path, control);
2561 if (ret != 0)
2562 goto err;
2563 break;
2564 default:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002565 break;
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002566 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002567 }
2568
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002569 list_add(&path->list, &dapm->card->paths);
2570 list_add(&path->list_sink, &wsink->sources);
2571 list_add(&path->list_source, &wsource->sinks);
2572
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002573 dapm_update_widget_flags(wsource);
2574 dapm_update_widget_flags(wsink);
2575
Lars-Peter Clausen5fe5b762014-10-25 17:41:58 +02002576 dapm_mark_dirty(wsource, "Route added");
2577 dapm_mark_dirty(wsink, "Route added");
Mark Brownfabd0382012-07-05 17:20:06 +01002578
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002579 if (dapm->card->instantiated && path->connect)
2580 dapm_path_invalidate(path);
2581
Richard Purdie2b97eab2006-10-06 18:32:18 +02002582 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002583err:
2584 kfree(path);
2585 return ret;
2586}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002587
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002588static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002589 const struct snd_soc_dapm_route *route)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002590{
2591 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2592 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2593 const char *sink;
2594 const char *source;
2595 char prefixed_sink[80];
2596 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002597 const char *prefix;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002598 int ret;
2599
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002600 prefix = soc_dapm_prefix(dapm);
2601 if (prefix) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002602 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002603 prefix, route->sink);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002604 sink = prefixed_sink;
2605 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002606 prefix, route->source);
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002607 source = prefixed_source;
2608 } else {
2609 sink = route->sink;
2610 source = route->source;
2611 }
2612
2613 /*
2614 * find src and dest widgets over all widgets but favor a widget from
2615 * current DAPM context
2616 */
2617 list_for_each_entry(w, &dapm->card->widgets, list) {
2618 if (!wsink && !(strcmp(w->name, sink))) {
2619 wtsink = w;
2620 if (w->dapm == dapm)
2621 wsink = w;
2622 continue;
2623 }
2624 if (!wsource && !(strcmp(w->name, source))) {
2625 wtsource = w;
2626 if (w->dapm == dapm)
2627 wsource = w;
2628 }
2629 }
2630 /* use widget from another DAPM context if not found from this */
2631 if (!wsink)
2632 wsink = wtsink;
2633 if (!wsource)
2634 wsource = wtsource;
2635
2636 if (wsource == NULL) {
2637 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2638 route->source);
2639 return -ENODEV;
2640 }
2641 if (wsink == NULL) {
2642 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2643 route->sink);
2644 return -ENODEV;
2645 }
2646
2647 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2648 route->connected);
2649 if (ret)
2650 goto err;
2651
2652 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002653err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002654 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002655 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002656 return ret;
2657}
Mark Brown105f1c22008-05-13 14:52:19 +02002658
Mark Brownefcc3c62012-07-05 17:24:19 +01002659static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2660 const struct snd_soc_dapm_route *route)
2661{
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002662 struct snd_soc_dapm_widget *wsource, *wsink;
Mark Brownefcc3c62012-07-05 17:24:19 +01002663 struct snd_soc_dapm_path *path, *p;
2664 const char *sink;
2665 const char *source;
2666 char prefixed_sink[80];
2667 char prefixed_source[80];
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002668 const char *prefix;
Mark Brownefcc3c62012-07-05 17:24:19 +01002669
2670 if (route->control) {
2671 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002672 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002673 return -EINVAL;
2674 }
2675
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002676 prefix = soc_dapm_prefix(dapm);
2677 if (prefix) {
Mark Brownefcc3c62012-07-05 17:24:19 +01002678 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002679 prefix, route->sink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002680 sink = prefixed_sink;
2681 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02002682 prefix, route->source);
Mark Brownefcc3c62012-07-05 17:24:19 +01002683 source = prefixed_source;
2684 } else {
2685 sink = route->sink;
2686 source = route->source;
2687 }
2688
2689 path = NULL;
2690 list_for_each_entry(p, &dapm->card->paths, list) {
2691 if (strcmp(p->source->name, source) != 0)
2692 continue;
2693 if (strcmp(p->sink->name, sink) != 0)
2694 continue;
2695 path = p;
2696 break;
2697 }
2698
2699 if (path) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002700 wsource = path->source;
2701 wsink = path->sink;
2702
2703 dapm_mark_dirty(wsource, "Route removed");
2704 dapm_mark_dirty(wsink, "Route removed");
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02002705 if (path->connect)
2706 dapm_path_invalidate(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002707
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002708 dapm_free_path(path);
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02002709
2710 /* Update any path related flags */
2711 dapm_update_widget_flags(wsource);
2712 dapm_update_widget_flags(wsink);
Mark Brownefcc3c62012-07-05 17:24:19 +01002713 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002714 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002715 source, sink);
2716 }
2717
2718 return 0;
2719}
2720
Mark Brown105f1c22008-05-13 14:52:19 +02002721/**
Mark Brown105f1c22008-05-13 14:52:19 +02002722 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002723 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002724 * @route: audio routes
2725 * @num: number of routes
2726 *
2727 * Connects 2 dapm widgets together via a named audio path. The sink is
2728 * the widget receiving the audio signal, whilst the source is the sender
2729 * of the audio signal.
2730 *
2731 * Returns 0 for success else error. On error all resources can be freed
2732 * with a call to snd_soc_card_free().
2733 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002734int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002735 const struct snd_soc_dapm_route *route, int num)
2736{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002737 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002738
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002739 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002740 for (i = 0; i < num; i++) {
Lars-Peter Clausena4e91542014-05-07 16:20:25 +02002741 r = snd_soc_dapm_add_route(dapm, route);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002742 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002743 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2744 route->source,
2745 route->control ? route->control : "direct",
2746 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002747 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002748 }
2749 route++;
2750 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002751 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002752
Dan Carpenter60884c22012-04-13 22:25:43 +03002753 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002754}
2755EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2756
Mark Brownefcc3c62012-07-05 17:24:19 +01002757/**
2758 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2759 * @dapm: DAPM context
2760 * @route: audio routes
2761 * @num: number of routes
2762 *
2763 * Removes routes from the DAPM context.
2764 */
2765int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2766 const struct snd_soc_dapm_route *route, int num)
2767{
2768 int i, ret = 0;
2769
2770 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2771 for (i = 0; i < num; i++) {
2772 snd_soc_dapm_del_route(dapm, route);
2773 route++;
2774 }
2775 mutex_unlock(&dapm->card->dapm_mutex);
2776
2777 return ret;
2778}
2779EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2780
Mark Brownbf3a9e12011-06-13 16:42:29 +01002781static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2782 const struct snd_soc_dapm_route *route)
2783{
2784 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2785 route->source,
2786 true);
2787 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2788 route->sink,
2789 true);
2790 struct snd_soc_dapm_path *path;
2791 int count = 0;
2792
2793 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002794 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002795 route->source);
2796 return -ENODEV;
2797 }
2798
2799 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002800 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002801 route->sink);
2802 return -ENODEV;
2803 }
2804
2805 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002806 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002807 route->source, route->sink);
2808
2809 list_for_each_entry(path, &source->sinks, list_source) {
2810 if (path->sink == sink) {
2811 path->weak = 1;
2812 count++;
2813 }
2814 }
2815
2816 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002817 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002818 route->source, route->sink);
2819 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002820 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002821 count, route->source, route->sink);
2822
2823 return 0;
2824}
2825
2826/**
2827 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2828 * @dapm: DAPM context
2829 * @route: audio routes
2830 * @num: number of routes
2831 *
2832 * Mark existing routes matching those specified in the passed array
2833 * as being weak, meaning that they are ignored for the purpose of
2834 * power decisions. The main intended use case is for sidetone paths
2835 * which couple audio between other independent paths if they are both
2836 * active in order to make the combination work better at the user
2837 * level but which aren't intended to be "used".
2838 *
2839 * Note that CODEC drivers should not use this as sidetone type paths
2840 * can frequently also be used as bypass paths.
2841 */
2842int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2843 const struct snd_soc_dapm_route *route, int num)
2844{
2845 int i, err;
2846 int ret = 0;
2847
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002848 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002849 for (i = 0; i < num; i++) {
2850 err = snd_soc_dapm_weak_route(dapm, route);
2851 if (err)
2852 ret = err;
2853 route++;
2854 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002855 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002856
2857 return ret;
2858}
2859EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2860
Mark Brown105f1c22008-05-13 14:52:19 +02002861/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002862 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002863 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002864 *
2865 * Checks the codec for any new dapm widgets and creates them if found.
2866 *
2867 * Returns 0 for success.
2868 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02002869int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002870{
2871 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002872 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002873
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002874 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002875
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002876 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002877 {
2878 if (w->new)
2879 continue;
2880
Stephen Warrenfad59882011-04-28 17:37:59 -06002881 if (w->num_kcontrols) {
2882 w->kcontrols = kzalloc(w->num_kcontrols *
2883 sizeof(struct snd_kcontrol *),
2884 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002885 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002886 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002887 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002888 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002889 }
2890
Richard Purdie2b97eab2006-10-06 18:32:18 +02002891 switch(w->id) {
2892 case snd_soc_dapm_switch:
2893 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002894 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002895 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002896 break;
2897 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02002898 case snd_soc_dapm_demux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002899 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002900 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002901 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002902 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002903 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002904 break;
Nikesh Oswalc6615082015-02-02 17:06:44 +00002905 case snd_soc_dapm_dai_link:
2906 dapm_new_dai_link(w);
2907 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002908 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002909 break;
2910 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002911
2912 /* Read the initial power state from the device */
2913 if (w->reg >= 0) {
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002914 soc_dapm_read(w->dapm, w->reg, &val);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08002915 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002916 val &= w->mask;
2917 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00002918 w->power = 1;
2919 }
2920
Richard Purdie2b97eab2006-10-06 18:32:18 +02002921 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002922
Mark Brown7508b122011-10-05 12:09:12 +01002923 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002924 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002925 }
2926
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002927 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2928 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002929 return 0;
2930}
2931EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2932
2933/**
2934 * snd_soc_dapm_get_volsw - dapm mixer get callback
2935 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002936 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002937 *
2938 * Callback to get the value of a dapm mixer control.
2939 *
2940 * Returns 0 for success.
2941 */
2942int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2943 struct snd_ctl_elem_value *ucontrol)
2944{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002945 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2946 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002947 struct soc_mixer_control *mc =
2948 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002949 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002950 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002951 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002952 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002953 unsigned int invert = mc->invert;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002954 unsigned int val;
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002955 int ret = 0;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002956
2957 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002958 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002959 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002960 kcontrol->id.name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002961
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002962 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002963 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) {
2964 ret = soc_dapm_read(dapm, reg, &val);
2965 val = (val >> shift) & mask;
2966 } else {
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002967 val = dapm_kcontrol_get_value(kcontrol);
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002968 }
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002969 mutex_unlock(&card->dapm_mutex);
2970
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002971 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002972 ucontrol->value.integer.value[0] = max - val;
2973 else
2974 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002975
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002976 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002977}
2978EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
2979
2980/**
2981 * snd_soc_dapm_put_volsw - dapm mixer set callback
2982 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002983 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002984 *
2985 * Callback to set the value of a dapm mixer control.
2986 *
2987 * Returns 0 for success.
2988 */
2989int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2990 struct snd_ctl_elem_value *ucontrol)
2991{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02002992 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
2993 struct snd_soc_card *card = dapm->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002994 struct soc_mixer_control *mc =
2995 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002996 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002997 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002998 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002999 unsigned int mask = (1 << fls(max)) - 1;
3000 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07003001 unsigned int val;
Jarkko Nikula18626c72014-06-09 14:20:29 +03003002 int connect, change, reg_change = 0;
Mark Brown97404f22010-12-14 16:13:57 +00003003 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003004 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003005
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003006 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003007 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003008 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02003009 kcontrol->id.name);
3010
Richard Purdie2b97eab2006-10-06 18:32:18 +02003011 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02003012 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003013
3014 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01003015 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003016
Liam Girdwood3cd04342012-03-09 12:02:08 +00003017 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003018
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003019 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown283375c2009-12-07 18:09:03 +00003020
Jarkko Nikula18626c72014-06-09 14:20:29 +03003021 if (reg != SND_SOC_NOPM) {
3022 mask = mask << shift;
3023 val = val << shift;
Lars-Peter Clausenc9e065c2014-05-04 19:17:05 +02003024
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003025 reg_change = soc_dapm_test_bits(dapm, reg, mask, val);
Jarkko Nikula18626c72014-06-09 14:20:29 +03003026 }
3027
3028 if (change || reg_change) {
3029 if (reg_change) {
3030 update.kcontrol = kcontrol;
3031 update.reg = reg;
3032 update.mask = mask;
3033 update.val = val;
3034 card->update = &update;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02003035 }
Jarkko Nikula18626c72014-06-09 14:20:29 +03003036 change |= reg_change;
Mark Brown97404f22010-12-14 16:13:57 +00003037
Nenghua Cao52765972013-12-13 20:13:49 +08003038 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Mark Brown97404f22010-12-14 16:13:57 +00003039
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003040 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00003041 }
3042
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003043 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003044
3045 if (ret > 0)
3046 soc_dpcm_runtime_update(card);
3047
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02003048 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003049}
3050EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
3051
3052/**
3053 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
3054 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003055 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003056 *
3057 * Callback to get the value of a dapm enumerated double mixer control.
3058 *
3059 * Returns 0 for success.
3060 */
3061int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
3062 struct snd_ctl_elem_value *ucontrol)
3063{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003064 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
Charles Keepax561ed682015-05-01 12:37:26 +01003065 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003066 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003067 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003068
Charles Keepax561ed682015-05-01 12:37:26 +01003069 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3070 if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003071 int ret = soc_dapm_read(dapm, e->reg, &reg_val);
Charles Keepax964a0b82015-05-08 10:50:10 +01003072 if (ret) {
3073 mutex_unlock(&card->dapm_mutex);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003074 return ret;
Charles Keepax964a0b82015-05-08 10:50:10 +01003075 }
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003076 } else {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003077 reg_val = dapm_kcontrol_get_value(kcontrol);
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003078 }
Charles Keepax561ed682015-05-01 12:37:26 +01003079 mutex_unlock(&card->dapm_mutex);
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003080
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003081 val = (reg_val >> e->shift_l) & e->mask;
3082 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
3083 if (e->shift_l != e->shift_r) {
3084 val = (reg_val >> e->shift_r) & e->mask;
3085 val = snd_soc_enum_val_to_item(e, val);
3086 ucontrol->value.enumerated.item[1] = val;
3087 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003088
Geert Uytterhoeven69128312014-08-08 17:29:35 +02003089 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003090}
3091EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
3092
3093/**
3094 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
3095 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00003096 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02003097 *
3098 * Callback to set the value of a dapm enumerated double mixer control.
3099 *
3100 * Returns 0 for success.
3101 */
3102int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
3103 struct snd_ctl_elem_value *ucontrol)
3104{
Lars-Peter Clausence0fc932014-06-16 18:13:06 +02003105 struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
3106 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003107 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003108 unsigned int *item = ucontrol->value.enumerated.item;
Charles Keepax561ed682015-05-01 12:37:26 +01003109 unsigned int val, change, reg_change = 0;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003110 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00003111 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08003112 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003113
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003114 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003115 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003116
3117 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003118 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003119 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003120 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003121 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003122 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02003123 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003124 }
3125
Liam Girdwood3cd04342012-03-09 12:02:08 +00003126 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06003127
Charles Keepax561ed682015-05-01 12:37:26 +01003128 change = dapm_kcontrol_set_value(kcontrol, val);
Mark Brown97404f22010-12-14 16:13:57 +00003129
Charles Keepax561ed682015-05-01 12:37:26 +01003130 if (e->reg != SND_SOC_NOPM)
3131 reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
3132
3133 if (change || reg_change) {
3134 if (reg_change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01003135 update.kcontrol = kcontrol;
3136 update.reg = e->reg;
3137 update.mask = mask;
3138 update.val = val;
3139 card->update = &update;
3140 }
Charles Keepax561ed682015-05-01 12:37:26 +01003141 change |= reg_change;
Mark Brown3a655772009-10-05 17:23:30 +01003142
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01003143 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01003144
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02003145 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06003146 }
3147
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003148 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08003149
3150 if (ret > 0)
3151 soc_dpcm_runtime_update(card);
3152
Mark Brown97404f22010-12-14 16:13:57 +00003153 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003154}
3155EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3156
3157/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003158 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3159 *
3160 * @kcontrol: mixer control
3161 * @uinfo: control element information
3162 *
3163 * Callback to provide information about a pin switch control.
3164 */
3165int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3166 struct snd_ctl_elem_info *uinfo)
3167{
3168 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3169 uinfo->count = 1;
3170 uinfo->value.integer.min = 0;
3171 uinfo->value.integer.max = 1;
3172
3173 return 0;
3174}
3175EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3176
3177/**
3178 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3179 *
3180 * @kcontrol: mixer control
3181 * @ucontrol: Value
3182 */
3183int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3184 struct snd_ctl_elem_value *ucontrol)
3185{
Mark Brown48a8c392012-02-14 17:11:15 -08003186 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003187 const char *pin = (const char *)kcontrol->private_value;
3188
Liam Girdwood3cd04342012-03-09 12:02:08 +00003189 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003190
3191 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003192 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003193
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003194 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003195
3196 return 0;
3197}
3198EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3199
3200/**
3201 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3202 *
3203 * @kcontrol: mixer control
3204 * @ucontrol: Value
3205 */
3206int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3207 struct snd_ctl_elem_value *ucontrol)
3208{
Mark Brown48a8c392012-02-14 17:11:15 -08003209 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003210 const char *pin = (const char *)kcontrol->private_value;
3211
Mark Brown8b37dbd2009-02-28 21:14:20 +00003212 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003213 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003214 else
Mark Brown48a8c392012-02-14 17:11:15 -08003215 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003216
Mark Brown48a8c392012-02-14 17:11:15 -08003217 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003218 return 0;
3219}
3220EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3221
Mark Brown5ba06fc2012-02-16 11:07:13 -08003222static struct snd_soc_dapm_widget *
3223snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3224 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003225{
3226 struct snd_soc_dapm_widget *w;
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003227 const char *prefix;
Mark Brown62ea8742012-01-21 21:14:48 +00003228 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003229
3230 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003231 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003232
Mark Brown62ea8742012-01-21 21:14:48 +00003233 switch (w->id) {
3234 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003235 w->regulator = devm_regulator_get(dapm->dev, w->name);
3236 if (IS_ERR(w->regulator)) {
3237 ret = PTR_ERR(w->regulator);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003238 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003239 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003240 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003241 }
Mark Brown8784c772013-01-10 19:33:47 +00003242
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003243 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003244 ret = regulator_allow_bypass(w->regulator, true);
3245 if (ret != 0)
3246 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003247 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003248 w->name, ret);
3249 }
Mark Brown62ea8742012-01-21 21:14:48 +00003250 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003251 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003252#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003253 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003254 if (IS_ERR(w->clk)) {
3255 ret = PTR_ERR(w->clk);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003256 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003257 w->name, ret);
3258 return NULL;
3259 }
Mark Brownec029952012-06-04 08:16:20 +01003260#else
3261 return NULL;
3262#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003263 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003264 default:
3265 break;
3266 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003267
Lars-Peter Clausen94f99c82014-06-16 18:13:01 +02003268 prefix = soc_dapm_prefix(dapm);
3269 if (prefix)
3270 w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
Lars-Peter Clausen2b581072013-05-14 11:05:32 +02003271 else
3272 w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
3273
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003274 if (w->name == NULL) {
3275 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003276 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003277 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003278
Mark Brown7ca3a182011-10-08 14:04:50 +01003279 switch (w->id) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003280 case snd_soc_dapm_mic:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003281 w->is_source = 1;
3282 w->power_check = dapm_generic_check_power;
3283 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003284 case snd_soc_dapm_input:
3285 if (!dapm->card->fully_routed)
3286 w->is_source = 1;
3287 w->power_check = dapm_generic_check_power;
3288 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003289 case snd_soc_dapm_spk:
3290 case snd_soc_dapm_hp:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003291 w->is_sink = 1;
3292 w->power_check = dapm_generic_check_power;
3293 break;
Lars-Peter Clausen86d75002014-12-21 11:05:44 +01003294 case snd_soc_dapm_output:
3295 if (!dapm->card->fully_routed)
3296 w->is_sink = 1;
3297 w->power_check = dapm_generic_check_power;
3298 break;
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003299 case snd_soc_dapm_vmid:
3300 case snd_soc_dapm_siggen:
3301 w->is_source = 1;
3302 w->power_check = dapm_always_on_check_power;
3303 break;
3304 case snd_soc_dapm_mux:
Lars-Peter Clausend714f972015-05-01 18:02:43 +02003305 case snd_soc_dapm_demux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003306 case snd_soc_dapm_switch:
3307 case snd_soc_dapm_mixer:
3308 case snd_soc_dapm_mixer_named_ctl:
Mark Brown63c69a62013-07-18 22:03:01 +01003309 case snd_soc_dapm_adc:
3310 case snd_soc_dapm_aif_out:
3311 case snd_soc_dapm_dac:
3312 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003313 case snd_soc_dapm_pga:
3314 case snd_soc_dapm_out_drv:
Mark Brown7ca3a182011-10-08 14:04:50 +01003315 case snd_soc_dapm_micbias:
Mark Brown7ca3a182011-10-08 14:04:50 +01003316 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003317 case snd_soc_dapm_dai_link:
Lars-Peter Clausencdef2ad2014-10-20 19:36:38 +02003318 case snd_soc_dapm_dai_out:
3319 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003320 w->power_check = dapm_generic_check_power;
3321 break;
3322 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003323 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003324 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003325 case snd_soc_dapm_kcontrol:
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003326 w->is_supply = 1;
Mark Brown7ca3a182011-10-08 14:04:50 +01003327 w->power_check = dapm_supply_check_power;
3328 break;
3329 default:
3330 w->power_check = dapm_always_on_check_power;
3331 break;
3332 }
3333
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003334 w->dapm = dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003335 INIT_LIST_HEAD(&w->sources);
3336 INIT_LIST_HEAD(&w->sinks);
3337 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003338 INIT_LIST_HEAD(&w->dirty);
Lars-Peter Clausen92fa1242015-05-01 18:02:42 +02003339 list_add_tail(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003340
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003341 w->inputs = -1;
3342 w->outputs = -1;
3343
Richard Purdie2b97eab2006-10-06 18:32:18 +02003344 /* machine layer set ups unconnected pins and insertions */
3345 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003346 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003347}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003348
3349/**
Mark Brown4ba13272008-05-13 14:51:19 +02003350 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003351 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003352 * @widget: widget array
3353 * @num: number of widgets
3354 *
3355 * Creates new DAPM controls based upon the templates.
3356 *
3357 * Returns 0 for success else error.
3358 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003359int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003360 const struct snd_soc_dapm_widget *widget,
3361 int num)
3362{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003363 struct snd_soc_dapm_widget *w;
3364 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003365 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003366
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003367 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003368 for (i = 0; i < num; i++) {
Mark Brown5ba06fc2012-02-16 11:07:13 -08003369 w = snd_soc_dapm_new_control(dapm, widget);
3370 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003371 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003372 "ASoC: Failed to create DAPM control %s\n",
3373 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003374 ret = -ENOMEM;
3375 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003376 }
Mark Brown4ba13272008-05-13 14:51:19 +02003377 widget++;
3378 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003379 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003380 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003381}
3382EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3383
Mark Brownc74184e2012-04-04 22:12:09 +01003384static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3385 struct snd_kcontrol *kcontrol, int event)
3386{
3387 struct snd_soc_dapm_path *source_p, *sink_p;
3388 struct snd_soc_dai *source, *sink;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003389 const struct snd_soc_pcm_stream *config = w->params + w->params_select;
Mark Brownc74184e2012-04-04 22:12:09 +01003390 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003391 struct snd_pcm_hw_params *params = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003392 u64 fmt;
3393 int ret;
3394
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003395 if (WARN_ON(!config) ||
3396 WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
3397 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003398
3399 /* We only support a single source and sink, pick the first */
3400 source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
3401 list_sink);
3402 sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
3403 list_source);
3404
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003405 if (WARN_ON(!source_p || !sink_p) ||
3406 WARN_ON(!sink_p->source || !source_p->sink) ||
3407 WARN_ON(!source_p->source || !sink_p->sink))
3408 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003409
3410 source = source_p->source->priv;
3411 sink = sink_p->sink->priv;
3412
3413 /* Be a little careful as we don't want to overflow the mask array */
3414 if (config->formats) {
3415 fmt = ffs(config->formats) - 1;
3416 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003417 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003418 config->formats);
3419 fmt = 0;
3420 }
3421
3422 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003423 params = kzalloc(sizeof(*params), GFP_KERNEL);
3424 if (!params) {
3425 ret = -ENOMEM;
3426 goto out;
3427 }
3428 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003429
Mark Brown9747cec2012-04-26 19:12:21 +01003430 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003431 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003432 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003433 config->rate_max;
3434
Mark Brown9747cec2012-04-26 19:12:21 +01003435 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003436 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003437 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003438 = config->channels_max;
3439
3440 memset(&substream, 0, sizeof(substream));
3441
3442 switch (event) {
3443 case SND_SOC_DAPM_PRE_PMU:
Benoit Cousson93e69582014-07-08 23:19:38 +02003444 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3445 ret = soc_dai_hw_params(&substream, params, source);
3446 if (ret < 0)
3447 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003448
Benoit Cousson93e69582014-07-08 23:19:38 +02003449 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3450 ret = soc_dai_hw_params(&substream, params, sink);
3451 if (ret < 0)
3452 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003453 break;
3454
3455 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003456 ret = snd_soc_dai_digital_mute(sink, 0,
3457 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003458 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003459 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003460 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003461 break;
3462
3463 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003464 ret = snd_soc_dai_digital_mute(sink, 1,
3465 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003466 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003467 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003468 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003469 break;
3470
3471 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003472 WARN(1, "Unknown event %d\n", event);
Mark Brownc74184e2012-04-04 22:12:09 +01003473 return -EINVAL;
3474 }
3475
Mark Brown9747cec2012-04-26 19:12:21 +01003476out:
3477 kfree(params);
3478 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003479}
3480
Nikesh Oswalc6615082015-02-02 17:06:44 +00003481static int snd_soc_dapm_dai_link_get(struct snd_kcontrol *kcontrol,
3482 struct snd_ctl_elem_value *ucontrol)
3483{
3484 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3485
3486 ucontrol->value.integer.value[0] = w->params_select;
3487
3488 return 0;
3489}
3490
3491static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
3492 struct snd_ctl_elem_value *ucontrol)
3493{
3494 struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
3495
3496 /* Can't change the config when widget is already powered */
3497 if (w->power)
3498 return -EBUSY;
3499
3500 if (ucontrol->value.integer.value[0] == w->params_select)
3501 return 0;
3502
3503 if (ucontrol->value.integer.value[0] >= w->num_params)
3504 return -EINVAL;
3505
3506 w->params_select = ucontrol->value.integer.value[0];
3507
3508 return 0;
3509}
3510
Mark Brownc74184e2012-04-04 22:12:09 +01003511int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3512 const struct snd_soc_pcm_stream *params,
Nikesh Oswalc6615082015-02-02 17:06:44 +00003513 unsigned int num_params,
Mark Brownc74184e2012-04-04 22:12:09 +01003514 struct snd_soc_dapm_widget *source,
3515 struct snd_soc_dapm_widget *sink)
3516{
Mark Brownc74184e2012-04-04 22:12:09 +01003517 struct snd_soc_dapm_widget template;
3518 struct snd_soc_dapm_widget *w;
Mark Brownc74184e2012-04-04 22:12:09 +01003519 char *link_name;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003520 int ret, count;
3521 unsigned long private_value;
3522 const char **w_param_text;
3523 struct soc_enum w_param_enum[] = {
3524 SOC_ENUM_SINGLE(0, 0, 0, NULL),
3525 };
3526 struct snd_kcontrol_new kcontrol_dai_link[] = {
3527 SOC_ENUM_EXT(NULL, w_param_enum[0],
3528 snd_soc_dapm_dai_link_get,
3529 snd_soc_dapm_dai_link_put),
3530 };
3531 const struct snd_soc_pcm_stream *config = params;
Mark Brownc74184e2012-04-04 22:12:09 +01003532
Nikesh Oswalc6615082015-02-02 17:06:44 +00003533 w_param_text = devm_kcalloc(card->dev, num_params,
3534 sizeof(char *), GFP_KERNEL);
3535 if (!w_param_text)
Mark Brownc74184e2012-04-04 22:12:09 +01003536 return -ENOMEM;
Mark Brownc74184e2012-04-04 22:12:09 +01003537
Charles Keepax46172b62015-03-25 11:22:35 +00003538 link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
3539 source->name, sink->name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003540 if (!link_name) {
3541 ret = -ENOMEM;
3542 goto outfree_w_param;
3543 }
Mark Brownc74184e2012-04-04 22:12:09 +01003544
Nikesh Oswalc6615082015-02-02 17:06:44 +00003545 for (count = 0 ; count < num_params; count++) {
3546 if (!config->stream_name) {
3547 dev_warn(card->dapm.dev,
3548 "ASoC: anonymous config %d for dai link %s\n",
3549 count, link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003550 w_param_text[count] =
Charles Keepax46172b62015-03-25 11:22:35 +00003551 devm_kasprintf(card->dev, GFP_KERNEL,
3552 "Anonymous Configuration %d",
3553 count);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003554 if (!w_param_text[count]) {
3555 ret = -ENOMEM;
3556 goto outfree_link_name;
3557 }
Nikesh Oswalc6615082015-02-02 17:06:44 +00003558 } else {
3559 w_param_text[count] = devm_kmemdup(card->dev,
3560 config->stream_name,
3561 strlen(config->stream_name) + 1,
3562 GFP_KERNEL);
3563 if (!w_param_text[count]) {
3564 ret = -ENOMEM;
3565 goto outfree_link_name;
3566 }
3567 }
3568 config++;
3569 }
3570 w_param_enum[0].items = num_params;
3571 w_param_enum[0].texts = w_param_text;
Mark Brownc74184e2012-04-04 22:12:09 +01003572
3573 memset(&template, 0, sizeof(template));
3574 template.reg = SND_SOC_NOPM;
3575 template.id = snd_soc_dapm_dai_link;
3576 template.name = link_name;
3577 template.event = snd_soc_dai_link_event;
3578 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3579 SND_SOC_DAPM_PRE_PMD;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003580 template.num_kcontrols = 1;
3581 /* duplicate w_param_enum on heap so that memory persists */
3582 private_value =
3583 (unsigned long) devm_kmemdup(card->dev,
3584 (void *)(kcontrol_dai_link[0].private_value),
3585 sizeof(struct soc_enum), GFP_KERNEL);
3586 if (!private_value) {
3587 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3588 link_name);
3589 ret = -ENOMEM;
3590 goto outfree_link_name;
3591 }
3592 kcontrol_dai_link[0].private_value = private_value;
3593 /* duplicate kcontrol_dai_link on heap so that memory persists */
3594 template.kcontrol_news =
3595 devm_kmemdup(card->dev, &kcontrol_dai_link[0],
3596 sizeof(struct snd_kcontrol_new),
3597 GFP_KERNEL);
3598 if (!template.kcontrol_news) {
3599 dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
3600 link_name);
3601 ret = -ENOMEM;
3602 goto outfree_private_value;
3603 }
Mark Brownc74184e2012-04-04 22:12:09 +01003604
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003605 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003606
3607 w = snd_soc_dapm_new_control(&card->dapm, &template);
3608 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003609 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003610 link_name);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003611 ret = -ENOMEM;
3612 goto outfree_kcontrol_news;
Mark Brownc74184e2012-04-04 22:12:09 +01003613 }
3614
3615 w->params = params;
Nikesh Oswalc6615082015-02-02 17:06:44 +00003616 w->num_params = num_params;
Mark Brownc74184e2012-04-04 22:12:09 +01003617
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003618 ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL);
3619 if (ret)
Nikesh Oswalc6615082015-02-02 17:06:44 +00003620 goto outfree_w;
Lars-Peter Clausenfe838972014-05-07 16:20:27 +02003621 return snd_soc_dapm_add_path(&card->dapm, w, sink, NULL, NULL);
Nikesh Oswalc6615082015-02-02 17:06:44 +00003622
3623outfree_w:
3624 devm_kfree(card->dev, w);
3625outfree_kcontrol_news:
3626 devm_kfree(card->dev, (void *)template.kcontrol_news);
3627outfree_private_value:
3628 devm_kfree(card->dev, (void *)private_value);
3629outfree_link_name:
3630 devm_kfree(card->dev, link_name);
3631outfree_w_param:
3632 for (count = 0 ; count < num_params; count++)
3633 devm_kfree(card->dev, (void *)w_param_text[count]);
3634 devm_kfree(card->dev, w_param_text);
3635
3636 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003637}
3638
Mark Brown888df392012-02-16 19:37:51 -08003639int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3640 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003641{
Mark Brown888df392012-02-16 19:37:51 -08003642 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003643 struct snd_soc_dapm_widget *w;
3644
Mark Brown888df392012-02-16 19:37:51 -08003645 WARN_ON(dapm->dev != dai->dev);
3646
3647 memset(&template, 0, sizeof(template));
3648 template.reg = SND_SOC_NOPM;
3649
3650 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003651 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003652 template.name = dai->driver->playback.stream_name;
3653 template.sname = dai->driver->playback.stream_name;
3654
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003655 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003656 template.name);
3657
3658 w = snd_soc_dapm_new_control(dapm, &template);
3659 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003660 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003661 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003662 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003663 }
3664
3665 w->priv = dai;
3666 dai->playback_widget = w;
3667 }
3668
3669 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003670 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003671 template.name = dai->driver->capture.stream_name;
3672 template.sname = dai->driver->capture.stream_name;
3673
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003674 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003675 template.name);
3676
3677 w = snd_soc_dapm_new_control(dapm, &template);
3678 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003679 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003680 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003681 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003682 }
3683
3684 w->priv = dai;
3685 dai->capture_widget = w;
3686 }
3687
3688 return 0;
3689}
3690
3691int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3692{
3693 struct snd_soc_dapm_widget *dai_w, *w;
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003694 struct snd_soc_dapm_widget *src, *sink;
Mark Brown888df392012-02-16 19:37:51 -08003695 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003696
3697 /* For each DAI widget... */
3698 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003699 switch (dai_w->id) {
3700 case snd_soc_dapm_dai_in:
3701 case snd_soc_dapm_dai_out:
3702 break;
3703 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003704 continue;
Mark Brown46162742013-06-05 19:36:11 +01003705 }
Mark Brown888df392012-02-16 19:37:51 -08003706
3707 dai = dai_w->priv;
3708
3709 /* ...find all widgets with the same stream and link them */
3710 list_for_each_entry(w, &card->widgets, list) {
3711 if (w->dapm != dai_w->dapm)
3712 continue;
3713
Mark Brown46162742013-06-05 19:36:11 +01003714 switch (w->id) {
3715 case snd_soc_dapm_dai_in:
3716 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08003717 continue;
Mark Brown46162742013-06-05 19:36:11 +01003718 default:
3719 break;
3720 }
Mark Brown888df392012-02-16 19:37:51 -08003721
Russell King19c2c5f2013-08-04 20:24:03 +01003722 if (!w->sname || !strstr(w->sname, dai_w->name))
Mark Brown888df392012-02-16 19:37:51 -08003723 continue;
3724
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003725 if (dai_w->id == snd_soc_dapm_dai_in) {
3726 src = dai_w;
3727 sink = w;
3728 } else {
3729 src = w;
3730 sink = dai_w;
Mark Brown888df392012-02-16 19:37:51 -08003731 }
Lars-Peter Clausen0f9bd7b2014-05-07 16:20:28 +02003732 dev_dbg(dai->dev, "%s -> %s\n", src->name, sink->name);
3733 snd_soc_dapm_add_path(w->dapm, src, sink, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003734 }
3735 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003736
Mark Brown888df392012-02-16 19:37:51 -08003737 return 0;
3738}
Liam Girdwood64a648c2011-07-25 11:15:15 +01003739
Benoit Cousson44ba2642014-07-08 23:19:36 +02003740static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
3741 struct snd_soc_pcm_runtime *rtd)
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003742{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003743 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003744 struct snd_soc_dapm_widget *sink, *source;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003745 int i;
3746
Benoit Cousson44ba2642014-07-08 23:19:36 +02003747 for (i = 0; i < rtd->num_codecs; i++) {
3748 struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003749
3750 /* there is no point in connecting BE DAI links with dummies */
3751 if (snd_soc_dai_is_dummy(codec_dai) ||
3752 snd_soc_dai_is_dummy(cpu_dai))
3753 continue;
3754
3755 /* connect BE DAI playback if widgets are valid */
3756 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003757 source = cpu_dai->playback_widget;
3758 sink = codec_dai->playback_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003759 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003760 cpu_dai->component->name, source->name,
3761 codec_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003762
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003763 snd_soc_dapm_add_path(&card->dapm, source, sink,
3764 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003765 }
3766
3767 /* connect BE DAI capture if widgets are valid */
3768 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003769 source = codec_dai->capture_widget;
3770 sink = cpu_dai->capture_widget;
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003771 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
Lars-Peter Clausenf4333202014-06-16 18:13:02 +02003772 codec_dai->component->name, source->name,
3773 cpu_dai->component->name, sink->name);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003774
Lars-Peter Clausen9887c202014-05-07 16:20:26 +02003775 snd_soc_dapm_add_path(&card->dapm, source, sink,
3776 NULL, NULL);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003777 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003778 }
3779}
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003780
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003781static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
3782 int event)
3783{
3784 struct snd_soc_dapm_widget *w;
3785
3786 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
3787 w = dai->playback_widget;
3788 else
3789 w = dai->capture_widget;
3790
3791 if (w) {
3792 dapm_mark_dirty(w, "stream event");
3793
3794 switch (event) {
3795 case SND_SOC_DAPM_STREAM_START:
3796 w->active = 1;
3797 break;
3798 case SND_SOC_DAPM_STREAM_STOP:
3799 w->active = 0;
3800 break;
3801 case SND_SOC_DAPM_STREAM_SUSPEND:
3802 case SND_SOC_DAPM_STREAM_RESUME:
3803 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3804 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3805 break;
3806 }
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003807
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003808 if (w->id == snd_soc_dapm_dai_in) {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003809 w->is_source = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003810 dapm_widget_invalidate_input_paths(w);
3811 } else {
Lars-Peter Clausen6dd98b02014-10-25 17:41:59 +02003812 w->is_sink = w->active;
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003813 dapm_widget_invalidate_output_paths(w);
3814 }
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003815 }
3816}
3817
Benoit Cousson44ba2642014-07-08 23:19:36 +02003818void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3819{
3820 struct snd_soc_pcm_runtime *rtd = card->rtd;
3821 int i;
3822
3823 /* for each BE DAI link... */
3824 for (i = 0; i < card->num_rtd; i++) {
3825 rtd = &card->rtd[i];
3826
3827 /*
3828 * dynamic FE links have no fixed DAI mapping.
3829 * CODEC<->CODEC links have no direct connection.
3830 */
3831 if (rtd->dai_link->dynamic || rtd->dai_link->params)
3832 continue;
3833
3834 dapm_connect_dai_link_widgets(card, rtd);
3835 }
3836}
3837
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003838static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3839 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003840{
Benoit Cousson44ba2642014-07-08 23:19:36 +02003841 int i;
3842
Lars-Peter Clausenc471fdd2014-04-29 14:51:22 +02003843 soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event);
Benoit Cousson44ba2642014-07-08 23:19:36 +02003844 for (i = 0; i < rtd->num_codecs; i++)
3845 soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003846
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003847 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003848}
3849
3850/**
3851 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3852 * @rtd: PCM runtime data
3853 * @stream: stream name
3854 * @event: stream event
3855 *
3856 * Sends a stream event to the dapm core. The core then makes any
3857 * necessary widget power changes.
3858 *
3859 * Returns 0 for success else error.
3860 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003861void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3862 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003863{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003864 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003865
Liam Girdwood3cd04342012-03-09 12:02:08 +00003866 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003867 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003868 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003869}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003870
3871/**
Charles Keepax11391102014-02-18 15:22:14 +00003872 * snd_soc_dapm_enable_pin_unlocked - enable pin.
3873 * @dapm: DAPM context
3874 * @pin: pin name
3875 *
3876 * Enables input/output pin and its parents or children widgets iff there is
3877 * a valid audio route and active audio stream.
3878 *
3879 * Requires external locking.
3880 *
3881 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3882 * do any widget power switching.
3883 */
3884int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3885 const char *pin)
3886{
3887 return snd_soc_dapm_set_pin(dapm, pin, 1);
3888}
3889EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
3890
3891/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003892 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003893 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003894 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02003895 *
Mark Brown74b8f952009-06-06 11:26:15 +01003896 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01003897 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00003898 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003899 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3900 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02003901 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003902int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003903{
Charles Keepax11391102014-02-18 15:22:14 +00003904 int ret;
3905
3906 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3907
3908 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
3909
3910 mutex_unlock(&dapm->card->dapm_mutex);
3911
3912 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003913}
Liam Girdwooda5302182008-07-07 13:35:17 +01003914EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003915
3916/**
Charles Keepax11391102014-02-18 15:22:14 +00003917 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
3918 * @dapm: DAPM context
3919 * @pin: pin name
3920 *
3921 * Enables input/output pin regardless of any other state. This is
3922 * intended for use with microphone bias supplies used in microphone
3923 * jack detection.
3924 *
3925 * Requires external locking.
3926 *
3927 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3928 * do any widget power switching.
3929 */
3930int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3931 const char *pin)
3932{
3933 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
3934
3935 if (!w) {
3936 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
3937 return -EINVAL;
3938 }
3939
3940 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
Lars-Peter Clausen92a99ea2014-10-25 17:42:03 +02003941 if (!w->connected) {
3942 /*
3943 * w->force does not affect the number of input or output paths,
3944 * so we only have to recheck if w->connected is changed
3945 */
3946 dapm_widget_invalidate_input_paths(w);
3947 dapm_widget_invalidate_output_paths(w);
3948 w->connected = 1;
3949 }
Charles Keepax11391102014-02-18 15:22:14 +00003950 w->force = 1;
3951 dapm_mark_dirty(w, "force enable");
3952
3953 return 0;
3954}
3955EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
3956
3957/**
Mark Brownda341832010-03-15 19:23:37 +00003958 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003959 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00003960 * @pin: pin name
3961 *
3962 * Enables input/output pin regardless of any other state. This is
3963 * intended for use with microphone bias supplies used in microphone
3964 * jack detection.
3965 *
3966 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3967 * do any widget power switching.
3968 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003969int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
3970 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00003971{
Charles Keepax11391102014-02-18 15:22:14 +00003972 int ret;
Mark Brownda341832010-03-15 19:23:37 +00003973
Charles Keepax11391102014-02-18 15:22:14 +00003974 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00003975
Charles Keepax11391102014-02-18 15:22:14 +00003976 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09003977
Charles Keepax11391102014-02-18 15:22:14 +00003978 mutex_unlock(&dapm->card->dapm_mutex);
3979
3980 return ret;
Mark Brownda341832010-03-15 19:23:37 +00003981}
3982EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
3983
3984/**
Charles Keepax11391102014-02-18 15:22:14 +00003985 * snd_soc_dapm_disable_pin_unlocked - disable pin.
3986 * @dapm: DAPM context
3987 * @pin: pin name
3988 *
3989 * Disables input/output pin and its parents or children widgets.
3990 *
3991 * Requires external locking.
3992 *
3993 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3994 * do any widget power switching.
3995 */
3996int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3997 const char *pin)
3998{
3999 return snd_soc_dapm_set_pin(dapm, pin, 0);
4000}
4001EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
4002
4003/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004004 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004005 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004006 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004007 *
Mark Brown74b8f952009-06-06 11:26:15 +01004008 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00004009 *
Liam Girdwooda5302182008-07-07 13:35:17 +01004010 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4011 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004012 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004013int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
4014 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01004015{
Charles Keepax11391102014-02-18 15:22:14 +00004016 int ret;
4017
4018 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4019
4020 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4021
4022 mutex_unlock(&dapm->card->dapm_mutex);
4023
4024 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01004025}
4026EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
4027
4028/**
Charles Keepax11391102014-02-18 15:22:14 +00004029 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
4030 * @dapm: DAPM context
4031 * @pin: pin name
4032 *
4033 * Marks the specified pin as being not connected, disabling it along
4034 * any parent or child widgets. At present this is identical to
4035 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4036 * additional things such as disabling controls which only affect
4037 * paths through the pin.
4038 *
4039 * Requires external locking.
4040 *
4041 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4042 * do any widget power switching.
4043 */
4044int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
4045 const char *pin)
4046{
4047 return snd_soc_dapm_set_pin(dapm, pin, 0);
4048}
4049EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
4050
4051/**
Mark Brown5817b522008-09-24 11:23:11 +01004052 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004053 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01004054 * @pin: pin name
4055 *
4056 * Marks the specified pin as being not connected, disabling it along
4057 * any parent or child widgets. At present this is identical to
4058 * snd_soc_dapm_disable_pin() but in future it will be extended to do
4059 * additional things such as disabling controls which only affect
4060 * paths through the pin.
4061 *
4062 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
4063 * do any widget power switching.
4064 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004065int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01004066{
Charles Keepax11391102014-02-18 15:22:14 +00004067 int ret;
4068
4069 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
4070
4071 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
4072
4073 mutex_unlock(&dapm->card->dapm_mutex);
4074
4075 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01004076}
4077EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
4078
4079/**
Liam Girdwooda5302182008-07-07 13:35:17 +01004080 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004081 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01004082 * @pin: audio signal pin endpoint (or start point)
4083 *
4084 * Get audio pin status - connected or disconnected.
4085 *
4086 * Returns 1 for connected otherwise 0.
4087 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004088int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
4089 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004090{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004091 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004092
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004093 if (w)
4094 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06004095
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004096 return 0;
4097}
Liam Girdwooda5302182008-07-07 13:35:17 +01004098EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02004099
4100/**
Mark Brown1547aba2010-05-07 21:11:40 +01004101 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004102 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01004103 * @pin: audio signal pin endpoint (or start point)
4104 *
4105 * Mark the given endpoint or pin as ignoring suspend. When the
4106 * system is disabled a path between two endpoints flagged as ignoring
4107 * suspend will not be disabled. The path must already be enabled via
4108 * normal means at suspend time, it will not be turned on if it was not
4109 * already enabled.
4110 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004111int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
4112 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01004113{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004114 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01004115
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004116 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00004117 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004118 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01004119 }
4120
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02004121 w->ignore_suspend = 1;
4122
4123 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01004124}
4125EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
4126
Lars-Peter Clausencdc45082014-10-20 19:36:33 +02004127/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02004128 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03004129 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02004130 *
4131 * Free all dapm widgets and resources.
4132 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004133void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02004134{
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02004135 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004136 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02004137 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02004138}
4139EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
4140
Xiang Xiao57996352014-03-02 00:04:02 +08004141static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01004142{
Liam Girdwood01005a72012-07-06 16:57:05 +01004143 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01004144 struct snd_soc_dapm_widget *w;
4145 LIST_HEAD(down_list);
4146 int powerdown = 0;
4147
Liam Girdwood01005a72012-07-06 16:57:05 +01004148 mutex_lock(&card->dapm_mutex);
4149
Jarkko Nikula97c866d2010-12-14 12:18:31 +02004150 list_for_each_entry(w, &dapm->card->widgets, list) {
4151 if (w->dapm != dapm)
4152 continue;
Mark Brown51737472009-06-22 13:16:51 +01004153 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00004154 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01004155 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01004156 powerdown = 1;
4157 }
4158 }
4159
4160 /* If there were no widgets to power down we're already in
4161 * standby.
4162 */
4163 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00004164 if (dapm->bias_level == SND_SOC_BIAS_ON)
4165 snd_soc_dapm_set_bias_level(dapm,
4166 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02004167 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00004168 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
4169 snd_soc_dapm_set_bias_level(dapm,
4170 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01004171 }
Liam Girdwood01005a72012-07-06 16:57:05 +01004172
4173 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004174}
Mark Brown51737472009-06-22 13:16:51 +01004175
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004176/*
4177 * snd_soc_dapm_shutdown - callback for system shutdown
4178 */
4179void snd_soc_dapm_shutdown(struct snd_soc_card *card)
4180{
Xiang Xiao57996352014-03-02 00:04:02 +08004181 struct snd_soc_dapm_context *dapm;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00004182
Xiang Xiao57996352014-03-02 00:04:02 +08004183 list_for_each_entry(dapm, &card->dapm_list, list) {
Xiang Xiao17282ba2014-03-02 00:04:03 +08004184 if (dapm != &card->dapm) {
4185 soc_dapm_shutdown_dapm(dapm);
4186 if (dapm->bias_level == SND_SOC_BIAS_STANDBY)
4187 snd_soc_dapm_set_bias_level(dapm,
4188 SND_SOC_BIAS_OFF);
4189 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +02004190 }
Xiang Xiao17282ba2014-03-02 00:04:03 +08004191
4192 soc_dapm_shutdown_dapm(&card->dapm);
4193 if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY)
4194 snd_soc_dapm_set_bias_level(&card->dapm,
4195 SND_SOC_BIAS_OFF);
Mark Brown51737472009-06-22 13:16:51 +01004196}
4197
Richard Purdie2b97eab2006-10-06 18:32:18 +02004198/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01004199MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02004200MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4201MODULE_LICENSE("GPL");