blob: c07c7fb7593a86f4b7577a5c2b1cb560d83a4c6e [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,
Mark Brown1dd275b2013-10-09 13:56:37 +010073 [snd_soc_dapm_dac] = 7,
74 [snd_soc_dapm_switch] = 8,
75 [snd_soc_dapm_mixer] = 8,
76 [snd_soc_dapm_mixer_named_ctl] = 8,
77 [snd_soc_dapm_pga] = 9,
78 [snd_soc_dapm_adc] = 10,
79 [snd_soc_dapm_out_drv] = 11,
80 [snd_soc_dapm_hp] = 11,
81 [snd_soc_dapm_spk] = 11,
82 [snd_soc_dapm_line] = 11,
83 [snd_soc_dapm_kcontrol] = 12,
84 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +020085};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000086
Richard Purdie2b97eab2006-10-06 18:32:18 +020087static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010088 [snd_soc_dapm_pre] = 0,
Lars-Peter Clausen57295072013-08-05 11:27:31 +020089 [snd_soc_dapm_kcontrol] = 1,
90 [snd_soc_dapm_adc] = 2,
91 [snd_soc_dapm_hp] = 3,
92 [snd_soc_dapm_spk] = 3,
93 [snd_soc_dapm_line] = 3,
94 [snd_soc_dapm_out_drv] = 3,
Mark Brown38357ab2009-06-06 19:03:23 +010095 [snd_soc_dapm_pga] = 4,
Lars-Peter Clausenefc77e32013-06-14 13:16:50 +020096 [snd_soc_dapm_switch] = 5,
Mark Brown38357ab2009-06-06 19:03:23 +010097 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +010098 [snd_soc_dapm_mixer] = 5,
99 [snd_soc_dapm_dac] = 6,
100 [snd_soc_dapm_mic] = 7,
101 [snd_soc_dapm_micbias] = 8,
102 [snd_soc_dapm_mux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +0100103 [snd_soc_dapm_aif_in] = 10,
104 [snd_soc_dapm_aif_out] = 10,
Mark Brown46162742013-06-05 19:36:11 +0100105 [snd_soc_dapm_dai_in] = 10,
106 [snd_soc_dapm_dai_out] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +0100107 [snd_soc_dapm_dai_link] = 11,
Mark Brownc74184e2012-04-04 22:12:09 +0100108 [snd_soc_dapm_supply] = 12,
Mark Brown1dd275b2013-10-09 13:56:37 +0100109 [snd_soc_dapm_clock_supply] = 13,
110 [snd_soc_dapm_regulator_supply] = 13,
111 [snd_soc_dapm_post] = 14,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200112};
113
Troy Kisky12ef1932008-10-13 17:42:14 -0700114static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100115{
116 if (pop_time)
117 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
118}
119
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200120static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100121{
122 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200123 char *buf;
124
125 if (!pop_time)
126 return;
127
128 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
129 if (buf == NULL)
130 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100131
132 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200133 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100134 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100135 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200136
137 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100138}
139
Mark Browndb432b42011-10-03 21:06:40 +0100140static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
141{
142 return !list_empty(&w->dirty);
143}
144
Mark Brown25c77c52011-10-08 13:36:03 +0100145void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100146{
Mark Brown75c1f892011-10-04 22:28:08 +0100147 if (!dapm_dirty_widget(w)) {
148 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
149 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100150 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100151 }
Mark Browndb432b42011-10-03 21:06:40 +0100152}
Mark Brown25c77c52011-10-08 13:36:03 +0100153EXPORT_SYMBOL_GPL(dapm_mark_dirty);
Mark Browndb432b42011-10-03 21:06:40 +0100154
Mark Browne2d32ff2012-08-31 17:38:32 -0700155void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm)
156{
157 struct snd_soc_card *card = dapm->card;
158 struct snd_soc_dapm_widget *w;
159
160 mutex_lock(&card->dapm_mutex);
161
162 list_for_each_entry(w, &card->widgets, list) {
163 switch (w->id) {
164 case snd_soc_dapm_input:
165 case snd_soc_dapm_output:
166 dapm_mark_dirty(w, "Rechecking inputs and outputs");
167 break;
168 default:
169 break;
170 }
171 }
172
173 mutex_unlock(&card->dapm_mutex);
174}
175EXPORT_SYMBOL_GPL(dapm_mark_io_dirty);
176
Richard Purdie2b97eab2006-10-06 18:32:18 +0200177/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100178static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200179 const struct snd_soc_dapm_widget *_widget)
180{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100181 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200182}
183
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200184struct dapm_kcontrol_data {
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200185 unsigned int value;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200186 struct snd_soc_dapm_widget *widget;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200187 struct list_head paths;
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200188 struct snd_soc_dapm_widget_list *wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200189};
190
191static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
192 struct snd_kcontrol *kcontrol)
193{
194 struct dapm_kcontrol_data *data;
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200195 struct soc_mixer_control *mc;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200196
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200197 data = kzalloc(sizeof(*data), GFP_KERNEL);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200198 if (!data) {
199 dev_err(widget->dapm->dev,
200 "ASoC: can't allocate kcontrol data for %s\n",
201 widget->name);
202 return -ENOMEM;
203 }
204
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200205 INIT_LIST_HEAD(&data->paths);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200206
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200207 switch (widget->id) {
208 case snd_soc_dapm_switch:
209 case snd_soc_dapm_mixer:
210 case snd_soc_dapm_mixer_named_ctl:
211 mc = (struct soc_mixer_control *)kcontrol->private_value;
212
213 if (mc->autodisable) {
214 struct snd_soc_dapm_widget template;
215
216 memset(&template, 0, sizeof(template));
217 template.reg = mc->reg;
218 template.mask = (1 << fls(mc->max)) - 1;
219 template.shift = mc->shift;
220 if (mc->invert)
221 template.off_val = mc->max;
222 else
223 template.off_val = 0;
224 template.on_val = template.off_val;
225 template.id = snd_soc_dapm_kcontrol;
226 template.name = kcontrol->id.name;
227
Lars-Peter Clausen2daabd72013-08-30 17:39:33 +0200228 data->value = template.on_val;
229
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200230 data->widget = snd_soc_dapm_new_control(widget->dapm,
231 &template);
232 if (!data->widget) {
233 kfree(data);
234 return -ENOMEM;
235 }
236 }
237 break;
238 default:
239 break;
240 }
241
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200242 kcontrol->private_data = data;
243
244 return 0;
245}
246
247static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
248{
249 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200250 kfree(data->widget);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200251 kfree(data->wlist);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200252 kfree(data);
253}
254
255static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
256 const struct snd_kcontrol *kcontrol)
257{
258 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
259
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200260 return data->wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200261}
262
263static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
264 struct snd_soc_dapm_widget *widget)
265{
266 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200267 struct snd_soc_dapm_widget_list *new_wlist;
268 unsigned int n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200269
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200270 if (data->wlist)
271 n = data->wlist->num_widgets + 1;
272 else
273 n = 1;
274
275 new_wlist = krealloc(data->wlist,
276 sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
277 if (!new_wlist)
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200278 return -ENOMEM;
279
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200280 new_wlist->widgets[n - 1] = widget;
281 new_wlist->num_widgets = n;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200282
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200283 data->wlist = new_wlist;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200284
285 return 0;
286}
287
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200288static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
289 struct snd_soc_dapm_path *path)
290{
291 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
292
293 list_add_tail(&path->list_kcontrol, &data->paths);
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200294
295 if (data->widget) {
296 snd_soc_dapm_add_path(data->widget->dapm, data->widget,
297 path->source, NULL, NULL);
298 }
299}
300
301static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
302{
303 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
304
305 if (!data->widget)
306 return true;
307
308 return data->widget->power;
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200309}
310
311static struct list_head *dapm_kcontrol_get_path_list(
312 const struct snd_kcontrol *kcontrol)
313{
314 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
315
316 return &data->paths;
317}
318
319#define dapm_kcontrol_for_each_path(path, kcontrol) \
320 list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
321 list_kcontrol)
322
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200323static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
324{
325 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
326
327 return data->value;
328}
329
330static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
331 unsigned int value)
332{
333 struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
334
335 if (data->value == value)
336 return false;
337
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200338 if (data->widget)
339 data->widget->on_val = value;
340
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +0200341 data->value = value;
342
343 return true;
344}
345
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200346/**
347 * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
348 * @kcontrol: The kcontrol
349 */
350struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol)
351{
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200352 return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec;
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +0200353}
354EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
355
Liam Girdwood6c120e12012-02-15 15:15:34 +0000356static void dapm_reset(struct snd_soc_card *card)
357{
358 struct snd_soc_dapm_widget *w;
359
360 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
361
362 list_for_each_entry(w, &card->widgets, list) {
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +0200363 w->new_power = w->power;
Liam Girdwood6c120e12012-02-15 15:15:34 +0000364 w->power_checked = false;
365 w->inputs = -1;
366 w->outputs = -1;
367 }
368}
369
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800370static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg,
371 unsigned int *value)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100372{
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800373 if (w->codec) {
374 *value = snd_soc_read(w->codec, reg);
375 return 0;
376 } else if (w->platform) {
377 *value = snd_soc_platform_read(w->platform, reg);
378 return 0;
379 }
Liam Girdwoodb7950642011-07-04 22:10:52 +0100380
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000381 dev_err(w->dapm->dev, "ASoC: no valid widget read method\n");
Liam Girdwoodb7950642011-07-04 22:10:52 +0100382 return -1;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100383}
384
Lars-Peter Clausen30ac6b62014-02-13 14:14:21 +0100385static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg,
386 unsigned int val)
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100387{
388 if (w->codec)
389 return snd_soc_write(w->codec, reg, val);
Liam Girdwoodb7950642011-07-04 22:10:52 +0100390 else if (w->platform)
391 return snd_soc_platform_write(w->platform, reg, val);
392
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000393 dev_err(w->dapm->dev, "ASoC: no valid widget write method\n");
Liam Girdwoodb7950642011-07-04 22:10:52 +0100394 return -1;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100395}
396
Liam Girdwood49575fb52012-03-06 18:16:19 +0000397static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
398{
Mark Browne06ab3b2012-03-06 23:58:22 +0000399 if (w->codec && !w->codec->using_regmap)
Liam Girdwood49575fb52012-03-06 18:16:19 +0000400 mutex_lock(&w->codec->mutex);
401 else if (w->platform)
402 mutex_lock(&w->platform->mutex);
403}
404
405static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
406{
Mark Browne06ab3b2012-03-06 23:58:22 +0000407 if (w->codec && !w->codec->using_regmap)
Liam Girdwood49575fb52012-03-06 18:16:19 +0000408 mutex_unlock(&w->codec->mutex);
409 else if (w->platform)
410 mutex_unlock(&w->platform->mutex);
411}
412
Mark Browneb270e92013-10-09 13:52:52 +0100413static void soc_dapm_async_complete(struct snd_soc_dapm_context *dapm)
414{
415 if (dapm->codec && dapm->codec->using_regmap)
416 regmap_async_complete(dapm->codec->control_data);
417}
418
Liam Girdwood49575fb52012-03-06 18:16:19 +0000419static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100420 unsigned short reg, unsigned int mask, unsigned int value)
421{
Mark Brown8a713da2011-12-03 12:33:55 +0000422 bool change;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100423 unsigned int old, new;
424 int ret;
425
Mark Brown8a713da2011-12-03 12:33:55 +0000426 if (w->codec && w->codec->using_regmap) {
Mark Browneb270e92013-10-09 13:52:52 +0100427 ret = regmap_update_bits_check_async(w->codec->control_data,
428 reg, mask, value,
429 &change);
Mark Brown8a713da2011-12-03 12:33:55 +0000430 if (ret != 0)
431 return ret;
432 } else {
Liam Girdwood49575fb52012-03-06 18:16:19 +0000433 soc_widget_lock(w);
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800434 ret = soc_widget_read(w, reg, &old);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000435 if (ret < 0) {
436 soc_widget_unlock(w);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100437 return ret;
Liam Girdwood49575fb52012-03-06 18:16:19 +0000438 }
Mark Brown8a713da2011-12-03 12:33:55 +0000439
Mark Brown8a713da2011-12-03 12:33:55 +0000440 new = (old & ~mask) | (value & mask);
441 change = old != new;
442 if (change) {
443 ret = soc_widget_write(w, reg, new);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000444 if (ret < 0) {
445 soc_widget_unlock(w);
Mark Brown8a713da2011-12-03 12:33:55 +0000446 return ret;
Liam Girdwood49575fb52012-03-06 18:16:19 +0000447 }
Mark Brown8a713da2011-12-03 12:33:55 +0000448 }
Liam Girdwood49575fb52012-03-06 18:16:19 +0000449 soc_widget_unlock(w);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100450 }
451
452 return change;
453}
454
Mark Brown452c5ea2009-05-17 21:41:23 +0100455/**
456 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800457 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100458 * @level: level to configure
459 *
460 * Configure the bias (power) levels for the SoC audio device.
461 *
462 * Returns 0 for success else error.
463 */
Mark Browned5a4c42011-02-18 11:12:42 -0800464static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200465 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100466{
Mark Browned5a4c42011-02-18 11:12:42 -0800467 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100468 int ret = 0;
469
Mark Brown84e90932010-11-04 00:07:02 -0400470 trace_snd_soc_bias_level_start(card, level);
471
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000472 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100473 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100474 if (ret != 0)
475 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100476
Mark Browncc4c6702011-06-06 19:03:34 +0100477 if (dapm->codec) {
478 if (dapm->codec->driver->set_bias_level)
479 ret = dapm->codec->driver->set_bias_level(dapm->codec,
480 level);
Mark Brownd8c3bb92012-08-23 18:10:42 +0100481 else
482 dapm->bias_level = level;
Mark Brown4e872a42012-08-23 18:20:49 +0100483 } else if (!card || dapm != &card->dapm) {
Liam Girdwood41231282012-07-06 16:56:16 +0100484 dapm->bias_level = level;
Mark Brown4e872a42012-08-23 18:20:49 +0100485 }
Liam Girdwood41231282012-07-06 16:56:16 +0100486
Mark Brown171ec6b2011-06-06 18:15:19 +0100487 if (ret != 0)
488 goto out;
489
490 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100491 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100492out:
Mark Brown84e90932010-11-04 00:07:02 -0400493 trace_snd_soc_bias_level_done(card, level);
494
Mark Brown452c5ea2009-05-17 21:41:23 +0100495 return ret;
496}
497
Richard Purdie2b97eab2006-10-06 18:32:18 +0200498/* set up initial codec paths */
499static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
500 struct snd_soc_dapm_path *p, int i)
501{
502 switch (w->id) {
503 case snd_soc_dapm_switch:
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000504 case snd_soc_dapm_mixer:
505 case snd_soc_dapm_mixer_named_ctl: {
Lars-Peter Clausen30ac6b62014-02-13 14:14:21 +0100506 unsigned int val;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100507 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Stephen Warren82cfecd2011-04-28 17:37:58 -0600508 w->kcontrol_news[i].private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +0200509 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400510 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100511 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400512 unsigned int mask = (1 << fls(max)) - 1;
513 unsigned int invert = mc->invert;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200514
Lars-Peter Clausen249ce132013-10-06 13:43:49 +0200515 if (reg != SND_SOC_NOPM) {
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -0800516 soc_widget_read(w, reg, &val);
Lars-Peter Clausen249ce132013-10-06 13:43:49 +0200517 val = (val >> shift) & mask;
518 if (invert)
519 val = max - val;
520 p->connect = !!val;
521 } else {
522 p->connect = 0;
523 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200524
Richard Purdie2b97eab2006-10-06 18:32:18 +0200525 }
526 break;
527 case snd_soc_dapm_mux: {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600528 struct soc_enum *e = (struct soc_enum *)
529 w->kcontrol_news[i].private_value;
Lars-Peter Clausen30ac6b62014-02-13 14:14:21 +0100530 unsigned int val, item;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200531
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +0100532 if (e->reg != SND_SOC_NOPM) {
533 soc_widget_read(w, e->reg, &val);
534 val = (val >> e->shift_l) & e->mask;
535 item = snd_soc_enum_val_to_item(e, val);
536 } else {
537 /* since a virtual mux has no backing registers to
538 * decide which path to connect, it will try to match
539 * with the first enumeration. This is to ensure
540 * that the default mux choice (the first) will be
541 * correctly powered up during initialization.
542 */
543 item = 0;
544 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200545
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100546 if (item < e->items && !strcmp(p->name, e->texts[item]))
Lars-Peter Clausen58fee772013-06-14 13:16:52 +0200547 p->connect = 1;
548 else
549 p->connect = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200550 }
551 break;
Mark Brown56563102011-10-03 22:41:09 +0100552 /* does not affect routing - always connected */
Richard Purdie2b97eab2006-10-06 18:32:18 +0200553 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -0600554 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200555 case snd_soc_dapm_output:
556 case snd_soc_dapm_adc:
557 case snd_soc_dapm_input:
Mark Brown1ab97c82011-11-27 16:21:51 +0000558 case snd_soc_dapm_siggen:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200559 case snd_soc_dapm_dac:
560 case snd_soc_dapm_micbias:
561 case snd_soc_dapm_vmid:
Mark Brown246d0a12009-04-22 18:24:55 +0100562 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +0000563 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +0200564 case snd_soc_dapm_clock_supply:
Mark Brown010ff262009-08-17 17:39:22 +0100565 case snd_soc_dapm_aif_in:
566 case snd_soc_dapm_aif_out:
Mark Brown46162742013-06-05 19:36:11 +0100567 case snd_soc_dapm_dai_in:
568 case snd_soc_dapm_dai_out:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200569 case snd_soc_dapm_hp:
570 case snd_soc_dapm_mic:
571 case snd_soc_dapm_spk:
572 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +0100573 case snd_soc_dapm_dai_link:
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200574 case snd_soc_dapm_kcontrol:
Mark Brown56563102011-10-03 22:41:09 +0100575 p->connect = 1;
576 break;
577 /* does affect routing - dynamically connected */
Richard Purdie2b97eab2006-10-06 18:32:18 +0200578 case snd_soc_dapm_pre:
579 case snd_soc_dapm_post:
580 p->connect = 0;
581 break;
582 }
583}
584
Mark Brown74b8f952009-06-06 11:26:15 +0100585/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200586static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200587 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
588 struct snd_soc_dapm_path *path, const char *control_name,
589 const struct snd_kcontrol_new *kcontrol)
590{
591 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
592 int i;
593
Takashi Iwai9a8d38d2014-02-18 08:11:42 +0100594 for (i = 0; i < e->items; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200595 if (!(strcmp(control_name, e->texts[i]))) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200596 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200597 list_add(&path->list_sink, &dest->sources);
598 list_add(&path->list_source, &src->sinks);
599 path->name = (char*)e->texts[i];
600 dapm_set_path_status(dest, path, 0);
601 return 0;
602 }
603 }
604
605 return -ENODEV;
606}
607
Mark Brown74b8f952009-06-06 11:26:15 +0100608/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200609static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200610 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
611 struct snd_soc_dapm_path *path, const char *control_name)
612{
613 int i;
614
615 /* search for mixer kcontrol */
616 for (i = 0; i < dest->num_kcontrols; i++) {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600617 if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200618 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200619 list_add(&path->list_sink, &dest->sources);
620 list_add(&path->list_source, &src->sinks);
Stephen Warren82cfecd2011-04-28 17:37:58 -0600621 path->name = dest->kcontrol_news[i].name;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200622 dapm_set_path_status(dest, path, i);
623 return 0;
624 }
625 }
626 return -ENODEV;
627}
628
Stephen Warrenaf468002011-04-28 17:38:01 -0600629static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600630 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600631 const struct snd_kcontrol_new *kcontrol_new,
632 struct snd_kcontrol **kcontrol)
633{
634 struct snd_soc_dapm_widget *w;
635 int i;
636
637 *kcontrol = NULL;
638
639 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600640 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
641 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600642 for (i = 0; i < w->num_kcontrols; i++) {
643 if (&w->kcontrol_news[i] == kcontrol_new) {
644 if (w->kcontrols)
645 *kcontrol = w->kcontrols[i];
646 return 1;
647 }
648 }
649 }
650
651 return 0;
652}
653
Stephen Warren85762e72013-03-29 15:40:10 -0600654/*
655 * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
656 * create it. Either way, add the widget into the control's widget list
657 */
658static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
Mark Brown946d92a2013-08-12 23:28:42 +0100659 int kci)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200660{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200661 struct snd_soc_dapm_context *dapm = w->dapm;
Mark Brown12ea2c72011-03-02 18:17:32 +0000662 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000663 const char *prefix;
Stephen Warren85762e72013-03-29 15:40:10 -0600664 size_t prefix_len;
665 int shared;
666 struct snd_kcontrol *kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600667 bool wname_in_long_name, kcname_in_long_name;
Stephen Warren85762e72013-03-29 15:40:10 -0600668 char *long_name;
669 const char *name;
670 int ret;
Mark Brownefb7ac32011-03-08 17:23:24 +0000671
672 if (dapm->codec)
673 prefix = dapm->codec->name_prefix;
674 else
675 prefix = NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200676
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000677 if (prefix)
678 prefix_len = strlen(prefix) + 1;
679 else
680 prefix_len = 0;
681
Stephen Warren85762e72013-03-29 15:40:10 -0600682 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
683 &kcontrol);
684
Stephen Warren85762e72013-03-29 15:40:10 -0600685 if (!kcontrol) {
686 if (shared) {
687 wname_in_long_name = false;
688 kcname_in_long_name = true;
689 } else {
690 switch (w->id) {
691 case snd_soc_dapm_switch:
692 case snd_soc_dapm_mixer:
693 wname_in_long_name = true;
694 kcname_in_long_name = true;
695 break;
696 case snd_soc_dapm_mixer_named_ctl:
697 wname_in_long_name = false;
698 kcname_in_long_name = true;
699 break;
700 case snd_soc_dapm_mux:
Stephen Warren85762e72013-03-29 15:40:10 -0600701 wname_in_long_name = true;
702 kcname_in_long_name = false;
703 break;
704 default:
Stephen Warren85762e72013-03-29 15:40:10 -0600705 return -EINVAL;
706 }
707 }
708
709 if (wname_in_long_name && kcname_in_long_name) {
Stephen Warren85762e72013-03-29 15:40:10 -0600710 /*
711 * The control will get a prefix from the control
712 * creation process but we're also using the same
713 * prefix for widgets so cut the prefix off the
714 * front of the widget name.
715 */
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200716 long_name = kasprintf(GFP_KERNEL, "%s %s",
Stephen Warren85762e72013-03-29 15:40:10 -0600717 w->name + prefix_len,
718 w->kcontrol_news[kci].name);
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200719 if (long_name == NULL)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +0200720 return -ENOMEM;
Stephen Warren85762e72013-03-29 15:40:10 -0600721
722 name = long_name;
723 } else if (wname_in_long_name) {
724 long_name = NULL;
725 name = w->name + prefix_len;
726 } else {
727 long_name = NULL;
728 name = w->kcontrol_news[kci].name;
729 }
730
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200731 kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
Stephen Warren85762e72013-03-29 15:40:10 -0600732 prefix);
Lars-Peter Clausen656ca9d2013-06-14 13:16:54 +0200733 kfree(long_name);
Lars-Peter Clausen9356e9d2013-08-01 14:08:06 +0200734 if (!kcontrol)
735 return -ENOMEM;
736 kcontrol->private_free = dapm_kcontrol_free;
Lars-Peter Clausene84357f2013-07-29 17:13:58 +0200737
738 ret = dapm_kcontrol_data_alloc(w, kcontrol);
739 if (ret) {
740 snd_ctl_free_one(kcontrol);
741 return ret;
742 }
743
Stephen Warren85762e72013-03-29 15:40:10 -0600744 ret = snd_ctl_add(card, kcontrol);
745 if (ret < 0) {
746 dev_err(dapm->dev,
747 "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
748 w->name, name, ret);
Stephen Warren85762e72013-03-29 15:40:10 -0600749 return ret;
750 }
Stephen Warren85762e72013-03-29 15:40:10 -0600751 }
752
Lars-Peter Clausen2c75bdf2013-08-01 14:08:07 +0200753 ret = dapm_kcontrol_add_widget(kcontrol, w);
754 if (ret)
755 return ret;
756
Stephen Warren85762e72013-03-29 15:40:10 -0600757 w->kcontrols[kci] = kcontrol;
Stephen Warren85762e72013-03-29 15:40:10 -0600758
759 return 0;
760}
761
762/* create new dapm mixer control */
763static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
764{
765 int i, ret;
766 struct snd_soc_dapm_path *path;
767
Richard Purdie2b97eab2006-10-06 18:32:18 +0200768 /* add kcontrol */
769 for (i = 0; i < w->num_kcontrols; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200770 /* match name */
771 list_for_each_entry(path, &w->sources, list_sink) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200772 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600773 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200774 continue;
775
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200776 if (w->kcontrols[i]) {
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200777 dapm_kcontrol_add_path(w->kcontrols[i], path);
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200778 continue;
779 }
780
Mark Brown946d92a2013-08-12 23:28:42 +0100781 ret = dapm_create_or_share_mixmux_kcontrol(w, i);
Stephen Warren85762e72013-03-29 15:40:10 -0600782 if (ret < 0)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200783 return ret;
Mark Brown946d92a2013-08-12 23:28:42 +0100784
785 dapm_kcontrol_add_path(w->kcontrols[i], path);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200786 }
787 }
Stephen Warren85762e72013-03-29 15:40:10 -0600788
789 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200790}
791
792/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200793static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200794{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200795 struct snd_soc_dapm_context *dapm = w->dapm;
Stephen Warren85762e72013-03-29 15:40:10 -0600796 struct snd_soc_dapm_path *path;
Stephen Warrenaf468002011-04-28 17:38:01 -0600797 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200798
Stephen Warrenaf468002011-04-28 17:38:01 -0600799 if (w->num_kcontrols != 1) {
800 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000801 "ASoC: mux %s has incorrect number of controls\n",
Stephen Warrenaf468002011-04-28 17:38:01 -0600802 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200803 return -EINVAL;
804 }
805
Lars-Peter Clausenfe581392013-08-01 18:30:38 +0200806 if (list_empty(&w->sources)) {
Stephen Warren85762e72013-03-29 15:40:10 -0600807 dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
808 return -EINVAL;
Stephen Warrenaf468002011-04-28 17:38:01 -0600809 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200810
Mark Brown946d92a2013-08-12 23:28:42 +0100811 ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
Stephen Warren85762e72013-03-29 15:40:10 -0600812 if (ret < 0)
813 return ret;
Stephen Warrenfad59882011-04-28 17:37:59 -0600814
Richard Purdie2b97eab2006-10-06 18:32:18 +0200815 list_for_each_entry(path, &w->sources, list_sink)
Lars-Peter Clausen5106b922013-07-29 17:14:00 +0200816 dapm_kcontrol_add_path(w->kcontrols[0], path);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200817
Stephen Warrenaf468002011-04-28 17:38:01 -0600818 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200819}
820
821/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200822static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200823{
Mark Browna6c65732010-03-03 17:45:21 +0000824 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200825 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000826 "ASoC: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200827
Mark Browna6c65732010-03-03 17:45:21 +0000828 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200829}
830
831/* reset 'walked' bit for each dapm path */
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +0100832static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
833 struct list_head *sink)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200834{
835 struct snd_soc_dapm_path *p;
836
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +0100837 list_for_each_entry(p, sink, list_source) {
838 if (p->walked) {
839 p->walked = 0;
840 dapm_clear_walk_output(dapm, &p->sink->sinks);
841 }
842 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200843}
844
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +0100845static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm,
846 struct list_head *source)
847{
848 struct snd_soc_dapm_path *p;
849
850 list_for_each_entry(p, source, list_sink) {
851 if (p->walked) {
852 p->walked = 0;
853 dapm_clear_walk_input(dapm, &p->source->sources);
854 }
855 }
856}
857
858
Mark Brown99497882010-05-07 20:24:05 +0100859/* We implement power down on suspend by checking the power state of
860 * the ALSA card - when we are suspending the ALSA state for the card
861 * is set to D3.
862 */
863static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
864{
Mark Brown12ea2c72011-03-02 18:17:32 +0000865 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +0100866
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000867 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +0100868 case SNDRV_CTL_POWER_D3hot:
869 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +0100870 if (widget->ignore_suspend)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000871 dev_dbg(widget->dapm->dev, "ASoC: %s ignoring suspend\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200872 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +0100873 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +0100874 default:
875 return 1;
876 }
877}
878
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100879/* add widget to list if it's not already in the list */
880static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
881 struct snd_soc_dapm_widget *w)
882{
883 struct snd_soc_dapm_widget_list *wlist;
884 int wlistsize, wlistentries, i;
885
886 if (*list == NULL)
887 return -EINVAL;
888
889 wlist = *list;
890
891 /* is this widget already in the list */
892 for (i = 0; i < wlist->num_widgets; i++) {
893 if (wlist->widgets[i] == w)
894 return 0;
895 }
896
897 /* allocate some new space */
898 wlistentries = wlist->num_widgets + 1;
899 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
900 wlistentries * sizeof(struct snd_soc_dapm_widget *);
901 *list = krealloc(wlist, wlistsize, GFP_KERNEL);
902 if (*list == NULL) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000903 dev_err(w->dapm->dev, "ASoC: can't allocate widget list for %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100904 w->name);
905 return -ENOMEM;
906 }
907 wlist = *list;
908
909 /* insert the widget */
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000910 dev_dbg(w->dapm->dev, "ASoC: added %s in widget list pos %d\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100911 w->name, wlist->num_widgets);
912
913 wlist->widgets[wlist->num_widgets] = w;
914 wlist->num_widgets++;
915 return 1;
916}
917
Richard Purdie2b97eab2006-10-06 18:32:18 +0200918/*
919 * Recursively check for a completed path to an active or physically connected
920 * output widget. Returns number of complete paths.
921 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100922static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
923 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200924{
925 struct snd_soc_dapm_path *path;
926 int con = 0;
927
Mark Brown024dc072011-10-09 11:52:05 +0100928 if (widget->outputs >= 0)
929 return widget->outputs;
930
Mark Brownde02d072011-09-20 21:43:24 +0100931 DAPM_UPDATE_STAT(widget, path_checks);
932
Mark Brown62ea8742012-01-21 21:14:48 +0000933 switch (widget->id) {
934 case snd_soc_dapm_supply:
935 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +0200936 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +0200937 case snd_soc_dapm_kcontrol:
Mark Brown246d0a12009-04-22 18:24:55 +0100938 return 0;
Mark Brown62ea8742012-01-21 21:14:48 +0000939 default:
940 break;
941 }
Mark Brown246d0a12009-04-22 18:24:55 +0100942
Mark Brown010ff262009-08-17 17:39:22 +0100943 switch (widget->id) {
944 case snd_soc_dapm_adc:
945 case snd_soc_dapm_aif_out:
Mark Brown46162742013-06-05 19:36:11 +0100946 case snd_soc_dapm_dai_out:
Mark Brown024dc072011-10-09 11:52:05 +0100947 if (widget->active) {
948 widget->outputs = snd_soc_dapm_suspend_check(widget);
949 return widget->outputs;
950 }
Mark Brown010ff262009-08-17 17:39:22 +0100951 default:
952 break;
953 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200954
955 if (widget->connected) {
956 /* connected pin ? */
Mark Brown024dc072011-10-09 11:52:05 +0100957 if (widget->id == snd_soc_dapm_output && !widget->ext) {
958 widget->outputs = snd_soc_dapm_suspend_check(widget);
959 return widget->outputs;
960 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200961
962 /* connected jack or spk ? */
Mark Brown024dc072011-10-09 11:52:05 +0100963 if (widget->id == snd_soc_dapm_hp ||
964 widget->id == snd_soc_dapm_spk ||
965 (widget->id == snd_soc_dapm_line &&
966 !list_empty(&widget->sources))) {
967 widget->outputs = snd_soc_dapm_suspend_check(widget);
968 return widget->outputs;
969 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200970 }
971
972 list_for_each_entry(path, &widget->sinks, list_source) {
Mark Browne56235e2011-09-21 18:19:14 +0100973 DAPM_UPDATE_STAT(widget, neighbour_checks);
974
Mark Brownbf3a9e12011-06-13 16:42:29 +0100975 if (path->weak)
976 continue;
977
Mark Brown8af294b2013-02-22 17:48:15 +0000978 if (path->walking)
979 return 1;
980
Richard Purdie2b97eab2006-10-06 18:32:18 +0200981 if (path->walked)
982 continue;
983
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100984 trace_snd_soc_dapm_output_path(widget, path);
985
Richard Purdie2b97eab2006-10-06 18:32:18 +0200986 if (path->sink && path->connect) {
987 path->walked = 1;
Mark Brown8af294b2013-02-22 17:48:15 +0000988 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100989
990 /* do we need to add this widget to the list ? */
991 if (list) {
992 int err;
993 err = dapm_list_add_widget(list, path->sink);
994 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +0000995 dev_err(widget->dapm->dev,
996 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100997 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +0000998 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100999 return con;
1000 }
1001 }
1002
1003 con += is_connected_output_ep(path->sink, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001004
1005 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001006 }
1007 }
1008
Mark Brown024dc072011-10-09 11:52:05 +01001009 widget->outputs = con;
1010
Richard Purdie2b97eab2006-10-06 18:32:18 +02001011 return con;
1012}
1013
1014/*
1015 * Recursively check for a completed path to an active or physically connected
1016 * input widget. Returns number of complete paths.
1017 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001018static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
1019 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001020{
1021 struct snd_soc_dapm_path *path;
1022 int con = 0;
1023
Mark Brown024dc072011-10-09 11:52:05 +01001024 if (widget->inputs >= 0)
1025 return widget->inputs;
1026
Mark Brownde02d072011-09-20 21:43:24 +01001027 DAPM_UPDATE_STAT(widget, path_checks);
1028
Mark Brown62ea8742012-01-21 21:14:48 +00001029 switch (widget->id) {
1030 case snd_soc_dapm_supply:
1031 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001032 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001033 case snd_soc_dapm_kcontrol:
Mark Brown246d0a12009-04-22 18:24:55 +01001034 return 0;
Mark Brown62ea8742012-01-21 21:14:48 +00001035 default:
1036 break;
1037 }
Mark Brown246d0a12009-04-22 18:24:55 +01001038
Richard Purdie2b97eab2006-10-06 18:32:18 +02001039 /* active stream ? */
Mark Brown010ff262009-08-17 17:39:22 +01001040 switch (widget->id) {
1041 case snd_soc_dapm_dac:
1042 case snd_soc_dapm_aif_in:
Mark Brown46162742013-06-05 19:36:11 +01001043 case snd_soc_dapm_dai_in:
Mark Brown024dc072011-10-09 11:52:05 +01001044 if (widget->active) {
1045 widget->inputs = snd_soc_dapm_suspend_check(widget);
1046 return widget->inputs;
1047 }
Mark Brown010ff262009-08-17 17:39:22 +01001048 default:
1049 break;
1050 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001051
1052 if (widget->connected) {
1053 /* connected pin ? */
Mark Brown024dc072011-10-09 11:52:05 +01001054 if (widget->id == snd_soc_dapm_input && !widget->ext) {
1055 widget->inputs = snd_soc_dapm_suspend_check(widget);
1056 return widget->inputs;
1057 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001058
1059 /* connected VMID/Bias for lower pops */
Mark Brown024dc072011-10-09 11:52:05 +01001060 if (widget->id == snd_soc_dapm_vmid) {
1061 widget->inputs = snd_soc_dapm_suspend_check(widget);
1062 return widget->inputs;
1063 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001064
1065 /* connected jack ? */
Peter Ujfalusieaeae5d2009-09-30 09:27:24 +03001066 if (widget->id == snd_soc_dapm_mic ||
Mark Brown024dc072011-10-09 11:52:05 +01001067 (widget->id == snd_soc_dapm_line &&
1068 !list_empty(&widget->sinks))) {
1069 widget->inputs = snd_soc_dapm_suspend_check(widget);
1070 return widget->inputs;
1071 }
1072
Mark Brown1ab97c82011-11-27 16:21:51 +00001073 /* signal generator */
1074 if (widget->id == snd_soc_dapm_siggen) {
1075 widget->inputs = snd_soc_dapm_suspend_check(widget);
1076 return widget->inputs;
1077 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001078 }
1079
1080 list_for_each_entry(path, &widget->sources, list_sink) {
Mark Browne56235e2011-09-21 18:19:14 +01001081 DAPM_UPDATE_STAT(widget, neighbour_checks);
1082
Mark Brownbf3a9e12011-06-13 16:42:29 +01001083 if (path->weak)
1084 continue;
1085
Mark Brown8af294b2013-02-22 17:48:15 +00001086 if (path->walking)
1087 return 1;
1088
Richard Purdie2b97eab2006-10-06 18:32:18 +02001089 if (path->walked)
1090 continue;
1091
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001092 trace_snd_soc_dapm_input_path(widget, path);
1093
Richard Purdie2b97eab2006-10-06 18:32:18 +02001094 if (path->source && path->connect) {
1095 path->walked = 1;
Mark Brown8af294b2013-02-22 17:48:15 +00001096 path->walking = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001097
1098 /* do we need to add this widget to the list ? */
1099 if (list) {
1100 int err;
Liam Girdwood90c6ce02012-06-05 19:27:15 +01001101 err = dapm_list_add_widget(list, path->source);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001102 if (err < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001103 dev_err(widget->dapm->dev,
1104 "ASoC: could not add widget %s\n",
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001105 widget->name);
Mark Brown8af294b2013-02-22 17:48:15 +00001106 path->walking = 0;
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001107 return con;
1108 }
1109 }
1110
1111 con += is_connected_input_ep(path->source, list);
Mark Brown8af294b2013-02-22 17:48:15 +00001112
1113 path->walking = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001114 }
1115 }
1116
Mark Brown024dc072011-10-09 11:52:05 +01001117 widget->inputs = con;
1118
Richard Purdie2b97eab2006-10-06 18:32:18 +02001119 return con;
1120}
1121
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001122/**
1123 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
1124 * @dai: the soc DAI.
1125 * @stream: stream direction.
1126 * @list: list of active widgets for this stream.
1127 *
1128 * Queries DAPM graph as to whether an valid audio stream path exists for
1129 * the initial stream specified by name. This takes into account
1130 * current mixer and mux kcontrol settings. Creates list of valid widgets.
1131 *
1132 * Returns the number of valid paths or negative error.
1133 */
1134int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
1135 struct snd_soc_dapm_widget_list **list)
1136{
1137 struct snd_soc_card *card = dai->card;
1138 int paths;
1139
1140 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
1141 dapm_reset(card);
1142
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001143 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001144 paths = is_connected_output_ep(dai->playback_widget, list);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001145 dapm_clear_walk_output(&card->dapm,
1146 &dai->playback_widget->sinks);
1147 } else {
Liam Girdwoodd298caa2012-06-01 18:03:00 +01001148 paths = is_connected_input_ep(dai->capture_widget, list);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001149 dapm_clear_walk_input(&card->dapm,
1150 &dai->capture_widget->sources);
1151 }
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001152
1153 trace_snd_soc_dapm_connected(paths, stream);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001154 mutex_unlock(&card->dapm_mutex);
1155
1156 return paths;
1157}
1158
Richard Purdie2b97eab2006-10-06 18:32:18 +02001159/*
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +03001160 * Handler for generic register modifier widget.
1161 */
1162int dapm_reg_event(struct snd_soc_dapm_widget *w,
1163 struct snd_kcontrol *kcontrol, int event)
1164{
1165 unsigned int val;
1166
1167 if (SND_SOC_DAPM_EVENT_ON(event))
1168 val = w->on_val;
1169 else
1170 val = w->off_val;
1171
Liam Girdwood49575fb52012-03-06 18:16:19 +00001172 soc_widget_update_bits_locked(w, -(w->reg + 1),
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +03001173 w->mask << w->shift, val << w->shift);
1174
1175 return 0;
1176}
Mark Brown11589412008-07-29 11:42:23 +01001177EXPORT_SYMBOL_GPL(dapm_reg_event);
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +03001178
Mark Brown62ea8742012-01-21 21:14:48 +00001179/*
1180 * Handler for regulator supply widget.
1181 */
1182int dapm_regulator_event(struct snd_soc_dapm_widget *w,
1183 struct snd_kcontrol *kcontrol, int event)
1184{
Mark Brownc05b84d2012-09-07 12:57:11 +08001185 int ret;
1186
Mark Browneb270e92013-10-09 13:52:52 +01001187 soc_dapm_async_complete(w->dapm);
1188
Mark Brownc05b84d2012-09-07 12:57:11 +08001189 if (SND_SOC_DAPM_EVENT_ON(event)) {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001190 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001191 ret = regulator_allow_bypass(w->regulator, false);
Mark Brownc05b84d2012-09-07 12:57:11 +08001192 if (ret != 0)
1193 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001194 "ASoC: Failed to unbypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001195 w->name, ret);
1196 }
1197
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001198 return regulator_enable(w->regulator);
Mark Brownc05b84d2012-09-07 12:57:11 +08001199 } else {
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001200 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00001201 ret = regulator_allow_bypass(w->regulator, true);
Mark Brownc05b84d2012-09-07 12:57:11 +08001202 if (ret != 0)
1203 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00001204 "ASoC: Failed to bypass %s: %d\n",
Mark Brownc05b84d2012-09-07 12:57:11 +08001205 w->name, ret);
1206 }
1207
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001208 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brownc05b84d2012-09-07 12:57:11 +08001209 }
Mark Brown62ea8742012-01-21 21:14:48 +00001210}
1211EXPORT_SYMBOL_GPL(dapm_regulator_event);
1212
Ola Liljad7e7eb92012-05-24 15:26:25 +02001213/*
1214 * Handler for clock supply widget.
1215 */
1216int dapm_clock_event(struct snd_soc_dapm_widget *w,
1217 struct snd_kcontrol *kcontrol, int event)
1218{
1219 if (!w->clk)
1220 return -EIO;
1221
Mark Browneb270e92013-10-09 13:52:52 +01001222 soc_dapm_async_complete(w->dapm);
1223
Mark Brownec029952012-06-04 08:16:20 +01001224#ifdef CONFIG_HAVE_CLK
Ola Liljad7e7eb92012-05-24 15:26:25 +02001225 if (SND_SOC_DAPM_EVENT_ON(event)) {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001226 return clk_prepare_enable(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001227 } else {
Fabio Baltieri37c1b922013-04-30 16:09:52 +02001228 clk_disable_unprepare(w->clk);
Ola Liljad7e7eb92012-05-24 15:26:25 +02001229 return 0;
1230 }
Mark Brownec029952012-06-04 08:16:20 +01001231#endif
Marek Belisko98b3cf12012-07-12 23:00:16 +02001232 return 0;
Ola Liljad7e7eb92012-05-24 15:26:25 +02001233}
1234EXPORT_SYMBOL_GPL(dapm_clock_event);
1235
Mark Brownd8050022011-09-28 18:28:23 +01001236static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1237{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001238 if (w->power_checked)
1239 return w->new_power;
1240
Mark Brownd8050022011-09-28 18:28:23 +01001241 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001242 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001243 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001244 w->new_power = w->power_check(w);
1245
1246 w->power_checked = true;
1247
1248 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001249}
1250
Mark Browncd0f2d42009-04-20 16:56:59 +01001251/* Generic check to see if a widget should be powered.
1252 */
1253static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1254{
1255 int in, out;
1256
Mark Brownde02d072011-09-20 21:43:24 +01001257 DAPM_UPDATE_STAT(w, power_checks);
1258
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001259 in = is_connected_input_ep(w, NULL);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001260 dapm_clear_walk_input(w->dapm, &w->sources);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001261 out = is_connected_output_ep(w, NULL);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001262 dapm_clear_walk_output(w->dapm, &w->sinks);
Mark Browncd0f2d42009-04-20 16:56:59 +01001263 return out != 0 && in != 0;
1264}
1265
Mark Brown6ea31b92009-04-20 17:15:41 +01001266/* Check to see if an ADC has power */
1267static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
1268{
1269 int in;
1270
Mark Brownde02d072011-09-20 21:43:24 +01001271 DAPM_UPDATE_STAT(w, power_checks);
1272
Mark Brown6ea31b92009-04-20 17:15:41 +01001273 if (w->active) {
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001274 in = is_connected_input_ep(w, NULL);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001275 dapm_clear_walk_input(w->dapm, &w->sources);
Mark Brown6ea31b92009-04-20 17:15:41 +01001276 return in != 0;
1277 } else {
1278 return dapm_generic_check_power(w);
1279 }
1280}
1281
1282/* Check to see if a DAC has power */
1283static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
1284{
1285 int out;
1286
Mark Brownde02d072011-09-20 21:43:24 +01001287 DAPM_UPDATE_STAT(w, power_checks);
1288
Mark Brown6ea31b92009-04-20 17:15:41 +01001289 if (w->active) {
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001290 out = is_connected_output_ep(w, NULL);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001291 dapm_clear_walk_output(w->dapm, &w->sinks);
Mark Brown6ea31b92009-04-20 17:15:41 +01001292 return out != 0;
1293 } else {
1294 return dapm_generic_check_power(w);
1295 }
1296}
1297
Mark Brown246d0a12009-04-22 18:24:55 +01001298/* Check to see if a power supply is needed */
1299static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1300{
1301 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001302
Mark Brownde02d072011-09-20 21:43:24 +01001303 DAPM_UPDATE_STAT(w, power_checks);
1304
Mark Brown246d0a12009-04-22 18:24:55 +01001305 /* Check if one of our outputs is connected */
1306 list_for_each_entry(path, &w->sinks, list_source) {
Mark Browna8fdac82011-09-28 18:20:26 +01001307 DAPM_UPDATE_STAT(w, neighbour_checks);
1308
Mark Brownbf3a9e12011-06-13 16:42:29 +01001309 if (path->weak)
1310 continue;
1311
Mark Brown215edda2009-09-08 18:59:05 +01001312 if (path->connected &&
1313 !path->connected(path->source, path->sink))
1314 continue;
1315
Mark Brown30173582011-02-11 11:42:19 +00001316 if (!path->sink)
1317 continue;
1318
Mark Brownf68d7e12011-10-04 22:57:50 +01001319 if (dapm_widget_power_check(path->sink))
1320 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001321 }
1322
Mark Brownf68d7e12011-10-04 22:57:50 +01001323 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001324}
1325
Mark Brown35c64bc2011-09-28 18:23:53 +01001326static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1327{
1328 return 1;
1329}
1330
Mark Brown38357ab2009-06-06 19:03:23 +01001331static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1332 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001333 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001334{
Mark Brown828a8422011-01-15 13:14:30 +00001335 int *sort;
1336
1337 if (power_up)
1338 sort = dapm_up_seq;
1339 else
1340 sort = dapm_down_seq;
1341
Mark Brown38357ab2009-06-06 19:03:23 +01001342 if (sort[a->id] != sort[b->id])
1343 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001344 if (a->subseq != b->subseq) {
1345 if (power_up)
1346 return a->subseq - b->subseq;
1347 else
1348 return b->subseq - a->subseq;
1349 }
Mark Brownb22ead22009-06-07 12:51:26 +01001350 if (a->reg != b->reg)
1351 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001352 if (a->dapm != b->dapm)
1353 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001354
Mark Brown38357ab2009-06-06 19:03:23 +01001355 return 0;
1356}
Mark Brown42aa3412009-03-01 19:21:10 +00001357
Mark Brown38357ab2009-06-06 19:03:23 +01001358/* Insert a widget in order into a DAPM power sequence. */
1359static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1360 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001361 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001362{
1363 struct snd_soc_dapm_widget *w;
1364
1365 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001366 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001367 list_add_tail(&new_widget->power_list, &w->power_list);
1368 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001369 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001370
Mark Brown38357ab2009-06-06 19:03:23 +01001371 list_add_tail(&new_widget->power_list, list);
1372}
Mark Brown42aa3412009-03-01 19:21:10 +00001373
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001374static void dapm_seq_check_event(struct snd_soc_card *card,
Mark Brown68f89ad2010-11-03 23:51:49 -04001375 struct snd_soc_dapm_widget *w, int event)
1376{
Mark Brown68f89ad2010-11-03 23:51:49 -04001377 const char *ev_name;
1378 int power, ret;
1379
1380 switch (event) {
1381 case SND_SOC_DAPM_PRE_PMU:
1382 ev_name = "PRE_PMU";
1383 power = 1;
1384 break;
1385 case SND_SOC_DAPM_POST_PMU:
1386 ev_name = "POST_PMU";
1387 power = 1;
1388 break;
1389 case SND_SOC_DAPM_PRE_PMD:
1390 ev_name = "PRE_PMD";
1391 power = 0;
1392 break;
1393 case SND_SOC_DAPM_POST_PMD:
1394 ev_name = "POST_PMD";
1395 power = 0;
1396 break;
Mark Brown80114122013-02-25 15:14:19 +00001397 case SND_SOC_DAPM_WILL_PMU:
1398 ev_name = "WILL_PMU";
1399 power = 1;
1400 break;
1401 case SND_SOC_DAPM_WILL_PMD:
1402 ev_name = "WILL_PMD";
1403 power = 0;
1404 break;
Mark Brown68f89ad2010-11-03 23:51:49 -04001405 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01001406 WARN(1, "Unknown event %d\n", event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001407 return;
1408 }
1409
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001410 if (w->new_power != power)
Mark Brown68f89ad2010-11-03 23:51:49 -04001411 return;
1412
1413 if (w->event && (w->event_flags & event)) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001414 pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001415 w->name, ev_name);
Mark Browneb270e92013-10-09 13:52:52 +01001416 soc_dapm_async_complete(w->dapm);
Mark Brown84e90932010-11-04 00:07:02 -04001417 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001418 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001419 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001420 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001421 dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
Mark Brown68f89ad2010-11-03 23:51:49 -04001422 ev_name, w->name, ret);
1423 }
1424}
1425
Mark Brownb22ead22009-06-07 12:51:26 +01001426/* Apply the coalesced changes from a DAPM sequence */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001427static void dapm_seq_run_coalesced(struct snd_soc_card *card,
Mark Brownb22ead22009-06-07 12:51:26 +01001428 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001429{
Mark Brown68f89ad2010-11-03 23:51:49 -04001430 struct snd_soc_dapm_widget *w;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001431 int reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001432 unsigned int value = 0;
1433 unsigned int mask = 0;
Mark Brownb22ead22009-06-07 12:51:26 +01001434
1435 reg = list_first_entry(pending, struct snd_soc_dapm_widget,
1436 power_list)->reg;
1437
1438 list_for_each_entry(w, pending, power_list) {
Takashi Iwaibf4edea2013-11-07 18:38:47 +01001439 WARN_ON(reg != w->reg);
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001440 w->power = w->new_power;
Mark Brownb22ead22009-06-07 12:51:26 +01001441
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001442 mask |= w->mask << w->shift;
1443 if (w->power)
1444 value |= w->on_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001445 else
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001446 value |= w->off_val << w->shift;
Mark Brownb22ead22009-06-07 12:51:26 +01001447
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001448 pop_dbg(w->dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001449 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1450 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001451
Mark Brown68f89ad2010-11-03 23:51:49 -04001452 /* Check for events */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001453 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
1454 dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001455 }
1456
Mark Brown81628102009-06-07 13:21:24 +01001457 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001458 /* Any widget will do, they should all be updating the
1459 * same register.
1460 */
1461 w = list_first_entry(pending, struct snd_soc_dapm_widget,
1462 power_list);
1463
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001464 pop_dbg(w->dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001465 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001466 value, mask, reg, card->pop_time);
1467 pop_wait(card->pop_time);
Liam Girdwood49575fb52012-03-06 18:16:19 +00001468 soc_widget_update_bits_locked(w, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001469 }
1470
1471 list_for_each_entry(w, pending, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001472 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
1473 dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001474 }
Mark Brown42aa3412009-03-01 19:21:10 +00001475}
1476
Mark Brownb22ead22009-06-07 12:51:26 +01001477/* Apply a DAPM power sequence.
1478 *
1479 * We walk over a pre-sorted list of widgets to apply power to. In
1480 * order to minimise the number of writes to the device required
1481 * multiple widgets will be updated in a single write where possible.
1482 * Currently anything that requires more than a single write is not
1483 * handled.
1484 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001485static void dapm_seq_run(struct snd_soc_card *card,
1486 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001487{
1488 struct snd_soc_dapm_widget *w, *n;
Mark Browneb270e92013-10-09 13:52:52 +01001489 struct snd_soc_dapm_context *d;
Mark Brownb22ead22009-06-07 12:51:26 +01001490 LIST_HEAD(pending);
1491 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001492 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001493 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001494 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001495 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001496 int *sort;
1497
1498 if (power_up)
1499 sort = dapm_up_seq;
1500 else
1501 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001502
Mark Brownb22ead22009-06-07 12:51:26 +01001503 list_for_each_entry_safe(w, n, list, power_list) {
1504 ret = 0;
1505
1506 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001507 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001508 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001509 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001510 dapm_seq_run_coalesced(card, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001511
Mark Brown474b62d2011-01-18 16:14:44 +00001512 if (cur_dapm && cur_dapm->seq_notifier) {
1513 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1514 if (sort[i] == cur_sort)
1515 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001516 i,
1517 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001518 }
1519
Mark Browneb270e92013-10-09 13:52:52 +01001520 if (cur_dapm && w->dapm != cur_dapm)
1521 soc_dapm_async_complete(cur_dapm);
1522
Mark Brownb22ead22009-06-07 12:51:26 +01001523 INIT_LIST_HEAD(&pending);
1524 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001525 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001526 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001527 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001528 }
1529
Mark Brown163cac02009-06-07 10:12:52 +01001530 switch (w->id) {
1531 case snd_soc_dapm_pre:
1532 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001533 list_for_each_entry_safe_continue(w, n, list,
1534 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001535
Mark Brownb22ead22009-06-07 12:51:26 +01001536 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001537 ret = w->event(w,
1538 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001539 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001540 ret = w->event(w,
1541 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001542 break;
1543
1544 case snd_soc_dapm_post:
1545 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001546 list_for_each_entry_safe_continue(w, n, list,
1547 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001548
Mark Brownb22ead22009-06-07 12:51:26 +01001549 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001550 ret = w->event(w,
1551 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001552 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001553 ret = w->event(w,
1554 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001555 break;
1556
Mark Brown163cac02009-06-07 10:12:52 +01001557 default:
Mark Brown81628102009-06-07 13:21:24 +01001558 /* Queue it up for application */
1559 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001560 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001561 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001562 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001563 list_move(&w->power_list, &pending);
1564 break;
Mark Brown163cac02009-06-07 10:12:52 +01001565 }
Mark Brownb22ead22009-06-07 12:51:26 +01001566
1567 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001568 dev_err(w->dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001569 "ASoC: Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001570 }
Mark Brownb22ead22009-06-07 12:51:26 +01001571
1572 if (!list_empty(&pending))
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001573 dapm_seq_run_coalesced(card, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001574
1575 if (cur_dapm && cur_dapm->seq_notifier) {
1576 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1577 if (sort[i] == cur_sort)
1578 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001579 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001580 }
Mark Browneb270e92013-10-09 13:52:52 +01001581
1582 list_for_each_entry(d, &card->dapm_list, list) {
1583 soc_dapm_async_complete(d);
1584 }
Mark Brown163cac02009-06-07 10:12:52 +01001585}
1586
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001587static void dapm_widget_update(struct snd_soc_card *card)
Mark Brown97404f22010-12-14 16:13:57 +00001588{
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001589 struct snd_soc_dapm_update *update = card->update;
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001590 struct snd_soc_dapm_widget_list *wlist;
1591 struct snd_soc_dapm_widget *w = NULL;
1592 unsigned int wi;
Mark Brown97404f22010-12-14 16:13:57 +00001593 int ret;
1594
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001595 if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
Mark Brown97404f22010-12-14 16:13:57 +00001596 return;
1597
Lars-Peter Clausene84357f2013-07-29 17:13:58 +02001598 wlist = dapm_kcontrol_get_wlist(update->kcontrol);
Mark Brown97404f22010-12-14 16:13:57 +00001599
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001600 for (wi = 0; wi < wlist->num_widgets; wi++) {
1601 w = wlist->widgets[wi];
1602
1603 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1604 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1605 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001606 dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001607 w->name, ret);
1608 }
Mark Brown97404f22010-12-14 16:13:57 +00001609 }
1610
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001611 if (!w)
1612 return;
1613
Liam Girdwood49575fb52012-03-06 18:16:19 +00001614 ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
Mark Brown97404f22010-12-14 16:13:57 +00001615 update->val);
1616 if (ret < 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001617 dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001618 w->name, ret);
Mark Brown97404f22010-12-14 16:13:57 +00001619
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001620 for (wi = 0; wi < wlist->num_widgets; wi++) {
1621 w = wlist->widgets[wi];
1622
1623 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1624 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1625 if (ret != 0)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001626 dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02001627 w->name, ret);
1628 }
Mark Brown97404f22010-12-14 16:13:57 +00001629 }
1630}
1631
Mark Brown9d0624a2011-02-18 11:49:43 -08001632/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1633 * they're changing state.
1634 */
1635static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1636{
1637 struct snd_soc_dapm_context *d = data;
1638 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001639
Mark Brown56fba412011-06-04 11:25:10 +01001640 /* If we're off and we're not supposed to be go into STANDBY */
1641 if (d->bias_level == SND_SOC_BIAS_OFF &&
1642 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001643 if (d->dev)
1644 pm_runtime_get_sync(d->dev);
1645
Mark Brown9d0624a2011-02-18 11:49:43 -08001646 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1647 if (ret != 0)
1648 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001649 "ASoC: Failed to turn on bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001650 }
1651
Mark Brown56fba412011-06-04 11:25:10 +01001652 /* Prepare for a STADDBY->ON or ON->STANDBY transition */
1653 if (d->bias_level != d->target_bias_level) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001654 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1655 if (ret != 0)
1656 dev_err(d->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001657 "ASoC: Failed to prepare bias: %d\n", ret);
Mark Brown9d0624a2011-02-18 11:49:43 -08001658 }
1659}
1660
1661/* Async callback run prior to DAPM sequences - brings to their final
1662 * state.
1663 */
1664static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1665{
1666 struct snd_soc_dapm_context *d = data;
1667 int ret;
1668
1669 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001670 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1671 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1672 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001673 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1674 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001675 dev_err(d->dev, "ASoC: Failed to apply standby bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001676 ret);
1677 }
1678
1679 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001680 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1681 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001682 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1683 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001684 dev_err(d->dev, "ASoC: Failed to turn off bias: %d\n",
1685 ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001686
1687 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001688 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001689 }
1690
1691 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001692 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1693 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001694 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1695 if (ret != 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00001696 dev_err(d->dev, "ASoC: Failed to apply active bias: %d\n",
Mark Brown9d0624a2011-02-18 11:49:43 -08001697 ret);
1698 }
1699}
Mark Brown97404f22010-12-14 16:13:57 +00001700
Mark Brownfe4fda52011-10-03 22:36:57 +01001701static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1702 bool power, bool connect)
1703{
1704 /* If a connection is being made or broken then that update
1705 * will have marked the peer dirty, otherwise the widgets are
1706 * not connected and this update has no impact. */
1707 if (!connect)
1708 return;
1709
1710 /* If the peer is already in the state we're moving to then we
1711 * won't have an impact on it. */
1712 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001713 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001714}
1715
Mark Brown05623c42011-09-28 17:02:31 +01001716static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1717 struct list_head *up_list,
1718 struct list_head *down_list)
1719{
Mark Browndb432b42011-10-03 21:06:40 +01001720 struct snd_soc_dapm_path *path;
1721
Mark Brown05623c42011-09-28 17:02:31 +01001722 if (w->power == power)
1723 return;
1724
1725 trace_snd_soc_dapm_widget_power(w, power);
1726
Mark Browndb432b42011-10-03 21:06:40 +01001727 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001728 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001729 */
1730 list_for_each_entry(path, &w->sources, list_sink) {
1731 if (path->source) {
Mark Brownfe4fda52011-10-03 22:36:57 +01001732 dapm_widget_set_peer_power(path->source, power,
1733 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001734 }
1735 }
Mark Brownf3bf3e42011-10-04 22:43:31 +01001736 switch (w->id) {
1737 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001738 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001739 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02001740 case snd_soc_dapm_kcontrol:
Mark Brownf3bf3e42011-10-04 22:43:31 +01001741 /* Supplies can't affect their outputs, only their inputs */
1742 break;
1743 default:
1744 list_for_each_entry(path, &w->sinks, list_source) {
1745 if (path->sink) {
1746 dapm_widget_set_peer_power(path->sink, power,
1747 path->connect);
1748 }
Mark Browndb432b42011-10-03 21:06:40 +01001749 }
Mark Brownf3bf3e42011-10-04 22:43:31 +01001750 break;
Mark Browndb432b42011-10-03 21:06:40 +01001751 }
1752
Mark Brown05623c42011-09-28 17:02:31 +01001753 if (power)
1754 dapm_seq_insert(w, up_list, true);
1755 else
1756 dapm_seq_insert(w, down_list, false);
Mark Brown05623c42011-09-28 17:02:31 +01001757}
1758
Mark Brown7c81beb2011-09-20 22:22:32 +01001759static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1760 struct list_head *up_list,
1761 struct list_head *down_list)
1762{
Mark Brown7c81beb2011-09-20 22:22:32 +01001763 int power;
1764
1765 switch (w->id) {
1766 case snd_soc_dapm_pre:
1767 dapm_seq_insert(w, down_list, false);
1768 break;
1769 case snd_soc_dapm_post:
1770 dapm_seq_insert(w, up_list, true);
1771 break;
1772
1773 default:
Mark Brownd8050022011-09-28 18:28:23 +01001774 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001775
Mark Brown05623c42011-09-28 17:02:31 +01001776 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001777 break;
1778 }
1779}
1780
Mark Brown42aa3412009-03-01 19:21:10 +00001781/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001782 * Scan each dapm widget for complete audio path.
1783 * A complete path is a route that has valid endpoints i.e.:-
1784 *
1785 * o DAC to output pin.
1786 * o Input Pin to ADC.
1787 * o Input pin to Output pin (bypass, sidetone)
1788 * o DAC to ADC (loopback).
1789 */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001790static int dapm_power_widgets(struct snd_soc_card *card, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001791{
1792 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001793 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001794 LIST_HEAD(up_list);
1795 LIST_HEAD(down_list);
Dan Williams2955b472012-07-09 19:33:25 -07001796 ASYNC_DOMAIN_EXCLUSIVE(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001797 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001798
Mark Brown84e90932010-11-04 00:07:02 -04001799 trace_snd_soc_dapm_start(card);
1800
Mark Brown56fba412011-06-04 11:25:10 +01001801 list_for_each_entry(d, &card->dapm_list, list) {
Mark Brown497098be2012-03-08 15:06:09 +00001802 if (d->idle_bias_off)
1803 d->target_bias_level = SND_SOC_BIAS_OFF;
1804 else
1805 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001806 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001807
Liam Girdwood6c120e12012-02-15 15:15:34 +00001808 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001809
Mark Brown6d3ddc82009-05-16 17:47:29 +01001810 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001811 * lists indicating if they should be powered up or down. We
1812 * only check widgets that have been flagged as dirty but note
1813 * that new widgets may be added to the dirty list while we
1814 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001815 */
Mark Browndb432b42011-10-03 21:06:40 +01001816 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001817 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001818 }
1819
Mark Brownf9de6d72011-09-28 17:19:47 +01001820 list_for_each_entry(w, &card->widgets, list) {
Mark Brown0ff97eb2012-07-20 17:29:34 +01001821 switch (w->id) {
1822 case snd_soc_dapm_pre:
1823 case snd_soc_dapm_post:
1824 /* These widgets always need to be powered */
1825 break;
1826 default:
1827 list_del_init(&w->dirty);
1828 break;
1829 }
Mark Browndb432b42011-10-03 21:06:40 +01001830
Lars-Peter Clausen39eb5fd2013-07-29 17:14:03 +02001831 if (w->new_power) {
Mark Brownf9de6d72011-09-28 17:19:47 +01001832 d = w->dapm;
1833
1834 /* Supplies and micbiases only bring the
1835 * context up to STANDBY as unless something
1836 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001837 * generally don't require full power. Signal
1838 * generators are virtual pins and have no
1839 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001840 */
1841 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001842 case snd_soc_dapm_siggen:
Lars-Peter Clausenda83fea2013-10-05 19:26:17 +02001843 case snd_soc_dapm_vmid:
Mark Brownafe62362012-01-25 19:55:22 +00001844 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001845 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001846 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001847 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001848 case snd_soc_dapm_micbias:
1849 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1850 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1851 break;
1852 default:
1853 d->target_bias_level = SND_SOC_BIAS_ON;
1854 break;
1855 }
1856 }
1857
1858 }
1859
Mark Brown85a843c2011-09-21 21:29:47 +01001860 /* Force all contexts in the card to the same bias state if
1861 * they're not ground referenced.
1862 */
Mark Brown56fba412011-06-04 11:25:10 +01001863 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001864 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001865 if (d->target_bias_level > bias)
1866 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001867 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown85a843c2011-09-21 21:29:47 +01001868 if (!d->idle_bias_off)
1869 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001870
Mark Brownde02d072011-09-20 21:43:24 +01001871 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001872
Mark Brown9d0624a2011-02-18 11:49:43 -08001873 /* Run all the bias changes in parallel */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001874 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown9d0624a2011-02-18 11:49:43 -08001875 async_schedule_domain(dapm_pre_sequence_async, d,
1876 &async_domain);
1877 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001878
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001879 list_for_each_entry(w, &down_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001880 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
Mark Brown80114122013-02-25 15:14:19 +00001881 }
1882
Lars-Peter Clausencf1f7c62013-05-23 00:12:53 +02001883 list_for_each_entry(w, &up_list, power_list) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001884 dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
Mark Brown80114122013-02-25 15:14:19 +00001885 }
1886
Mark Brown6d3ddc82009-05-16 17:47:29 +01001887 /* Power down widgets first; try to avoid amplifying pops. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001888 dapm_seq_run(card, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001889
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001890 dapm_widget_update(card);
Mark Brown97404f22010-12-14 16:13:57 +00001891
Mark Brown6d3ddc82009-05-16 17:47:29 +01001892 /* Now power up. */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001893 dapm_seq_run(card, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001894
Mark Brown9d0624a2011-02-18 11:49:43 -08001895 /* Run all the bias changes in parallel */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001896 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown9d0624a2011-02-18 11:49:43 -08001897 async_schedule_domain(dapm_post_sequence_async, d,
1898 &async_domain);
1899 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001900
Liam Girdwood8078d872012-02-15 15:15:35 +00001901 /* do we need to notify any clients that DAPM event is complete */
1902 list_for_each_entry(d, &card->dapm_list, list) {
1903 if (d->stream_event)
1904 d->stream_event(d, event);
1905 }
1906
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02001907 pop_dbg(card->dev, card->pop_time,
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001908 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001909 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001910
Mark Brown84e90932010-11-04 00:07:02 -04001911 trace_snd_soc_dapm_done(card);
1912
Mark Brown42aa3412009-03-01 19:21:10 +00001913 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001914}
1915
Mark Brown79fb9382009-08-21 16:38:13 +01001916#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001917static ssize_t dapm_widget_power_read_file(struct file *file,
1918 char __user *user_buf,
1919 size_t count, loff_t *ppos)
1920{
1921 struct snd_soc_dapm_widget *w = file->private_data;
1922 char *buf;
1923 int in, out;
1924 ssize_t ret;
1925 struct snd_soc_dapm_path *p = NULL;
1926
1927 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1928 if (!buf)
1929 return -ENOMEM;
1930
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001931 in = is_connected_input_ep(w, NULL);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001932 dapm_clear_walk_input(w->dapm, &w->sources);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001933 out = is_connected_output_ep(w, NULL);
Ryo Tsutsui1059ecf2013-04-01 12:50:01 +01001934 dapm_clear_walk_output(w->dapm, &w->sinks);
Mark Brown79fb9382009-08-21 16:38:13 +01001935
Mark Brownf13ebad2012-03-03 18:01:01 +00001936 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1937 w->name, w->power ? "On" : "Off",
1938 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001939
Mark Brownd033c362009-12-04 15:25:56 +00001940 if (w->reg >= 0)
1941 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02001942 " - R%d(0x%x) mask 0x%x",
1943 w->reg, w->reg, w->mask << w->shift);
Mark Brownd033c362009-12-04 15:25:56 +00001944
1945 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1946
Mark Brown3eef08b2009-09-14 16:49:00 +01001947 if (w->sname)
1948 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1949 w->sname,
1950 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001951
1952 list_for_each_entry(p, &w->sources, list_sink) {
Takashi Iwaiff186202013-10-28 14:21:49 +01001953 if (p->connected && !p->connected(w, p->source))
Mark Brown215edda2009-09-08 18:59:05 +01001954 continue;
1955
Mark Brown79fb9382009-08-21 16:38:13 +01001956 if (p->connect)
1957 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001958 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001959 p->name ? p->name : "static",
1960 p->source->name);
1961 }
1962 list_for_each_entry(p, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001963 if (p->connected && !p->connected(w, p->sink))
1964 continue;
1965
Mark Brown79fb9382009-08-21 16:38:13 +01001966 if (p->connect)
1967 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001968 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001969 p->name ? p->name : "static",
1970 p->sink->name);
1971 }
1972
1973 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1974
1975 kfree(buf);
1976 return ret;
1977}
1978
1979static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001980 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01001981 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001982 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001983};
1984
Mark Brownef49e4f2011-04-04 20:48:13 +09001985static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1986 size_t count, loff_t *ppos)
1987{
1988 struct snd_soc_dapm_context *dapm = file->private_data;
1989 char *level;
1990
1991 switch (dapm->bias_level) {
1992 case SND_SOC_BIAS_ON:
1993 level = "On\n";
1994 break;
1995 case SND_SOC_BIAS_PREPARE:
1996 level = "Prepare\n";
1997 break;
1998 case SND_SOC_BIAS_STANDBY:
1999 level = "Standby\n";
2000 break;
2001 case SND_SOC_BIAS_OFF:
2002 level = "Off\n";
2003 break;
2004 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01002005 WARN(1, "Unknown bias_level %d\n", dapm->bias_level);
Mark Brownef49e4f2011-04-04 20:48:13 +09002006 level = "Unknown\n";
2007 break;
2008 }
2009
2010 return simple_read_from_buffer(user_buf, count, ppos, level,
2011 strlen(level));
2012}
2013
2014static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07002015 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09002016 .read = dapm_bias_read_file,
2017 .llseek = default_llseek,
2018};
2019
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002020void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2021 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002022{
Mark Brown79fb9382009-08-21 16:38:13 +01002023 struct dentry *d;
2024
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002025 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
2026
2027 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00002028 dev_warn(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002029 "ASoC: Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002030 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002031 }
Mark Brown79fb9382009-08-21 16:38:13 +01002032
Mark Brownef49e4f2011-04-04 20:48:13 +09002033 d = debugfs_create_file("bias_level", 0444,
2034 dapm->debugfs_dapm, dapm,
2035 &dapm_bias_fops);
2036 if (!d)
2037 dev_warn(dapm->dev,
2038 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01002039}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002040
2041static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2042{
2043 struct snd_soc_dapm_context *dapm = w->dapm;
2044 struct dentry *d;
2045
2046 if (!dapm->debugfs_dapm || !w->name)
2047 return;
2048
2049 d = debugfs_create_file(w->name, 0444,
2050 dapm->debugfs_dapm, w,
2051 &dapm_widget_power_fops);
2052 if (!d)
2053 dev_warn(w->dapm->dev,
2054 "ASoC: Failed to create %s debugfs file\n",
2055 w->name);
2056}
2057
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002058static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2059{
2060 debugfs_remove_recursive(dapm->debugfs_dapm);
2061}
2062
Mark Brown79fb9382009-08-21 16:38:13 +01002063#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02002064void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
2065 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01002066{
2067}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002068
2069static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
2070{
2071}
2072
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002073static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
2074{
2075}
2076
Mark Brown79fb9382009-08-21 16:38:13 +01002077#endif
2078
Richard Purdie2b97eab2006-10-06 18:32:18 +02002079/* test and update the power status of a mux widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002080static int soc_dapm_mux_update_power(struct snd_soc_card *card,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002081 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002082{
2083 struct snd_soc_dapm_path *path;
2084 int found = 0;
2085
Richard Purdie2b97eab2006-10-06 18:32:18 +02002086 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002087 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Zhaocb01e2b2008-10-07 08:05:20 +08002088 if (!path->name || !e->texts[mux])
Richard Purdie2b97eab2006-10-06 18:32:18 +02002089 continue;
2090
2091 found = 1;
2092 /* we now need to match the string in the enum to the path */
Mark Browndb432b42011-10-03 21:06:40 +01002093 if (!(strcmp(path->name, e->texts[mux]))) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002094 path->connect = 1; /* new connection */
Mark Brown75c1f892011-10-04 22:28:08 +01002095 dapm_mark_dirty(path->source, "mux connection");
Mark Browndb432b42011-10-03 21:06:40 +01002096 } else {
2097 if (path->connect)
Mark Brown75c1f892011-10-04 22:28:08 +01002098 dapm_mark_dirty(path->source,
2099 "mux disconnection");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002100 path->connect = 0; /* old connection must be powered down */
Mark Browndb432b42011-10-03 21:06:40 +01002101 }
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002102 dapm_mark_dirty(path->sink, "mux change");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002103 }
2104
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002105 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002106 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002107
Liam Girdwood618dae12012-04-25 12:12:51 +01002108 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002109}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002110
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002111int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002112 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
2113 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002114{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002115 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002116 int ret;
2117
Liam Girdwood3cd04342012-03-09 12:02:08 +00002118 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002119 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002120 ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002121 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002122 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002123 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002124 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002125 return ret;
2126}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002127EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002128
Milan plzik1b075e32008-01-10 14:39:46 +01002129/* test and update the power status of a mixer or switch widget */
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002130static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
Mark Brown283375c2009-12-07 18:09:03 +00002131 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002132{
2133 struct snd_soc_dapm_path *path;
2134 int found = 0;
2135
Richard Purdie2b97eab2006-10-06 18:32:18 +02002136 /* find dapm widget path assoc with kcontrol */
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002137 dapm_kcontrol_for_each_path(path, kcontrol) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002138 found = 1;
Mark Brown283375c2009-12-07 18:09:03 +00002139 path->connect = connect;
Mark Brown75c1f892011-10-04 22:28:08 +01002140 dapm_mark_dirty(path->source, "mixer connection");
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002141 dapm_mark_dirty(path->sink, "mixer update");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002142 }
2143
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002144 if (found)
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002145 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002146
Liam Girdwood618dae12012-04-25 12:12:51 +01002147 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002148}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002149
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002150int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
Lars-Peter Clausen6b3fc032013-07-24 15:27:38 +02002151 struct snd_kcontrol *kcontrol, int connect,
2152 struct snd_soc_dapm_update *update)
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002153{
Lars-Peter Clausence6cfaf2013-07-24 15:27:37 +02002154 struct snd_soc_card *card = dapm->card;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002155 int ret;
2156
Liam Girdwood3cd04342012-03-09 12:02:08 +00002157 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002158 card->update = update;
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002159 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002160 card->update = NULL;
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002161 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01002162 if (ret > 0)
Lars-Peter Clausenc3f48ae2013-07-24 15:27:36 +02002163 soc_dpcm_runtime_update(card);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002164 return ret;
2165}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002166EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002167
2168/* show dapm widget status in sys fs */
2169static ssize_t dapm_widget_show(struct device *dev,
2170 struct device_attribute *attr, char *buf)
2171{
Mark Brown36ae1a92012-01-06 17:12:45 -08002172 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00002173 struct snd_soc_codec *codec =rtd->codec;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002174 struct snd_soc_dapm_widget *w;
2175 int count = 0;
2176 char *state = "not set";
2177
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002178 list_for_each_entry(w, &codec->card->widgets, list) {
2179 if (w->dapm != &codec->dapm)
2180 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002181
2182 /* only display widgets that burnm power */
2183 switch (w->id) {
2184 case snd_soc_dapm_hp:
2185 case snd_soc_dapm_mic:
2186 case snd_soc_dapm_spk:
2187 case snd_soc_dapm_line:
2188 case snd_soc_dapm_micbias:
2189 case snd_soc_dapm_dac:
2190 case snd_soc_dapm_adc:
2191 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002192 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002193 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002194 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01002195 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002196 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002197 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002198 if (w->name)
2199 count += sprintf(buf + count, "%s: %s\n",
2200 w->name, w->power ? "On":"Off");
2201 break;
2202 default:
2203 break;
2204 }
2205 }
2206
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002207 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02002208 case SND_SOC_BIAS_ON:
2209 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002210 break;
Mark Brown0be98982008-05-19 12:31:28 +02002211 case SND_SOC_BIAS_PREPARE:
2212 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002213 break;
Mark Brown0be98982008-05-19 12:31:28 +02002214 case SND_SOC_BIAS_STANDBY:
2215 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002216 break;
Mark Brown0be98982008-05-19 12:31:28 +02002217 case SND_SOC_BIAS_OFF:
2218 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02002219 break;
2220 }
2221 count += sprintf(buf + count, "PM State: %s\n", state);
2222
2223 return count;
2224}
2225
2226static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2227
2228int snd_soc_dapm_sys_add(struct device *dev)
2229{
Troy Kisky12ef1932008-10-13 17:42:14 -07002230 return device_create_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002231}
2232
2233static void snd_soc_dapm_sys_remove(struct device *dev)
2234{
Mark Brownaef90842009-05-16 17:53:16 +01002235 device_remove_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002236}
2237
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002238static void dapm_free_path(struct snd_soc_dapm_path *path)
2239{
2240 list_del(&path->list_sink);
2241 list_del(&path->list_source);
Lars-Peter Clausen5106b922013-07-29 17:14:00 +02002242 list_del(&path->list_kcontrol);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002243 list_del(&path->list);
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002244 kfree(path);
2245}
2246
Richard Purdie2b97eab2006-10-06 18:32:18 +02002247/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002248static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002249{
2250 struct snd_soc_dapm_widget *w, *next_w;
2251 struct snd_soc_dapm_path *p, *next_p;
2252
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002253 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2254 if (w->dapm != dapm)
2255 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002256 list_del(&w->list);
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002257 /*
2258 * remove source and sink paths associated to this widget.
2259 * While removing the path, remove reference to it from both
2260 * source and sink widgets so that path is removed only once.
2261 */
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002262 list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
2263 dapm_free_path(p);
2264
2265 list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
2266 dapm_free_path(p);
2267
Stephen Warrenfad59882011-04-28 17:37:59 -06002268 kfree(w->kcontrols);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002269 kfree(w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002270 kfree(w);
2271 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002272}
2273
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002274static struct snd_soc_dapm_widget *dapm_find_widget(
2275 struct snd_soc_dapm_context *dapm, const char *pin,
2276 bool search_other_contexts)
2277{
2278 struct snd_soc_dapm_widget *w;
2279 struct snd_soc_dapm_widget *fallback = NULL;
2280
2281 list_for_each_entry(w, &dapm->card->widgets, list) {
2282 if (!strcmp(w->name, pin)) {
2283 if (w->dapm == dapm)
2284 return w;
2285 else
2286 fallback = w;
2287 }
2288 }
2289
2290 if (search_other_contexts)
2291 return fallback;
2292
2293 return NULL;
2294}
2295
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002296static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002297 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002298{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002299 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002300
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002301 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002302 dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002303 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002304 }
2305
Mark Brown1a8b2d92012-02-16 11:50:07 -08002306 if (w->connected != status)
2307 dapm_mark_dirty(w, "pin configuration");
2308
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002309 w->connected = status;
2310 if (status == 0)
2311 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002312
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002313 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002314}
2315
Richard Purdie2b97eab2006-10-06 18:32:18 +02002316/**
Charles Keepax3eb29df2014-02-18 15:22:15 +00002317 * snd_soc_dapm_sync_unlocked - scan and power dapm paths
2318 * @dapm: DAPM context
2319 *
2320 * Walks all dapm audio paths and powers widgets according to their
2321 * stream or path usage.
2322 *
2323 * Requires external locking.
2324 *
2325 * Returns 0 for success.
2326 */
2327int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm)
2328{
2329 /*
2330 * Suppress early reports (eg, jacks syncing their state) to avoid
2331 * silly DAPM runs during card startup.
2332 */
2333 if (!dapm->card || !dapm->card->instantiated)
2334 return 0;
2335
2336 return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
2337}
2338EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked);
2339
2340/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002341 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002342 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002343 *
2344 * Walks all dapm audio paths and powers widgets according to their
2345 * stream or path usage.
2346 *
2347 * Returns 0 for success.
2348 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002349int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002350{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002351 int ret;
2352
Liam Girdwood3cd04342012-03-09 12:02:08 +00002353 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Charles Keepax3eb29df2014-02-18 15:22:15 +00002354 ret = snd_soc_dapm_sync_unlocked(dapm);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002355 mutex_unlock(&dapm->card->dapm_mutex);
2356 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002357}
Liam Girdwooda5302182008-07-07 13:35:17 +01002358EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002359
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002360static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
2361 struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
2362 const char *control,
2363 int (*connected)(struct snd_soc_dapm_widget *source,
2364 struct snd_soc_dapm_widget *sink))
Richard Purdie2b97eab2006-10-06 18:32:18 +02002365{
2366 struct snd_soc_dapm_path *path;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002367 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002368
2369 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2370 if (!path)
2371 return -ENOMEM;
2372
2373 path->source = wsource;
2374 path->sink = wsink;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002375 path->connected = connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002376 INIT_LIST_HEAD(&path->list);
Mark Brown69c2d342013-08-13 00:20:36 +01002377 INIT_LIST_HEAD(&path->list_kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002378 INIT_LIST_HEAD(&path->list_source);
2379 INIT_LIST_HEAD(&path->list_sink);
2380
2381 /* check for external widgets */
2382 if (wsink->id == snd_soc_dapm_input) {
2383 if (wsource->id == snd_soc_dapm_micbias ||
2384 wsource->id == snd_soc_dapm_mic ||
Rongrong Cao087d53a2009-07-10 20:13:30 +01002385 wsource->id == snd_soc_dapm_line ||
2386 wsource->id == snd_soc_dapm_output)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002387 wsink->ext = 1;
2388 }
2389 if (wsource->id == snd_soc_dapm_output) {
2390 if (wsink->id == snd_soc_dapm_spk ||
2391 wsink->id == snd_soc_dapm_hp ||
Seth Forshee1e392212007-04-16 15:36:42 +02002392 wsink->id == snd_soc_dapm_line ||
2393 wsink->id == snd_soc_dapm_input)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002394 wsource->ext = 1;
2395 }
2396
Lars-Peter Clausen34742cb2013-08-27 15:50:54 +02002397 dapm_mark_dirty(wsource, "Route added");
2398 dapm_mark_dirty(wsink, "Route added");
2399
Richard Purdie2b97eab2006-10-06 18:32:18 +02002400 /* connect static paths */
2401 if (control == NULL) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002402 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002403 list_add(&path->list_sink, &wsink->sources);
2404 list_add(&path->list_source, &wsource->sinks);
2405 path->connect = 1;
2406 return 0;
2407 }
2408
2409 /* connect dynamic paths */
Lu Guanqundc2bea62011-04-20 16:00:36 +08002410 switch (wsink->id) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002411 case snd_soc_dapm_adc:
2412 case snd_soc_dapm_dac:
2413 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002414 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002415 case snd_soc_dapm_input:
2416 case snd_soc_dapm_output:
Mark Brown1ab97c82011-11-27 16:21:51 +00002417 case snd_soc_dapm_siggen:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002418 case snd_soc_dapm_micbias:
2419 case snd_soc_dapm_vmid:
2420 case snd_soc_dapm_pre:
2421 case snd_soc_dapm_post:
Mark Brown246d0a12009-04-22 18:24:55 +01002422 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002423 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002424 case snd_soc_dapm_clock_supply:
Mark Brown010ff262009-08-17 17:39:22 +01002425 case snd_soc_dapm_aif_in:
2426 case snd_soc_dapm_aif_out:
Mark Brown46162742013-06-05 19:36:11 +01002427 case snd_soc_dapm_dai_in:
2428 case snd_soc_dapm_dai_out:
Mark Brownc74184e2012-04-04 22:12:09 +01002429 case snd_soc_dapm_dai_link:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002430 case snd_soc_dapm_kcontrol:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002431 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002432 list_add(&path->list_sink, &wsink->sources);
2433 list_add(&path->list_source, &wsource->sinks);
2434 path->connect = 1;
2435 return 0;
2436 case snd_soc_dapm_mux:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002437 ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
Stephen Warren82cfecd2011-04-28 17:37:58 -06002438 &wsink->kcontrol_news[0]);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002439 if (ret != 0)
2440 goto err;
2441 break;
2442 case snd_soc_dapm_switch:
2443 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002444 case snd_soc_dapm_mixer_named_ctl:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002445 ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002446 if (ret != 0)
2447 goto err;
2448 break;
2449 case snd_soc_dapm_hp:
2450 case snd_soc_dapm_mic:
2451 case snd_soc_dapm_line:
2452 case snd_soc_dapm_spk:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002453 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002454 list_add(&path->list_sink, &wsink->sources);
2455 list_add(&path->list_source, &wsource->sinks);
2456 path->connect = 0;
2457 return 0;
2458 }
Mark Brownfabd0382012-07-05 17:20:06 +01002459
Richard Purdie2b97eab2006-10-06 18:32:18 +02002460 return 0;
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002461err:
2462 kfree(path);
2463 return ret;
2464}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002465
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002466static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Arun Shamanna Lakshmibd23c5b2014-01-15 13:03:16 -08002467 const struct snd_soc_dapm_route *route,
2468 unsigned int is_prefixed)
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002469{
2470 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
2471 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
2472 const char *sink;
2473 const char *source;
2474 char prefixed_sink[80];
2475 char prefixed_source[80];
2476 int ret;
2477
Arun Shamanna Lakshmibd23c5b2014-01-15 13:03:16 -08002478 if (dapm->codec && dapm->codec->name_prefix && !is_prefixed) {
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002479 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2480 dapm->codec->name_prefix, route->sink);
2481 sink = prefixed_sink;
2482 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
2483 dapm->codec->name_prefix, route->source);
2484 source = prefixed_source;
2485 } else {
2486 sink = route->sink;
2487 source = route->source;
2488 }
2489
2490 /*
2491 * find src and dest widgets over all widgets but favor a widget from
2492 * current DAPM context
2493 */
2494 list_for_each_entry(w, &dapm->card->widgets, list) {
2495 if (!wsink && !(strcmp(w->name, sink))) {
2496 wtsink = w;
2497 if (w->dapm == dapm)
2498 wsink = w;
2499 continue;
2500 }
2501 if (!wsource && !(strcmp(w->name, source))) {
2502 wtsource = w;
2503 if (w->dapm == dapm)
2504 wsource = w;
2505 }
2506 }
2507 /* use widget from another DAPM context if not found from this */
2508 if (!wsink)
2509 wsink = wtsink;
2510 if (!wsource)
2511 wsource = wtsource;
2512
2513 if (wsource == NULL) {
2514 dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
2515 route->source);
2516 return -ENODEV;
2517 }
2518 if (wsink == NULL) {
2519 dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
2520 route->sink);
2521 return -ENODEV;
2522 }
2523
2524 ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
2525 route->connected);
2526 if (ret)
2527 goto err;
2528
2529 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002530err:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002531 dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02002532 source, route->control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002533 return ret;
2534}
Mark Brown105f1c22008-05-13 14:52:19 +02002535
Mark Brownefcc3c62012-07-05 17:24:19 +01002536static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
2537 const struct snd_soc_dapm_route *route)
2538{
2539 struct snd_soc_dapm_path *path, *p;
2540 const char *sink;
2541 const char *source;
2542 char prefixed_sink[80];
2543 char prefixed_source[80];
2544
2545 if (route->control) {
2546 dev_err(dapm->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002547 "ASoC: Removal of routes with controls not supported\n");
Mark Brownefcc3c62012-07-05 17:24:19 +01002548 return -EINVAL;
2549 }
2550
2551 if (dapm->codec && dapm->codec->name_prefix) {
2552 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2553 dapm->codec->name_prefix, route->sink);
2554 sink = prefixed_sink;
2555 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
2556 dapm->codec->name_prefix, route->source);
2557 source = prefixed_source;
2558 } else {
2559 sink = route->sink;
2560 source = route->source;
2561 }
2562
2563 path = NULL;
2564 list_for_each_entry(p, &dapm->card->paths, list) {
2565 if (strcmp(p->source->name, source) != 0)
2566 continue;
2567 if (strcmp(p->sink->name, sink) != 0)
2568 continue;
2569 path = p;
2570 break;
2571 }
2572
2573 if (path) {
2574 dapm_mark_dirty(path->source, "Route removed");
2575 dapm_mark_dirty(path->sink, "Route removed");
2576
Lars-Peter Clausen88722932013-06-14 13:16:53 +02002577 dapm_free_path(path);
Mark Brownefcc3c62012-07-05 17:24:19 +01002578 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002579 dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
Mark Brownefcc3c62012-07-05 17:24:19 +01002580 source, sink);
2581 }
2582
2583 return 0;
2584}
2585
Mark Brown105f1c22008-05-13 14:52:19 +02002586/**
Mark Brown105f1c22008-05-13 14:52:19 +02002587 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002588 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002589 * @route: audio routes
2590 * @num: number of routes
2591 *
2592 * Connects 2 dapm widgets together via a named audio path. The sink is
2593 * the widget receiving the audio signal, whilst the source is the sender
2594 * of the audio signal.
2595 *
2596 * Returns 0 for success else error. On error all resources can be freed
2597 * with a call to snd_soc_card_free().
2598 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002599int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002600 const struct snd_soc_dapm_route *route, int num)
2601{
Mark Brown62d4a4b2012-06-22 12:21:49 +01002602 int i, r, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002603
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002604 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002605 for (i = 0; i < num; i++) {
Arun Shamanna Lakshmibd23c5b2014-01-15 13:03:16 -08002606 r = snd_soc_dapm_add_route(dapm, route, false);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002607 if (r < 0) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002608 dev_err(dapm->dev, "ASoC: Failed to add route %s -> %s -> %s\n",
2609 route->source,
2610 route->control ? route->control : "direct",
2611 route->sink);
Mark Brown62d4a4b2012-06-22 12:21:49 +01002612 ret = r;
Mark Brown105f1c22008-05-13 14:52:19 +02002613 }
2614 route++;
2615 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002616 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002617
Dan Carpenter60884c22012-04-13 22:25:43 +03002618 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002619}
2620EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2621
Mark Brownefcc3c62012-07-05 17:24:19 +01002622/**
2623 * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
2624 * @dapm: DAPM context
2625 * @route: audio routes
2626 * @num: number of routes
2627 *
2628 * Removes routes from the DAPM context.
2629 */
2630int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
2631 const struct snd_soc_dapm_route *route, int num)
2632{
2633 int i, ret = 0;
2634
2635 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2636 for (i = 0; i < num; i++) {
2637 snd_soc_dapm_del_route(dapm, route);
2638 route++;
2639 }
2640 mutex_unlock(&dapm->card->dapm_mutex);
2641
2642 return ret;
2643}
2644EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
2645
Mark Brownbf3a9e12011-06-13 16:42:29 +01002646static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2647 const struct snd_soc_dapm_route *route)
2648{
2649 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2650 route->source,
2651 true);
2652 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2653 route->sink,
2654 true);
2655 struct snd_soc_dapm_path *path;
2656 int count = 0;
2657
2658 if (!source) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002659 dev_err(dapm->dev, "ASoC: Unable to find source %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002660 route->source);
2661 return -ENODEV;
2662 }
2663
2664 if (!sink) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002665 dev_err(dapm->dev, "ASoC: Unable to find sink %s for weak route\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002666 route->sink);
2667 return -ENODEV;
2668 }
2669
2670 if (route->control || route->connected)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002671 dev_warn(dapm->dev, "ASoC: Ignoring control for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002672 route->source, route->sink);
2673
2674 list_for_each_entry(path, &source->sinks, list_source) {
2675 if (path->sink == sink) {
2676 path->weak = 1;
2677 count++;
2678 }
2679 }
2680
2681 if (count == 0)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002682 dev_err(dapm->dev, "ASoC: No path found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002683 route->source, route->sink);
2684 if (count > 1)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002685 dev_warn(dapm->dev, "ASoC: %d paths found for weak route %s->%s\n",
Mark Brownbf3a9e12011-06-13 16:42:29 +01002686 count, route->source, route->sink);
2687
2688 return 0;
2689}
2690
2691/**
2692 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2693 * @dapm: DAPM context
2694 * @route: audio routes
2695 * @num: number of routes
2696 *
2697 * Mark existing routes matching those specified in the passed array
2698 * as being weak, meaning that they are ignored for the purpose of
2699 * power decisions. The main intended use case is for sidetone paths
2700 * which couple audio between other independent paths if they are both
2701 * active in order to make the combination work better at the user
2702 * level but which aren't intended to be "used".
2703 *
2704 * Note that CODEC drivers should not use this as sidetone type paths
2705 * can frequently also be used as bypass paths.
2706 */
2707int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2708 const struct snd_soc_dapm_route *route, int num)
2709{
2710 int i, err;
2711 int ret = 0;
2712
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002713 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002714 for (i = 0; i < num; i++) {
2715 err = snd_soc_dapm_weak_route(dapm, route);
2716 if (err)
2717 ret = err;
2718 route++;
2719 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002720 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002721
2722 return ret;
2723}
2724EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2725
Mark Brown105f1c22008-05-13 14:52:19 +02002726/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002727 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002728 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002729 *
2730 * Checks the codec for any new dapm widgets and creates them if found.
2731 *
2732 * Returns 0 for success.
2733 */
Lars-Peter Clausen824ef822013-08-27 15:51:01 +02002734int snd_soc_dapm_new_widgets(struct snd_soc_card *card)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002735{
2736 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002737 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002738
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002739 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002740
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002741 list_for_each_entry(w, &card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002742 {
2743 if (w->new)
2744 continue;
2745
Stephen Warrenfad59882011-04-28 17:37:59 -06002746 if (w->num_kcontrols) {
2747 w->kcontrols = kzalloc(w->num_kcontrols *
2748 sizeof(struct snd_kcontrol *),
2749 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002750 if (!w->kcontrols) {
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002751 mutex_unlock(&card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002752 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002753 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002754 }
2755
Richard Purdie2b97eab2006-10-06 18:32:18 +02002756 switch(w->id) {
2757 case snd_soc_dapm_switch:
2758 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002759 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002760 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002761 break;
2762 case snd_soc_dapm_mux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002763 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002764 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002765 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002766 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002767 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002768 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002769 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002770 break;
2771 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002772
2773 /* Read the initial power state from the device */
2774 if (w->reg >= 0) {
Arun Shamanna Lakshmif7d3c172014-01-14 15:31:54 -08002775 soc_widget_read(w, w->reg, &val);
2776 val = val >> w->shift;
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02002777 val &= w->mask;
2778 if (val == w->on_val)
Mark Brownb66a70d2011-02-09 18:04:11 +00002779 w->power = 1;
2780 }
2781
Richard Purdie2b97eab2006-10-06 18:32:18 +02002782 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002783
Mark Brown7508b122011-10-05 12:09:12 +01002784 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002785 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002786 }
2787
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02002788 dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
2789 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002790 return 0;
2791}
2792EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2793
2794/**
2795 * snd_soc_dapm_get_volsw - dapm mixer get callback
2796 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002797 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002798 *
2799 * Callback to get the value of a dapm mixer control.
2800 *
2801 * Returns 0 for success.
2802 */
2803int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2804 struct snd_ctl_elem_value *ucontrol)
2805{
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +02002806 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002807 struct snd_soc_card *card = codec->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002808 struct soc_mixer_control *mc =
2809 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002810 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002811 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002812 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002813 unsigned int mask = (1 << fls(max)) - 1;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002814 unsigned int invert = mc->invert;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002815 unsigned int val;
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002816
2817 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +02002818 dev_warn(codec->dapm.dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002819 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002820 kcontrol->id.name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002821
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002822 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002823 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002824 val = (snd_soc_read(codec, reg) >> shift) & mask;
2825 else
2826 val = dapm_kcontrol_get_value(kcontrol);
2827 mutex_unlock(&card->dapm_mutex);
2828
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002829 if (invert)
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002830 ucontrol->value.integer.value[0] = max - val;
2831 else
2832 ucontrol->value.integer.value[0] = val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002833
2834 return 0;
2835}
2836EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
2837
2838/**
2839 * snd_soc_dapm_put_volsw - dapm mixer set callback
2840 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002841 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002842 *
2843 * Callback to set the value of a dapm mixer control.
2844 *
2845 * Returns 0 for success.
2846 */
2847int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2848 struct snd_ctl_elem_value *ucontrol)
2849{
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +02002850 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002851 struct snd_soc_card *card = codec->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002852 struct soc_mixer_control *mc =
2853 (struct soc_mixer_control *)kcontrol->private_value;
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002854 int reg = mc->reg;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002855 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002856 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002857 unsigned int mask = (1 << fls(max)) - 1;
2858 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002859 unsigned int val;
Mark Brown97404f22010-12-14 16:13:57 +00002860 int connect, change;
2861 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08002862 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002863
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002864 if (snd_soc_volsw_is_stereo(mc))
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +02002865 dev_warn(codec->dapm.dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00002866 "ASoC: Control '%s' is stereo, which is not supported\n",
Benoît Thébaudeauda602ab2012-07-03 20:18:17 +02002867 kcontrol->id.name);
2868
Richard Purdie2b97eab2006-10-06 18:32:18 +02002869 val = (ucontrol->value.integer.value[0] & mask);
Benoît Thébaudeau8a720712012-06-18 22:41:28 +02002870 connect = !!val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002871
2872 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002873 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002874
Liam Girdwood3cd04342012-03-09 12:02:08 +00002875 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002876
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002877 change = dapm_kcontrol_set_value(kcontrol, val);
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002878
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002879 if (reg != SND_SOC_NOPM) {
2880 mask = mask << shift;
2881 val = val << shift;
Lars-Peter Clausen57295072013-08-05 11:27:31 +02002882
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002883 change = snd_soc_test_bits(codec, reg, mask, val);
2884 }
2885
Mark Brown97404f22010-12-14 16:13:57 +00002886 if (change) {
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002887 if (reg != SND_SOC_NOPM) {
2888 update.kcontrol = kcontrol;
2889 update.reg = reg;
2890 update.mask = mask;
2891 update.val = val;
Mark Brown283375c2009-12-07 18:09:03 +00002892
Lars-Peter Clausen249ce132013-10-06 13:43:49 +02002893 card->update = &update;
2894 }
Mark Brown97404f22010-12-14 16:13:57 +00002895
Nenghua Cao52765972013-12-13 20:13:49 +08002896 ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
Mark Brown97404f22010-12-14 16:13:57 +00002897
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002898 card->update = NULL;
Mark Brown283375c2009-12-07 18:09:03 +00002899 }
2900
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002901 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08002902
2903 if (ret > 0)
2904 soc_dpcm_runtime_update(card);
2905
Lars-Peter Clausen56a67832013-07-24 15:27:35 +02002906 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002907}
2908EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
2909
2910/**
2911 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
2912 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002913 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002914 *
2915 * Callback to get the value of a dapm enumerated double mixer control.
2916 *
2917 * Returns 0 for success.
2918 */
2919int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
2920 struct snd_ctl_elem_value *ucontrol)
2921{
Lars-Peter Clauseneee5d7f2013-07-29 17:13:57 +02002922 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002923 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002924 unsigned int reg_val, val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002925
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002926 if (e->reg != SND_SOC_NOPM)
2927 reg_val = snd_soc_read(codec, e->reg);
2928 else
2929 reg_val = dapm_kcontrol_get_value(kcontrol);
2930
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002931 val = (reg_val >> e->shift_l) & e->mask;
2932 ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
2933 if (e->shift_l != e->shift_r) {
2934 val = (reg_val >> e->shift_r) & e->mask;
2935 val = snd_soc_enum_val_to_item(e, val);
2936 ucontrol->value.enumerated.item[1] = val;
2937 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002938
2939 return 0;
2940}
2941EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
2942
2943/**
2944 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
2945 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002946 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002947 *
2948 * Callback to set the value of a dapm enumerated double mixer control.
2949 *
2950 * Returns 0 for success.
2951 */
2952int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
2953 struct snd_ctl_elem_value *ucontrol)
2954{
Lars-Peter Clausencf7c1de2013-07-29 17:13:59 +02002955 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002956 struct snd_soc_card *card = codec->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002957 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002958 unsigned int *item = ucontrol->value.enumerated.item;
2959 unsigned int val, change;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02002960 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00002961 struct snd_soc_dapm_update update;
Nenghua Cao52765972013-12-13 20:13:49 +08002962 int ret = 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002963
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002964 if (item[0] >= e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002965 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002966
2967 val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02002968 mask = e->mask << e->shift_l;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002969 if (e->shift_l != e->shift_r) {
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002970 if (item[1] > e->items)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002971 return -EINVAL;
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002972 val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l;
Lars-Peter Clausen86767b72012-09-14 13:57:27 +02002973 mask |= e->mask << e->shift_r;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002974 }
2975
Liam Girdwood3cd04342012-03-09 12:02:08 +00002976 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002977
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002978 if (e->reg != SND_SOC_NOPM)
2979 change = snd_soc_test_bits(codec, e->reg, mask, val);
2980 else
2981 change = dapm_kcontrol_set_value(kcontrol, val);
2982
Stephen Warrenfafd2172011-04-28 17:38:00 -06002983 if (change) {
Lars-Peter Clausen236aaa62014-02-28 08:31:11 +01002984 if (e->reg != SND_SOC_NOPM) {
2985 update.kcontrol = kcontrol;
2986 update.reg = e->reg;
2987 update.mask = mask;
2988 update.val = val;
2989 card->update = &update;
2990 }
Mark Brown97404f22010-12-14 16:13:57 +00002991
Lars-Peter Clausen3727b492014-02-28 08:31:04 +01002992 ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
Mark Brown1642e3d2009-10-05 16:24:26 +01002993
Lars-Peter Clausen564c65042013-07-29 17:13:55 +02002994 card->update = NULL;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002995 }
2996
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002997 mutex_unlock(&card->dapm_mutex);
Nenghua Cao52765972013-12-13 20:13:49 +08002998
2999 if (ret > 0)
3000 soc_dpcm_runtime_update(card);
3001
Mark Brown97404f22010-12-14 16:13:57 +00003002 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003003}
3004EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
3005
3006/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00003007 * snd_soc_dapm_info_pin_switch - Info for a pin switch
3008 *
3009 * @kcontrol: mixer control
3010 * @uinfo: control element information
3011 *
3012 * Callback to provide information about a pin switch control.
3013 */
3014int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
3015 struct snd_ctl_elem_info *uinfo)
3016{
3017 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
3018 uinfo->count = 1;
3019 uinfo->value.integer.min = 0;
3020 uinfo->value.integer.max = 1;
3021
3022 return 0;
3023}
3024EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
3025
3026/**
3027 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
3028 *
3029 * @kcontrol: mixer control
3030 * @ucontrol: Value
3031 */
3032int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
3033 struct snd_ctl_elem_value *ucontrol)
3034{
Mark Brown48a8c392012-02-14 17:11:15 -08003035 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003036 const char *pin = (const char *)kcontrol->private_value;
3037
Liam Girdwood3cd04342012-03-09 12:02:08 +00003038 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003039
3040 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08003041 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003042
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003043 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003044
3045 return 0;
3046}
3047EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
3048
3049/**
3050 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
3051 *
3052 * @kcontrol: mixer control
3053 * @ucontrol: Value
3054 */
3055int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
3056 struct snd_ctl_elem_value *ucontrol)
3057{
Mark Brown48a8c392012-02-14 17:11:15 -08003058 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003059 const char *pin = (const char *)kcontrol->private_value;
3060
Mark Brown8b37dbd2009-02-28 21:14:20 +00003061 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08003062 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003063 else
Mark Brown48a8c392012-02-14 17:11:15 -08003064 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003065
Mark Brown48a8c392012-02-14 17:11:15 -08003066 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00003067 return 0;
3068}
3069EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
3070
Mark Brown5ba06fc2012-02-16 11:07:13 -08003071static struct snd_soc_dapm_widget *
3072snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
3073 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003074{
3075 struct snd_soc_dapm_widget *w;
Mark Brown62ea8742012-01-21 21:14:48 +00003076 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003077
3078 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08003079 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003080
Mark Brown62ea8742012-01-21 21:14:48 +00003081 switch (w->id) {
3082 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00003083 w->regulator = devm_regulator_get(dapm->dev, w->name);
3084 if (IS_ERR(w->regulator)) {
3085 ret = PTR_ERR(w->regulator);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003086 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Mark Brown62ea8742012-01-21 21:14:48 +00003087 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003088 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00003089 }
Mark Brown8784c772013-01-10 19:33:47 +00003090
Lars-Peter Clausende9ba982013-07-29 17:14:01 +02003091 if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
Mark Brown8784c772013-01-10 19:33:47 +00003092 ret = regulator_allow_bypass(w->regulator, true);
3093 if (ret != 0)
3094 dev_warn(w->dapm->dev,
Charles Keepax30686c32014-02-18 16:05:27 +00003095 "ASoC: Failed to bypass %s: %d\n",
Mark Brown8784c772013-01-10 19:33:47 +00003096 w->name, ret);
3097 }
Mark Brown62ea8742012-01-21 21:14:48 +00003098 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02003099 case snd_soc_dapm_clock_supply:
Mark Brown165961e2012-06-05 10:44:23 +01003100#ifdef CONFIG_CLKDEV_LOOKUP
Mark Brown695594f12012-06-04 08:14:13 +01003101 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02003102 if (IS_ERR(w->clk)) {
3103 ret = PTR_ERR(w->clk);
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003104 dev_err(dapm->dev, "ASoC: Failed to request %s: %d\n",
Ola Liljad7e7eb92012-05-24 15:26:25 +02003105 w->name, ret);
3106 return NULL;
3107 }
Mark Brownec029952012-06-04 08:16:20 +01003108#else
3109 return NULL;
3110#endif
Ola Liljad7e7eb92012-05-24 15:26:25 +02003111 break;
Mark Brown62ea8742012-01-21 21:14:48 +00003112 default:
3113 break;
3114 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003115
Mark Brown88e8b9a2011-03-02 18:18:24 +00003116 if (dapm->codec && dapm->codec->name_prefix)
Lars-Peter Clausen2b581072013-05-14 11:05:32 +02003117 w->name = kasprintf(GFP_KERNEL, "%s %s",
3118 dapm->codec->name_prefix, widget->name);
3119 else
3120 w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
3121
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003122 if (w->name == NULL) {
3123 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08003124 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003125 }
Jarkko Nikulaead9b912010-11-13 20:40:44 +02003126
Mark Brown7ca3a182011-10-08 14:04:50 +01003127 switch (w->id) {
3128 case snd_soc_dapm_switch:
3129 case snd_soc_dapm_mixer:
3130 case snd_soc_dapm_mixer_named_ctl:
3131 w->power_check = dapm_generic_check_power;
3132 break;
3133 case snd_soc_dapm_mux:
Mark Brown7ca3a182011-10-08 14:04:50 +01003134 w->power_check = dapm_generic_check_power;
3135 break;
Mark Brown46162742013-06-05 19:36:11 +01003136 case snd_soc_dapm_dai_out:
Mark Brown7ca3a182011-10-08 14:04:50 +01003137 w->power_check = dapm_adc_check_power;
3138 break;
Mark Brown46162742013-06-05 19:36:11 +01003139 case snd_soc_dapm_dai_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003140 w->power_check = dapm_dac_check_power;
3141 break;
Mark Brown63c69a62013-07-18 22:03:01 +01003142 case snd_soc_dapm_adc:
3143 case snd_soc_dapm_aif_out:
3144 case snd_soc_dapm_dac:
3145 case snd_soc_dapm_aif_in:
Mark Brown7ca3a182011-10-08 14:04:50 +01003146 case snd_soc_dapm_pga:
3147 case snd_soc_dapm_out_drv:
3148 case snd_soc_dapm_input:
3149 case snd_soc_dapm_output:
3150 case snd_soc_dapm_micbias:
3151 case snd_soc_dapm_spk:
3152 case snd_soc_dapm_hp:
3153 case snd_soc_dapm_mic:
3154 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01003155 case snd_soc_dapm_dai_link:
Mark Brown7ca3a182011-10-08 14:04:50 +01003156 w->power_check = dapm_generic_check_power;
3157 break;
3158 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00003159 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02003160 case snd_soc_dapm_clock_supply:
Lars-Peter Clausen57295072013-08-05 11:27:31 +02003161 case snd_soc_dapm_kcontrol:
Mark Brown7ca3a182011-10-08 14:04:50 +01003162 w->power_check = dapm_supply_check_power;
3163 break;
3164 default:
3165 w->power_check = dapm_always_on_check_power;
3166 break;
3167 }
3168
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003169 w->dapm = dapm;
3170 w->codec = dapm->codec;
Liam Girdwoodb7950642011-07-04 22:10:52 +01003171 w->platform = dapm->platform;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003172 INIT_LIST_HEAD(&w->sources);
3173 INIT_LIST_HEAD(&w->sinks);
3174 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01003175 INIT_LIST_HEAD(&w->dirty);
Jarkko Nikula97c866d2010-12-14 12:18:31 +02003176 list_add(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003177
3178 /* machine layer set ups unconnected pins and insertions */
3179 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08003180 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003181}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003182
3183/**
Mark Brown4ba13272008-05-13 14:51:19 +02003184 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003185 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02003186 * @widget: widget array
3187 * @num: number of widgets
3188 *
3189 * Creates new DAPM controls based upon the templates.
3190 *
3191 * Returns 0 for success else error.
3192 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003193int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003194 const struct snd_soc_dapm_widget *widget,
3195 int num)
3196{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003197 struct snd_soc_dapm_widget *w;
3198 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003199 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003200
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003201 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003202 for (i = 0; i < num; i++) {
Mark Brown5ba06fc2012-02-16 11:07:13 -08003203 w = snd_soc_dapm_new_control(dapm, widget);
3204 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003205 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003206 "ASoC: Failed to create DAPM control %s\n",
3207 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003208 ret = -ENOMEM;
3209 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003210 }
Mark Brown4ba13272008-05-13 14:51:19 +02003211 widget++;
3212 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003213 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003214 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003215}
3216EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3217
Mark Brownc74184e2012-04-04 22:12:09 +01003218static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3219 struct snd_kcontrol *kcontrol, int event)
3220{
3221 struct snd_soc_dapm_path *source_p, *sink_p;
3222 struct snd_soc_dai *source, *sink;
3223 const struct snd_soc_pcm_stream *config = w->params;
3224 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003225 struct snd_pcm_hw_params *params = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003226 u64 fmt;
3227 int ret;
3228
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003229 if (WARN_ON(!config) ||
3230 WARN_ON(list_empty(&w->sources) || list_empty(&w->sinks)))
3231 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003232
3233 /* We only support a single source and sink, pick the first */
3234 source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
3235 list_sink);
3236 sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
3237 list_source);
3238
Takashi Iwaibf4edea2013-11-07 18:38:47 +01003239 if (WARN_ON(!source_p || !sink_p) ||
3240 WARN_ON(!sink_p->source || !source_p->sink) ||
3241 WARN_ON(!source_p->source || !sink_p->sink))
3242 return -EINVAL;
Mark Brownc74184e2012-04-04 22:12:09 +01003243
3244 source = source_p->source->priv;
3245 sink = sink_p->sink->priv;
3246
3247 /* Be a little careful as we don't want to overflow the mask array */
3248 if (config->formats) {
3249 fmt = ffs(config->formats) - 1;
3250 } else {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003251 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003252 config->formats);
3253 fmt = 0;
3254 }
3255
3256 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003257 params = kzalloc(sizeof(*params), GFP_KERNEL);
3258 if (!params) {
3259 ret = -ENOMEM;
3260 goto out;
3261 }
3262 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003263
Mark Brown9747cec2012-04-26 19:12:21 +01003264 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003265 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003266 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003267 config->rate_max;
3268
Mark Brown9747cec2012-04-26 19:12:21 +01003269 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003270 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003271 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003272 = config->channels_max;
3273
3274 memset(&substream, 0, sizeof(substream));
3275
3276 switch (event) {
3277 case SND_SOC_DAPM_PRE_PMU:
3278 if (source->driver->ops && source->driver->ops->hw_params) {
3279 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3280 ret = source->driver->ops->hw_params(&substream,
Mark Brown9747cec2012-04-26 19:12:21 +01003281 params, source);
Mark Brownc74184e2012-04-04 22:12:09 +01003282 if (ret != 0) {
3283 dev_err(source->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003284 "ASoC: hw_params() failed: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003285 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003286 }
3287 }
3288
3289 if (sink->driver->ops && sink->driver->ops->hw_params) {
3290 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
Mark Brown9747cec2012-04-26 19:12:21 +01003291 ret = sink->driver->ops->hw_params(&substream, params,
Mark Brownc74184e2012-04-04 22:12:09 +01003292 sink);
3293 if (ret != 0) {
3294 dev_err(sink->dev,
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003295 "ASoC: hw_params() failed: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003296 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003297 }
3298 }
3299 break;
3300
3301 case SND_SOC_DAPM_POST_PMU:
Mark Brownda183962013-02-06 15:44:07 +00003302 ret = snd_soc_dai_digital_mute(sink, 0,
3303 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003304 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003305 dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003306 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003307 break;
3308
3309 case SND_SOC_DAPM_PRE_PMD:
Mark Brownda183962013-02-06 15:44:07 +00003310 ret = snd_soc_dai_digital_mute(sink, 1,
3311 SNDRV_PCM_STREAM_PLAYBACK);
Mark Brownc74184e2012-04-04 22:12:09 +01003312 if (ret != 0 && ret != -ENOTSUPP)
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003313 dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003314 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003315 break;
3316
3317 default:
Takashi Iwaia6ed0602013-11-06 11:07:19 +01003318 WARN(1, "Unknown event %d\n", event);
Mark Brownc74184e2012-04-04 22:12:09 +01003319 return -EINVAL;
3320 }
3321
Mark Brown9747cec2012-04-26 19:12:21 +01003322out:
3323 kfree(params);
3324 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003325}
3326
3327int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3328 const struct snd_soc_pcm_stream *params,
3329 struct snd_soc_dapm_widget *source,
3330 struct snd_soc_dapm_widget *sink)
3331{
3332 struct snd_soc_dapm_route routes[2];
3333 struct snd_soc_dapm_widget template;
3334 struct snd_soc_dapm_widget *w;
3335 size_t len;
3336 char *link_name;
3337
3338 len = strlen(source->name) + strlen(sink->name) + 2;
3339 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
3340 if (!link_name)
3341 return -ENOMEM;
3342 snprintf(link_name, len, "%s-%s", source->name, sink->name);
3343
3344 memset(&template, 0, sizeof(template));
3345 template.reg = SND_SOC_NOPM;
3346 template.id = snd_soc_dapm_dai_link;
3347 template.name = link_name;
3348 template.event = snd_soc_dai_link_event;
3349 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3350 SND_SOC_DAPM_PRE_PMD;
3351
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003352 dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
Mark Brownc74184e2012-04-04 22:12:09 +01003353
3354 w = snd_soc_dapm_new_control(&card->dapm, &template);
3355 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003356 dev_err(card->dev, "ASoC: Failed to create %s widget\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003357 link_name);
3358 return -ENOMEM;
3359 }
3360
3361 w->params = params;
3362
3363 memset(&routes, 0, sizeof(routes));
3364
3365 routes[0].source = source->name;
3366 routes[0].sink = link_name;
3367 routes[1].source = link_name;
3368 routes[1].sink = sink->name;
3369
3370 return snd_soc_dapm_add_routes(&card->dapm, routes,
3371 ARRAY_SIZE(routes));
3372}
3373
Mark Brown888df392012-02-16 19:37:51 -08003374int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3375 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003376{
Mark Brown888df392012-02-16 19:37:51 -08003377 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003378 struct snd_soc_dapm_widget *w;
3379
Mark Brown888df392012-02-16 19:37:51 -08003380 WARN_ON(dapm->dev != dai->dev);
3381
3382 memset(&template, 0, sizeof(template));
3383 template.reg = SND_SOC_NOPM;
3384
3385 if (dai->driver->playback.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003386 template.id = snd_soc_dapm_dai_in;
Mark Brown888df392012-02-16 19:37:51 -08003387 template.name = dai->driver->playback.stream_name;
3388 template.sname = dai->driver->playback.stream_name;
3389
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003390 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003391 template.name);
3392
3393 w = snd_soc_dapm_new_control(dapm, &template);
3394 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003395 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003396 dai->driver->playback.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003397 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003398 }
3399
3400 w->priv = dai;
3401 dai->playback_widget = w;
3402 }
3403
3404 if (dai->driver->capture.stream_name) {
Mark Brown46162742013-06-05 19:36:11 +01003405 template.id = snd_soc_dapm_dai_out;
Mark Brown888df392012-02-16 19:37:51 -08003406 template.name = dai->driver->capture.stream_name;
3407 template.sname = dai->driver->capture.stream_name;
3408
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003409 dev_dbg(dai->dev, "ASoC: adding %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003410 template.name);
3411
3412 w = snd_soc_dapm_new_control(dapm, &template);
3413 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003414 dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
Mark Brown888df392012-02-16 19:37:51 -08003415 dai->driver->capture.stream_name);
Takashi Iwai298402a2013-10-28 14:21:50 +01003416 return -ENOMEM;
Mark Brown888df392012-02-16 19:37:51 -08003417 }
3418
3419 w->priv = dai;
3420 dai->capture_widget = w;
3421 }
3422
3423 return 0;
3424}
3425
3426int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3427{
3428 struct snd_soc_dapm_widget *dai_w, *w;
3429 struct snd_soc_dai *dai;
Mark Brown888df392012-02-16 19:37:51 -08003430
3431 /* For each DAI widget... */
3432 list_for_each_entry(dai_w, &card->widgets, list) {
Mark Brown46162742013-06-05 19:36:11 +01003433 switch (dai_w->id) {
3434 case snd_soc_dapm_dai_in:
3435 case snd_soc_dapm_dai_out:
3436 break;
3437 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02003438 continue;
Mark Brown46162742013-06-05 19:36:11 +01003439 }
Mark Brown888df392012-02-16 19:37:51 -08003440
3441 dai = dai_w->priv;
3442
3443 /* ...find all widgets with the same stream and link them */
3444 list_for_each_entry(w, &card->widgets, list) {
3445 if (w->dapm != dai_w->dapm)
3446 continue;
3447
Mark Brown46162742013-06-05 19:36:11 +01003448 switch (w->id) {
3449 case snd_soc_dapm_dai_in:
3450 case snd_soc_dapm_dai_out:
Mark Brown888df392012-02-16 19:37:51 -08003451 continue;
Mark Brown46162742013-06-05 19:36:11 +01003452 default:
3453 break;
3454 }
Mark Brown888df392012-02-16 19:37:51 -08003455
Russell King19c2c5f2013-08-04 20:24:03 +01003456 if (!w->sname || !strstr(w->sname, dai_w->name))
Mark Brown888df392012-02-16 19:37:51 -08003457 continue;
3458
3459 if (dai->driver->playback.stream_name &&
3460 strstr(w->sname,
3461 dai->driver->playback.stream_name)) {
Mark Brown888df392012-02-16 19:37:51 -08003462 dev_dbg(dai->dev, "%s -> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02003463 dai->playback_widget->name, w->name);
Mark Brown888df392012-02-16 19:37:51 -08003464
Lars-Peter Clausen25536282013-07-29 17:14:02 +02003465 snd_soc_dapm_add_path(w->dapm,
3466 dai->playback_widget, w, NULL, NULL);
Mark Brown888df392012-02-16 19:37:51 -08003467 }
3468
3469 if (dai->driver->capture.stream_name &&
3470 strstr(w->sname,
3471 dai->driver->capture.stream_name)) {
Mark Brown888df392012-02-16 19:37:51 -08003472 dev_dbg(dai->dev, "%s -> %s\n",
Lars-Peter Clausen25536282013-07-29 17:14:02 +02003473 w->name, dai->capture_widget->name);
Mark Brown888df392012-02-16 19:37:51 -08003474
Lars-Peter Clausen25536282013-07-29 17:14:02 +02003475 snd_soc_dapm_add_path(w->dapm, w,
3476 dai->capture_widget, NULL, NULL);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003477 }
3478 }
3479 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003480
Mark Brown888df392012-02-16 19:37:51 -08003481 return 0;
3482}
Liam Girdwood64a648c2011-07-25 11:15:15 +01003483
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003484void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card)
3485{
3486 struct snd_soc_pcm_runtime *rtd = card->rtd;
3487 struct snd_soc_dai *cpu_dai, *codec_dai;
3488 struct snd_soc_dapm_route r;
3489 int i;
3490
3491 memset(&r, 0, sizeof(r));
3492
3493 /* for each BE DAI link... */
3494 for (i = 0; i < card->num_rtd; i++) {
3495 rtd = &card->rtd[i];
3496 cpu_dai = rtd->cpu_dai;
3497 codec_dai = rtd->codec_dai;
3498
3499 /* dynamic FE links have no fixed DAI mapping */
3500 if (rtd->dai_link->dynamic)
3501 continue;
3502
3503 /* there is no point in connecting BE DAI links with dummies */
3504 if (snd_soc_dai_is_dummy(codec_dai) ||
3505 snd_soc_dai_is_dummy(cpu_dai))
3506 continue;
3507
3508 /* connect BE DAI playback if widgets are valid */
3509 if (codec_dai->playback_widget && cpu_dai->playback_widget) {
3510 r.source = cpu_dai->playback_widget->name;
3511 r.sink = codec_dai->playback_widget->name;
3512 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
3513 cpu_dai->codec->name, r.source,
3514 codec_dai->platform->name, r.sink);
3515
Arun Shamanna Lakshmibd23c5b2014-01-15 13:03:16 -08003516 snd_soc_dapm_add_route(&card->dapm, &r, true);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003517 }
3518
3519 /* connect BE DAI capture if widgets are valid */
3520 if (codec_dai->capture_widget && cpu_dai->capture_widget) {
3521 r.source = codec_dai->capture_widget->name;
3522 r.sink = cpu_dai->capture_widget->name;
3523 dev_dbg(rtd->dev, "connected DAI link %s:%s -> %s:%s\n",
3524 codec_dai->codec->name, r.source,
3525 cpu_dai->platform->name, r.sink);
3526
Arun Shamanna Lakshmibd23c5b2014-01-15 13:03:16 -08003527 snd_soc_dapm_add_route(&card->dapm, &r, true);
Liam Girdwoodb893ea52014-01-08 10:40:19 +00003528 }
3529
3530 }
3531}
3532
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003533static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3534 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003535{
Mark Brown7bd3a6f2012-02-16 15:03:27 -08003536
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003537 struct snd_soc_dapm_widget *w_cpu, *w_codec;
3538 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
3539 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Mark Brown7bd3a6f2012-02-16 15:03:27 -08003540
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003541 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
3542 w_cpu = cpu_dai->playback_widget;
3543 w_codec = codec_dai->playback_widget;
3544 } else {
3545 w_cpu = cpu_dai->capture_widget;
3546 w_codec = codec_dai->capture_widget;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003547 }
3548
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003549 if (w_cpu) {
3550
3551 dapm_mark_dirty(w_cpu, "stream event");
3552
3553 switch (event) {
3554 case SND_SOC_DAPM_STREAM_START:
3555 w_cpu->active = 1;
3556 break;
3557 case SND_SOC_DAPM_STREAM_STOP:
3558 w_cpu->active = 0;
3559 break;
3560 case SND_SOC_DAPM_STREAM_SUSPEND:
3561 case SND_SOC_DAPM_STREAM_RESUME:
3562 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3563 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3564 break;
3565 }
3566 }
3567
3568 if (w_codec) {
3569
3570 dapm_mark_dirty(w_codec, "stream event");
3571
3572 switch (event) {
3573 case SND_SOC_DAPM_STREAM_START:
3574 w_codec->active = 1;
3575 break;
3576 case SND_SOC_DAPM_STREAM_STOP:
3577 w_codec->active = 0;
3578 break;
3579 case SND_SOC_DAPM_STREAM_SUSPEND:
3580 case SND_SOC_DAPM_STREAM_RESUME:
3581 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3582 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3583 break;
3584 }
3585 }
3586
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003587 dapm_power_widgets(rtd->card, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003588}
3589
3590/**
3591 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3592 * @rtd: PCM runtime data
3593 * @stream: stream name
3594 * @event: stream event
3595 *
3596 * Sends a stream event to the dapm core. The core then makes any
3597 * necessary widget power changes.
3598 *
3599 * Returns 0 for success else error.
3600 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003601void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3602 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003603{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003604 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003605
Liam Girdwood3cd04342012-03-09 12:02:08 +00003606 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003607 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003608 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003609}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003610
3611/**
Charles Keepax11391102014-02-18 15:22:14 +00003612 * snd_soc_dapm_enable_pin_unlocked - enable pin.
3613 * @dapm: DAPM context
3614 * @pin: pin name
3615 *
3616 * Enables input/output pin and its parents or children widgets iff there is
3617 * a valid audio route and active audio stream.
3618 *
3619 * Requires external locking.
3620 *
3621 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3622 * do any widget power switching.
3623 */
3624int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3625 const char *pin)
3626{
3627 return snd_soc_dapm_set_pin(dapm, pin, 1);
3628}
3629EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
3630
3631/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003632 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003633 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003634 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02003635 *
Mark Brown74b8f952009-06-06 11:26:15 +01003636 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01003637 * a valid audio route and active audio stream.
Charles Keepax11391102014-02-18 15:22:14 +00003638 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003639 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3640 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02003641 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003642int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003643{
Charles Keepax11391102014-02-18 15:22:14 +00003644 int ret;
3645
3646 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3647
3648 ret = snd_soc_dapm_set_pin(dapm, pin, 1);
3649
3650 mutex_unlock(&dapm->card->dapm_mutex);
3651
3652 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003653}
Liam Girdwooda5302182008-07-07 13:35:17 +01003654EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003655
3656/**
Charles Keepax11391102014-02-18 15:22:14 +00003657 * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
3658 * @dapm: DAPM context
3659 * @pin: pin name
3660 *
3661 * Enables input/output pin regardless of any other state. This is
3662 * intended for use with microphone bias supplies used in microphone
3663 * jack detection.
3664 *
3665 * Requires external locking.
3666 *
3667 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3668 * do any widget power switching.
3669 */
3670int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3671 const char *pin)
3672{
3673 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
3674
3675 if (!w) {
3676 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
3677 return -EINVAL;
3678 }
3679
3680 dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
3681 w->connected = 1;
3682 w->force = 1;
3683 dapm_mark_dirty(w, "force enable");
3684
3685 return 0;
3686}
3687EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
3688
3689/**
Mark Brownda341832010-03-15 19:23:37 +00003690 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003691 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00003692 * @pin: pin name
3693 *
3694 * Enables input/output pin regardless of any other state. This is
3695 * intended for use with microphone bias supplies used in microphone
3696 * jack detection.
3697 *
3698 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3699 * do any widget power switching.
3700 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003701int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
3702 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00003703{
Charles Keepax11391102014-02-18 15:22:14 +00003704 int ret;
Mark Brownda341832010-03-15 19:23:37 +00003705
Charles Keepax11391102014-02-18 15:22:14 +00003706 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownda341832010-03-15 19:23:37 +00003707
Charles Keepax11391102014-02-18 15:22:14 +00003708 ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
Mark Brown0d867332011-04-06 11:38:14 +09003709
Charles Keepax11391102014-02-18 15:22:14 +00003710 mutex_unlock(&dapm->card->dapm_mutex);
3711
3712 return ret;
Mark Brownda341832010-03-15 19:23:37 +00003713}
3714EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
3715
3716/**
Charles Keepax11391102014-02-18 15:22:14 +00003717 * snd_soc_dapm_disable_pin_unlocked - disable pin.
3718 * @dapm: DAPM context
3719 * @pin: pin name
3720 *
3721 * Disables input/output pin and its parents or children widgets.
3722 *
3723 * Requires external locking.
3724 *
3725 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3726 * do any widget power switching.
3727 */
3728int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
3729 const char *pin)
3730{
3731 return snd_soc_dapm_set_pin(dapm, pin, 0);
3732}
3733EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
3734
3735/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003736 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003737 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003738 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003739 *
Mark Brown74b8f952009-06-06 11:26:15 +01003740 * Disables input/output pin and its parents or children widgets.
Charles Keepax11391102014-02-18 15:22:14 +00003741 *
Liam Girdwooda5302182008-07-07 13:35:17 +01003742 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3743 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003744 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003745int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
3746 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01003747{
Charles Keepax11391102014-02-18 15:22:14 +00003748 int ret;
3749
3750 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3751
3752 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
3753
3754 mutex_unlock(&dapm->card->dapm_mutex);
3755
3756 return ret;
Liam Girdwooda5302182008-07-07 13:35:17 +01003757}
3758EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
3759
3760/**
Charles Keepax11391102014-02-18 15:22:14 +00003761 * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
3762 * @dapm: DAPM context
3763 * @pin: pin name
3764 *
3765 * Marks the specified pin as being not connected, disabling it along
3766 * any parent or child widgets. At present this is identical to
3767 * snd_soc_dapm_disable_pin() but in future it will be extended to do
3768 * additional things such as disabling controls which only affect
3769 * paths through the pin.
3770 *
3771 * Requires external locking.
3772 *
3773 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3774 * do any widget power switching.
3775 */
3776int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
3777 const char *pin)
3778{
3779 return snd_soc_dapm_set_pin(dapm, pin, 0);
3780}
3781EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
3782
3783/**
Mark Brown5817b522008-09-24 11:23:11 +01003784 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003785 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01003786 * @pin: pin name
3787 *
3788 * Marks the specified pin as being not connected, disabling it along
3789 * any parent or child widgets. At present this is identical to
3790 * snd_soc_dapm_disable_pin() but in future it will be extended to do
3791 * additional things such as disabling controls which only affect
3792 * paths through the pin.
3793 *
3794 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3795 * do any widget power switching.
3796 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003797int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01003798{
Charles Keepax11391102014-02-18 15:22:14 +00003799 int ret;
3800
3801 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
3802
3803 ret = snd_soc_dapm_set_pin(dapm, pin, 0);
3804
3805 mutex_unlock(&dapm->card->dapm_mutex);
3806
3807 return ret;
Mark Brown5817b522008-09-24 11:23:11 +01003808}
3809EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
3810
3811/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003812 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003813 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003814 * @pin: audio signal pin endpoint (or start point)
3815 *
3816 * Get audio pin status - connected or disconnected.
3817 *
3818 * Returns 1 for connected otherwise 0.
3819 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003820int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
3821 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003822{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003823 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003824
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003825 if (w)
3826 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06003827
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003828 return 0;
3829}
Liam Girdwooda5302182008-07-07 13:35:17 +01003830EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003831
3832/**
Mark Brown1547aba2010-05-07 21:11:40 +01003833 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003834 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01003835 * @pin: audio signal pin endpoint (or start point)
3836 *
3837 * Mark the given endpoint or pin as ignoring suspend. When the
3838 * system is disabled a path between two endpoints flagged as ignoring
3839 * suspend will not be disabled. The path must already be enabled via
3840 * normal means at suspend time, it will not be turned on if it was not
3841 * already enabled.
3842 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003843int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
3844 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01003845{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003846 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01003847
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003848 if (!w) {
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003849 dev_err(dapm->dev, "ASoC: unknown pin %s\n", pin);
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003850 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01003851 }
3852
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003853 w->ignore_suspend = 1;
3854
3855 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01003856}
3857EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
3858
Stephen Warren16332812011-11-23 12:42:04 -07003859static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
3860 struct snd_soc_dapm_widget *w)
3861{
3862 struct snd_soc_dapm_path *p;
3863
3864 list_for_each_entry(p, &card->paths, list) {
3865 if ((p->source == w) || (p->sink == w)) {
3866 dev_dbg(card->dev,
3867 "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
3868 p->source->name, p->source->id, p->source->dapm,
3869 p->sink->name, p->sink->id, p->sink->dapm);
3870
3871 /* Connected to something other than the codec */
3872 if (p->source->dapm != p->sink->dapm)
3873 return true;
3874 /*
3875 * Loopback connection from codec external pin to
3876 * codec external pin
3877 */
3878 if (p->sink->id == snd_soc_dapm_input) {
3879 switch (p->source->id) {
3880 case snd_soc_dapm_output:
3881 case snd_soc_dapm_micbias:
3882 return true;
3883 default:
3884 break;
3885 }
3886 }
3887 }
3888 }
3889
3890 return false;
3891}
3892
3893/**
3894 * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins
3895 * @codec: The codec whose pins should be processed
3896 *
3897 * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec
3898 * which are unused. Pins are used if they are connected externally to the
3899 * codec, whether that be to some other device, or a loop-back connection to
3900 * the codec itself.
3901 */
3902void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec)
3903{
3904 struct snd_soc_card *card = codec->card;
3905 struct snd_soc_dapm_context *dapm = &codec->dapm;
3906 struct snd_soc_dapm_widget *w;
3907
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003908 dev_dbg(codec->dev, "ASoC: Auto NC: DAPMs: card:%p codec:%p\n",
Stephen Warren16332812011-11-23 12:42:04 -07003909 &card->dapm, &codec->dapm);
3910
3911 list_for_each_entry(w, &card->widgets, list) {
3912 if (w->dapm != dapm)
3913 continue;
3914 switch (w->id) {
3915 case snd_soc_dapm_input:
3916 case snd_soc_dapm_output:
3917 case snd_soc_dapm_micbias:
Liam Girdwood30a6a1a2012-11-19 14:39:12 +00003918 dev_dbg(codec->dev, "ASoC: Auto NC: Checking widget %s\n",
Stephen Warren16332812011-11-23 12:42:04 -07003919 w->name);
3920 if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
Mark Browna094b802011-11-27 19:42:20 +00003921 dev_dbg(codec->dev,
Stephen Warren16332812011-11-23 12:42:04 -07003922 "... Not in map; disabling\n");
3923 snd_soc_dapm_nc_pin(dapm, w->name);
3924 }
3925 break;
3926 default:
3927 break;
3928 }
3929 }
3930}
3931
Mark Brown1547aba2010-05-07 21:11:40 +01003932/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02003933 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03003934 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02003935 *
3936 * Free all dapm widgets and resources.
3937 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003938void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003939{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003940 snd_soc_dapm_sys_remove(dapm->dev);
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02003941 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003942 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02003943 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003944}
3945EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
3946
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003947static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01003948{
Liam Girdwood01005a72012-07-06 16:57:05 +01003949 struct snd_soc_card *card = dapm->card;
Mark Brown51737472009-06-22 13:16:51 +01003950 struct snd_soc_dapm_widget *w;
3951 LIST_HEAD(down_list);
3952 int powerdown = 0;
3953
Liam Girdwood01005a72012-07-06 16:57:05 +01003954 mutex_lock(&card->dapm_mutex);
3955
Jarkko Nikula97c866d2010-12-14 12:18:31 +02003956 list_for_each_entry(w, &dapm->card->widgets, list) {
3957 if (w->dapm != dapm)
3958 continue;
Mark Brown51737472009-06-22 13:16:51 +01003959 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00003960 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01003961 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01003962 powerdown = 1;
3963 }
3964 }
3965
3966 /* If there were no widgets to power down we're already in
3967 * standby.
3968 */
3969 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00003970 if (dapm->bias_level == SND_SOC_BIAS_ON)
3971 snd_soc_dapm_set_bias_level(dapm,
3972 SND_SOC_BIAS_PREPARE);
Lars-Peter Clausen95dd5cd2013-07-29 17:13:56 +02003973 dapm_seq_run(card, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00003974 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
3975 snd_soc_dapm_set_bias_level(dapm,
3976 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01003977 }
Liam Girdwood01005a72012-07-06 16:57:05 +01003978
3979 mutex_unlock(&card->dapm_mutex);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00003980}
Mark Brown51737472009-06-22 13:16:51 +01003981
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00003982/*
3983 * snd_soc_dapm_shutdown - callback for system shutdown
3984 */
3985void snd_soc_dapm_shutdown(struct snd_soc_card *card)
3986{
3987 struct snd_soc_codec *codec;
3988
Misael Lopez Cruz445632a2012-11-08 12:03:12 -06003989 list_for_each_entry(codec, &card->codec_dev_list, card_list) {
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003990 soc_dapm_shutdown_codec(&codec->dapm);
Mark Brown7679e422012-02-22 15:52:56 +00003991 if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
3992 snd_soc_dapm_set_bias_level(&codec->dapm,
3993 SND_SOC_BIAS_OFF);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003994 }
Mark Brown51737472009-06-22 13:16:51 +01003995}
3996
Richard Purdie2b97eab2006-10-06 18:32:18 +02003997/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01003998MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02003999MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
4000MODULE_LICENSE("GPL");