blob: 0c94027c4e3b30c716254776aae9f07231e42cf2 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090038#include <linux/slab.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020039#include <sound/core.h>
40#include <sound/pcm.h>
41#include <sound/pcm_params.h>
Liam Girdwoodce6120c2010-11-05 15:53:46 +020042#include <sound/soc.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020043#include <sound/initval.h>
44
Mark Brown84e90932010-11-04 00:07:02 -040045#include <trace/events/asoc.h>
46
Mark Brownde02d072011-09-20 21:43:24 +010047#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
48
Richard Purdie2b97eab2006-10-06 18:32:18 +020049/* dapm power sequences - make this per codec in the future */
50static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010051 [snd_soc_dapm_pre] = 0,
52 [snd_soc_dapm_supply] = 1,
Mark Brown62ea8742012-01-21 21:14:48 +000053 [snd_soc_dapm_regulator_supply] = 1,
Mark Brown38357ab2009-06-06 19:03:23 +010054 [snd_soc_dapm_micbias] = 2,
Mark Brown010ff262009-08-17 17:39:22 +010055 [snd_soc_dapm_aif_in] = 3,
56 [snd_soc_dapm_aif_out] = 3,
57 [snd_soc_dapm_mic] = 4,
58 [snd_soc_dapm_mux] = 5,
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +000059 [snd_soc_dapm_virt_mux] = 5,
Mark Brown010ff262009-08-17 17:39:22 +010060 [snd_soc_dapm_value_mux] = 5,
61 [snd_soc_dapm_dac] = 6,
62 [snd_soc_dapm_mixer] = 7,
63 [snd_soc_dapm_mixer_named_ctl] = 7,
64 [snd_soc_dapm_pga] = 8,
65 [snd_soc_dapm_adc] = 9,
Olaya, Margaritad88429a2010-12-10 21:11:44 -060066 [snd_soc_dapm_out_drv] = 10,
Mark Brown010ff262009-08-17 17:39:22 +010067 [snd_soc_dapm_hp] = 10,
68 [snd_soc_dapm_spk] = 10,
69 [snd_soc_dapm_post] = 11,
Richard Purdie2b97eab2006-10-06 18:32:18 +020070};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000071
Richard Purdie2b97eab2006-10-06 18:32:18 +020072static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010073 [snd_soc_dapm_pre] = 0,
74 [snd_soc_dapm_adc] = 1,
75 [snd_soc_dapm_hp] = 2,
Mark Brown1ca04062009-08-17 16:26:59 +010076 [snd_soc_dapm_spk] = 2,
Olaya, Margaritad88429a2010-12-10 21:11:44 -060077 [snd_soc_dapm_out_drv] = 2,
Mark Brown38357ab2009-06-06 19:03:23 +010078 [snd_soc_dapm_pga] = 4,
79 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +010080 [snd_soc_dapm_mixer] = 5,
81 [snd_soc_dapm_dac] = 6,
82 [snd_soc_dapm_mic] = 7,
83 [snd_soc_dapm_micbias] = 8,
84 [snd_soc_dapm_mux] = 9,
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +000085 [snd_soc_dapm_virt_mux] = 9,
Mark Browne3d4dab2009-06-07 13:08:45 +010086 [snd_soc_dapm_value_mux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +010087 [snd_soc_dapm_aif_in] = 10,
88 [snd_soc_dapm_aif_out] = 10,
Mark Brown62ea8742012-01-21 21:14:48 +000089 [snd_soc_dapm_regulator_supply] = 11,
Mark Brown010ff262009-08-17 17:39:22 +010090 [snd_soc_dapm_supply] = 11,
91 [snd_soc_dapm_post] = 12,
Richard Purdie2b97eab2006-10-06 18:32:18 +020092};
93
Troy Kisky12ef1932008-10-13 17:42:14 -070094static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +010095{
96 if (pop_time)
97 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
98}
99
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200100static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100101{
102 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200103 char *buf;
104
105 if (!pop_time)
106 return;
107
108 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
109 if (buf == NULL)
110 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100111
112 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200113 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100114 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100115 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200116
117 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100118}
119
Mark Browndb432b42011-10-03 21:06:40 +0100120static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
121{
122 return !list_empty(&w->dirty);
123}
124
Mark Brown25c77c52011-10-08 13:36:03 +0100125void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100126{
Mark Brown75c1f892011-10-04 22:28:08 +0100127 if (!dapm_dirty_widget(w)) {
128 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
129 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100130 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100131 }
Mark Browndb432b42011-10-03 21:06:40 +0100132}
Mark Brown25c77c52011-10-08 13:36:03 +0100133EXPORT_SYMBOL_GPL(dapm_mark_dirty);
Mark Browndb432b42011-10-03 21:06:40 +0100134
Richard Purdie2b97eab2006-10-06 18:32:18 +0200135/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100136static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200137 const struct snd_soc_dapm_widget *_widget)
138{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100139 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200140}
141
Liam Girdwood48056082011-07-20 12:23:33 +0100142/* get snd_card from DAPM context */
143static inline struct snd_card *dapm_get_snd_card(
144 struct snd_soc_dapm_context *dapm)
145{
146 if (dapm->codec)
147 return dapm->codec->card->snd_card;
148 else if (dapm->platform)
149 return dapm->platform->card->snd_card;
150 else
151 BUG();
152
153 /* unreachable */
154 return NULL;
155}
156
157/* get soc_card from DAPM context */
158static inline struct snd_soc_card *dapm_get_soc_card(
159 struct snd_soc_dapm_context *dapm)
160{
161 if (dapm->codec)
162 return dapm->codec->card;
163 else if (dapm->platform)
164 return dapm->platform->card;
165 else
166 BUG();
167
168 /* unreachable */
169 return NULL;
170}
171
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100172static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
173{
174 if (w->codec)
175 return snd_soc_read(w->codec, reg);
Liam Girdwoodb7950642011-07-04 22:10:52 +0100176 else if (w->platform)
177 return snd_soc_platform_read(w->platform, reg);
178
179 dev_err(w->dapm->dev, "no valid widget read method\n");
180 return -1;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100181}
182
183static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
184{
185 if (w->codec)
186 return snd_soc_write(w->codec, reg, val);
Liam Girdwoodb7950642011-07-04 22:10:52 +0100187 else if (w->platform)
188 return snd_soc_platform_write(w->platform, reg, val);
189
190 dev_err(w->dapm->dev, "no valid widget write method\n");
191 return -1;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100192}
193
194static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
195 unsigned short reg, unsigned int mask, unsigned int value)
196{
Mark Brown8a713da2011-12-03 12:33:55 +0000197 bool change;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100198 unsigned int old, new;
199 int ret;
200
Mark Brown8a713da2011-12-03 12:33:55 +0000201 if (w->codec && w->codec->using_regmap) {
202 ret = regmap_update_bits_check(w->codec->control_data,
203 reg, mask, value, &change);
204 if (ret != 0)
205 return ret;
206 } else {
207 ret = soc_widget_read(w, reg);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100208 if (ret < 0)
209 return ret;
Mark Brown8a713da2011-12-03 12:33:55 +0000210
211 old = ret;
212 new = (old & ~mask) | (value & mask);
213 change = old != new;
214 if (change) {
215 ret = soc_widget_write(w, reg, new);
216 if (ret < 0)
217 return ret;
218 }
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100219 }
220
221 return change;
222}
223
Mark Brown452c5ea2009-05-17 21:41:23 +0100224/**
225 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800226 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100227 * @level: level to configure
228 *
229 * Configure the bias (power) levels for the SoC audio device.
230 *
231 * Returns 0 for success else error.
232 */
Mark Browned5a4c42011-02-18 11:12:42 -0800233static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200234 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100235{
Mark Browned5a4c42011-02-18 11:12:42 -0800236 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100237 int ret = 0;
238
Mark Brown84e90932010-11-04 00:07:02 -0400239 trace_snd_soc_bias_level_start(card, level);
240
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000241 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100242 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100243 if (ret != 0)
244 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100245
Mark Browncc4c6702011-06-06 19:03:34 +0100246 if (dapm->codec) {
247 if (dapm->codec->driver->set_bias_level)
248 ret = dapm->codec->driver->set_bias_level(dapm->codec,
249 level);
250 else
251 dapm->bias_level = level;
252 }
Mark Brown171ec6b2011-06-06 18:15:19 +0100253 if (ret != 0)
254 goto out;
255
256 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100257 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100258out:
Mark Brown84e90932010-11-04 00:07:02 -0400259 trace_snd_soc_bias_level_done(card, level);
260
Mark Brown452c5ea2009-05-17 21:41:23 +0100261 return ret;
262}
263
Richard Purdie2b97eab2006-10-06 18:32:18 +0200264/* set up initial codec paths */
265static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
266 struct snd_soc_dapm_path *p, int i)
267{
268 switch (w->id) {
269 case snd_soc_dapm_switch:
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000270 case snd_soc_dapm_mixer:
271 case snd_soc_dapm_mixer_named_ctl: {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200272 int val;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100273 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Stephen Warren82cfecd2011-04-28 17:37:58 -0600274 w->kcontrol_news[i].private_value;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400275 unsigned int reg = mc->reg;
276 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100277 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400278 unsigned int mask = (1 << fls(max)) - 1;
279 unsigned int invert = mc->invert;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200280
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100281 val = soc_widget_read(w, reg);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200282 val = (val >> shift) & mask;
283
284 if ((invert && !val) || (!invert && val))
285 p->connect = 1;
286 else
287 p->connect = 0;
288 }
289 break;
290 case snd_soc_dapm_mux: {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600291 struct soc_enum *e = (struct soc_enum *)
292 w->kcontrol_news[i].private_value;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200293 int val, item, bitmask;
294
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100295 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Mark Brown88d96082011-06-06 16:16:34 +0100296 ;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100297 val = soc_widget_read(w, e->reg);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200298 item = (val >> e->shift_l) & (bitmask - 1);
299
300 p->connect = 0;
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100301 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200302 if (!(strcmp(p->name, e->texts[i])) && item == i)
303 p->connect = 1;
304 }
305 }
306 break;
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +0000307 case snd_soc_dapm_virt_mux: {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600308 struct soc_enum *e = (struct soc_enum *)
309 w->kcontrol_news[i].private_value;
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +0000310
311 p->connect = 0;
312 /* since a virtual mux has no backing registers to
313 * decide which path to connect, it will try to match
314 * with the first enumeration. This is to ensure
315 * that the default mux choice (the first) will be
316 * correctly powered up during initialization.
317 */
318 if (!strcmp(p->name, e->texts[0]))
319 p->connect = 1;
320 }
321 break;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200322 case snd_soc_dapm_value_mux: {
Peter Ujfalusi74155552009-01-08 13:34:29 +0200323 struct soc_enum *e = (struct soc_enum *)
Stephen Warren82cfecd2011-04-28 17:37:58 -0600324 w->kcontrol_news[i].private_value;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200325 int val, item;
326
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100327 val = soc_widget_read(w, e->reg);
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200328 val = (val >> e->shift_l) & e->mask;
329 for (item = 0; item < e->max; item++) {
330 if (val == e->values[item])
331 break;
332 }
333
334 p->connect = 0;
335 for (i = 0; i < e->max; i++) {
336 if (!(strcmp(p->name, e->texts[i])) && item == i)
337 p->connect = 1;
338 }
339 }
340 break;
Mark Brown56563102011-10-03 22:41:09 +0100341 /* does not affect routing - always connected */
Richard Purdie2b97eab2006-10-06 18:32:18 +0200342 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -0600343 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200344 case snd_soc_dapm_output:
345 case snd_soc_dapm_adc:
346 case snd_soc_dapm_input:
Mark Brown1ab97c82011-11-27 16:21:51 +0000347 case snd_soc_dapm_siggen:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200348 case snd_soc_dapm_dac:
349 case snd_soc_dapm_micbias:
350 case snd_soc_dapm_vmid:
Mark Brown246d0a12009-04-22 18:24:55 +0100351 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +0000352 case snd_soc_dapm_regulator_supply:
Mark Brown010ff262009-08-17 17:39:22 +0100353 case snd_soc_dapm_aif_in:
354 case snd_soc_dapm_aif_out:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200355 case snd_soc_dapm_hp:
356 case snd_soc_dapm_mic:
357 case snd_soc_dapm_spk:
358 case snd_soc_dapm_line:
Mark Brown56563102011-10-03 22:41:09 +0100359 p->connect = 1;
360 break;
361 /* does affect routing - dynamically connected */
Richard Purdie2b97eab2006-10-06 18:32:18 +0200362 case snd_soc_dapm_pre:
363 case snd_soc_dapm_post:
364 p->connect = 0;
365 break;
366 }
367}
368
Mark Brown74b8f952009-06-06 11:26:15 +0100369/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200370static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200371 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
372 struct snd_soc_dapm_path *path, const char *control_name,
373 const struct snd_kcontrol_new *kcontrol)
374{
375 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
376 int i;
377
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100378 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200379 if (!(strcmp(control_name, e->texts[i]))) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200380 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200381 list_add(&path->list_sink, &dest->sources);
382 list_add(&path->list_source, &src->sinks);
383 path->name = (char*)e->texts[i];
384 dapm_set_path_status(dest, path, 0);
385 return 0;
386 }
387 }
388
389 return -ENODEV;
390}
391
Mark Brown74b8f952009-06-06 11:26:15 +0100392/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200393static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200394 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
395 struct snd_soc_dapm_path *path, const char *control_name)
396{
397 int i;
398
399 /* search for mixer kcontrol */
400 for (i = 0; i < dest->num_kcontrols; i++) {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600401 if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200402 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200403 list_add(&path->list_sink, &dest->sources);
404 list_add(&path->list_source, &src->sinks);
Stephen Warren82cfecd2011-04-28 17:37:58 -0600405 path->name = dest->kcontrol_news[i].name;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200406 dapm_set_path_status(dest, path, i);
407 return 0;
408 }
409 }
410 return -ENODEV;
411}
412
Stephen Warrenaf468002011-04-28 17:38:01 -0600413static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600414 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600415 const struct snd_kcontrol_new *kcontrol_new,
416 struct snd_kcontrol **kcontrol)
417{
418 struct snd_soc_dapm_widget *w;
419 int i;
420
421 *kcontrol = NULL;
422
423 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600424 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
425 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600426 for (i = 0; i < w->num_kcontrols; i++) {
427 if (&w->kcontrol_news[i] == kcontrol_new) {
428 if (w->kcontrols)
429 *kcontrol = w->kcontrols[i];
430 return 1;
431 }
432 }
433 }
434
435 return 0;
436}
437
Richard Purdie2b97eab2006-10-06 18:32:18 +0200438/* create new dapm mixer control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200439static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200440{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200441 struct snd_soc_dapm_context *dapm = w->dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200442 int i, ret = 0;
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000443 size_t name_len, prefix_len;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200444 struct snd_soc_dapm_path *path;
Mark Brown12ea2c72011-03-02 18:17:32 +0000445 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000446 const char *prefix;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600447 struct snd_soc_dapm_widget_list *wlist;
448 size_t wlistsize;
Mark Brownefb7ac32011-03-08 17:23:24 +0000449
450 if (dapm->codec)
451 prefix = dapm->codec->name_prefix;
452 else
453 prefix = NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200454
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000455 if (prefix)
456 prefix_len = strlen(prefix) + 1;
457 else
458 prefix_len = 0;
459
Richard Purdie2b97eab2006-10-06 18:32:18 +0200460 /* add kcontrol */
461 for (i = 0; i < w->num_kcontrols; i++) {
462
463 /* match name */
464 list_for_each_entry(path, &w->sources, list_sink) {
465
466 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600467 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200468 continue;
469
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200470 if (w->kcontrols[i]) {
471 path->kcontrol = w->kcontrols[i];
472 continue;
473 }
474
Stephen Warrenfafd2172011-04-28 17:38:00 -0600475 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
476 sizeof(struct snd_soc_dapm_widget *),
477 wlist = kzalloc(wlistsize, GFP_KERNEL);
478 if (wlist == NULL) {
479 dev_err(dapm->dev,
480 "asoc: can't allocate widget list for %s\n",
481 w->name);
482 return -ENOMEM;
483 }
484 wlist->num_widgets = 1;
485 wlist->widgets[0] = w;
486
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000487 /* add dapm control with long name.
488 * for dapm_mixer this is the concatenation of the
489 * mixer and kcontrol name.
490 * for dapm_mixer_named_ctl this is simply the
491 * kcontrol name.
492 */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600493 name_len = strlen(w->kcontrol_news[i].name) + 1;
Mark Brown07495f32009-03-05 17:06:23 +0000494 if (w->id != snd_soc_dapm_mixer_named_ctl)
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000495 name_len += 1 + strlen(w->name);
496
Mark Brown219b93f2008-10-28 13:02:31 +0000497 path->long_name = kmalloc(name_len, GFP_KERNEL);
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000498
Stephen Warrenfafd2172011-04-28 17:38:00 -0600499 if (path->long_name == NULL) {
500 kfree(wlist);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200501 return -ENOMEM;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600502 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200503
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000504 switch (w->id) {
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000505 default:
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000506 /* The control will get a prefix from
507 * the control creation process but
508 * we're also using the same prefix
509 * for widgets so cut the prefix off
510 * the front of the widget name.
511 */
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000512 snprintf(path->long_name, name_len, "%s %s",
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000513 w->name + prefix_len,
Stephen Warren82cfecd2011-04-28 17:37:58 -0600514 w->kcontrol_news[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000515 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000516 case snd_soc_dapm_mixer_named_ctl:
517 snprintf(path->long_name, name_len, "%s",
Stephen Warren82cfecd2011-04-28 17:37:58 -0600518 w->kcontrol_news[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000519 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000520 }
521
Mark Brown219b93f2008-10-28 13:02:31 +0000522 path->long_name[name_len - 1] = '\0';
523
Stephen Warrenfafd2172011-04-28 17:38:00 -0600524 path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
525 wlist, path->long_name,
526 prefix);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200527 ret = snd_ctl_add(card, path->kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200528 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200529 dev_err(dapm->dev,
530 "asoc: failed to add dapm kcontrol %s: %d\n",
531 path->long_name, ret);
Stephen Warrenfafd2172011-04-28 17:38:00 -0600532 kfree(wlist);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200533 kfree(path->long_name);
534 path->long_name = NULL;
535 return ret;
536 }
Stephen Warrenfad59882011-04-28 17:37:59 -0600537 w->kcontrols[i] = path->kcontrol;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200538 }
539 }
540 return ret;
541}
542
543/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200544static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200545{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200546 struct snd_soc_dapm_context *dapm = w->dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200547 struct snd_soc_dapm_path *path = NULL;
548 struct snd_kcontrol *kcontrol;
Mark Brown12ea2c72011-03-02 18:17:32 +0000549 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000550 const char *prefix;
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000551 size_t prefix_len;
Stephen Warrenaf468002011-04-28 17:38:01 -0600552 int ret;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600553 struct snd_soc_dapm_widget_list *wlist;
Stephen Warrenaf468002011-04-28 17:38:01 -0600554 int shared, wlistentries;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600555 size_t wlistsize;
Stephen Warrenaf468002011-04-28 17:38:01 -0600556 char *name;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200557
Stephen Warrenaf468002011-04-28 17:38:01 -0600558 if (w->num_kcontrols != 1) {
559 dev_err(dapm->dev,
560 "asoc: mux %s has incorrect number of controls\n",
561 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200562 return -EINVAL;
563 }
564
Stephen Warren1007da02011-05-26 09:57:33 -0600565 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
Stephen Warrenaf468002011-04-28 17:38:01 -0600566 &kcontrol);
567 if (kcontrol) {
568 wlist = kcontrol->private_data;
569 wlistentries = wlist->num_widgets + 1;
570 } else {
571 wlist = NULL;
572 wlistentries = 1;
573 }
Stephen Warrenfafd2172011-04-28 17:38:00 -0600574 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
Stephen Warrenaf468002011-04-28 17:38:01 -0600575 wlistentries * sizeof(struct snd_soc_dapm_widget *),
576 wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
Stephen Warrenfafd2172011-04-28 17:38:00 -0600577 if (wlist == NULL) {
578 dev_err(dapm->dev,
579 "asoc: can't allocate widget list for %s\n", w->name);
580 return -ENOMEM;
581 }
Stephen Warrenaf468002011-04-28 17:38:01 -0600582 wlist->num_widgets = wlistentries;
583 wlist->widgets[wlistentries - 1] = w;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600584
Stephen Warrenaf468002011-04-28 17:38:01 -0600585 if (!kcontrol) {
586 if (dapm->codec)
587 prefix = dapm->codec->name_prefix;
588 else
589 prefix = NULL;
Mark Brownefb7ac32011-03-08 17:23:24 +0000590
Stephen Warrenaf468002011-04-28 17:38:01 -0600591 if (shared) {
592 name = w->kcontrol_news[0].name;
593 prefix_len = 0;
594 } else {
595 name = w->name;
596 if (prefix)
597 prefix_len = strlen(prefix) + 1;
598 else
599 prefix_len = 0;
600 }
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000601
Stephen Warrenaf468002011-04-28 17:38:01 -0600602 /*
603 * The control will get a prefix from the control creation
604 * process but we're also using the same prefix for widgets so
605 * cut the prefix off the front of the widget name.
606 */
607 kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
608 name + prefix_len, prefix);
609 ret = snd_ctl_add(card, kcontrol);
610 if (ret < 0) {
Mark Brown53daf202011-09-05 10:51:05 -0700611 dev_err(dapm->dev, "failed to add kcontrol %s: %d\n",
612 w->name, ret);
Stephen Warrenaf468002011-04-28 17:38:01 -0600613 kfree(wlist);
614 return ret;
615 }
616 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200617
Stephen Warrenaf468002011-04-28 17:38:01 -0600618 kcontrol->private_data = wlist;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200619
Stephen Warrenfad59882011-04-28 17:37:59 -0600620 w->kcontrols[0] = kcontrol;
621
Richard Purdie2b97eab2006-10-06 18:32:18 +0200622 list_for_each_entry(path, &w->sources, list_sink)
623 path->kcontrol = kcontrol;
624
Stephen Warrenaf468002011-04-28 17:38:01 -0600625 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200626}
627
628/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200629static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200630{
Mark Browna6c65732010-03-03 17:45:21 +0000631 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200632 dev_err(w->dapm->dev,
633 "asoc: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200634
Mark Browna6c65732010-03-03 17:45:21 +0000635 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200636}
637
638/* reset 'walked' bit for each dapm path */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200639static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200640{
641 struct snd_soc_dapm_path *p;
642
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200643 list_for_each_entry(p, &dapm->card->paths, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200644 p->walked = 0;
645}
646
Mark Brown99497882010-05-07 20:24:05 +0100647/* We implement power down on suspend by checking the power state of
648 * the ALSA card - when we are suspending the ALSA state for the card
649 * is set to D3.
650 */
651static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
652{
Mark Brown12ea2c72011-03-02 18:17:32 +0000653 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +0100654
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000655 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +0100656 case SNDRV_CTL_POWER_D3hot:
657 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +0100658 if (widget->ignore_suspend)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200659 dev_dbg(widget->dapm->dev, "%s ignoring suspend\n",
660 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +0100661 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +0100662 default:
663 return 1;
664 }
665}
666
Richard Purdie2b97eab2006-10-06 18:32:18 +0200667/*
668 * Recursively check for a completed path to an active or physically connected
669 * output widget. Returns number of complete paths.
670 */
671static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
672{
673 struct snd_soc_dapm_path *path;
674 int con = 0;
675
Mark Brown024dc072011-10-09 11:52:05 +0100676 if (widget->outputs >= 0)
677 return widget->outputs;
678
Mark Brownde02d072011-09-20 21:43:24 +0100679 DAPM_UPDATE_STAT(widget, path_checks);
680
Mark Brown62ea8742012-01-21 21:14:48 +0000681 switch (widget->id) {
682 case snd_soc_dapm_supply:
683 case snd_soc_dapm_regulator_supply:
Mark Brown246d0a12009-04-22 18:24:55 +0100684 return 0;
Mark Brown62ea8742012-01-21 21:14:48 +0000685 default:
686 break;
687 }
Mark Brown246d0a12009-04-22 18:24:55 +0100688
Mark Brown010ff262009-08-17 17:39:22 +0100689 switch (widget->id) {
690 case snd_soc_dapm_adc:
691 case snd_soc_dapm_aif_out:
Mark Brown024dc072011-10-09 11:52:05 +0100692 if (widget->active) {
693 widget->outputs = snd_soc_dapm_suspend_check(widget);
694 return widget->outputs;
695 }
Mark Brown010ff262009-08-17 17:39:22 +0100696 default:
697 break;
698 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200699
700 if (widget->connected) {
701 /* connected pin ? */
Mark Brown024dc072011-10-09 11:52:05 +0100702 if (widget->id == snd_soc_dapm_output && !widget->ext) {
703 widget->outputs = snd_soc_dapm_suspend_check(widget);
704 return widget->outputs;
705 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200706
707 /* connected jack or spk ? */
Mark Brown024dc072011-10-09 11:52:05 +0100708 if (widget->id == snd_soc_dapm_hp ||
709 widget->id == snd_soc_dapm_spk ||
710 (widget->id == snd_soc_dapm_line &&
711 !list_empty(&widget->sources))) {
712 widget->outputs = snd_soc_dapm_suspend_check(widget);
713 return widget->outputs;
714 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200715 }
716
717 list_for_each_entry(path, &widget->sinks, list_source) {
Mark Browne56235e2011-09-21 18:19:14 +0100718 DAPM_UPDATE_STAT(widget, neighbour_checks);
719
Mark Brownbf3a9e12011-06-13 16:42:29 +0100720 if (path->weak)
721 continue;
722
Richard Purdie2b97eab2006-10-06 18:32:18 +0200723 if (path->walked)
724 continue;
725
726 if (path->sink && path->connect) {
727 path->walked = 1;
728 con += is_connected_output_ep(path->sink);
729 }
730 }
731
Mark Brown024dc072011-10-09 11:52:05 +0100732 widget->outputs = con;
733
Richard Purdie2b97eab2006-10-06 18:32:18 +0200734 return con;
735}
736
737/*
738 * Recursively check for a completed path to an active or physically connected
739 * input widget. Returns number of complete paths.
740 */
741static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
742{
743 struct snd_soc_dapm_path *path;
744 int con = 0;
745
Mark Brown024dc072011-10-09 11:52:05 +0100746 if (widget->inputs >= 0)
747 return widget->inputs;
748
Mark Brownde02d072011-09-20 21:43:24 +0100749 DAPM_UPDATE_STAT(widget, path_checks);
750
Mark Brown62ea8742012-01-21 21:14:48 +0000751 switch (widget->id) {
752 case snd_soc_dapm_supply:
753 case snd_soc_dapm_regulator_supply:
Mark Brown246d0a12009-04-22 18:24:55 +0100754 return 0;
Mark Brown62ea8742012-01-21 21:14:48 +0000755 default:
756 break;
757 }
Mark Brown246d0a12009-04-22 18:24:55 +0100758
Richard Purdie2b97eab2006-10-06 18:32:18 +0200759 /* active stream ? */
Mark Brown010ff262009-08-17 17:39:22 +0100760 switch (widget->id) {
761 case snd_soc_dapm_dac:
762 case snd_soc_dapm_aif_in:
Mark Brown024dc072011-10-09 11:52:05 +0100763 if (widget->active) {
764 widget->inputs = snd_soc_dapm_suspend_check(widget);
765 return widget->inputs;
766 }
Mark Brown010ff262009-08-17 17:39:22 +0100767 default:
768 break;
769 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200770
771 if (widget->connected) {
772 /* connected pin ? */
Mark Brown024dc072011-10-09 11:52:05 +0100773 if (widget->id == snd_soc_dapm_input && !widget->ext) {
774 widget->inputs = snd_soc_dapm_suspend_check(widget);
775 return widget->inputs;
776 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200777
778 /* connected VMID/Bias for lower pops */
Mark Brown024dc072011-10-09 11:52:05 +0100779 if (widget->id == snd_soc_dapm_vmid) {
780 widget->inputs = snd_soc_dapm_suspend_check(widget);
781 return widget->inputs;
782 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200783
784 /* connected jack ? */
Peter Ujfalusieaeae5d2009-09-30 09:27:24 +0300785 if (widget->id == snd_soc_dapm_mic ||
Mark Brown024dc072011-10-09 11:52:05 +0100786 (widget->id == snd_soc_dapm_line &&
787 !list_empty(&widget->sinks))) {
788 widget->inputs = snd_soc_dapm_suspend_check(widget);
789 return widget->inputs;
790 }
791
Mark Brown1ab97c82011-11-27 16:21:51 +0000792 /* signal generator */
793 if (widget->id == snd_soc_dapm_siggen) {
794 widget->inputs = snd_soc_dapm_suspend_check(widget);
795 return widget->inputs;
796 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200797 }
798
799 list_for_each_entry(path, &widget->sources, list_sink) {
Mark Browne56235e2011-09-21 18:19:14 +0100800 DAPM_UPDATE_STAT(widget, neighbour_checks);
801
Mark Brownbf3a9e12011-06-13 16:42:29 +0100802 if (path->weak)
803 continue;
804
Richard Purdie2b97eab2006-10-06 18:32:18 +0200805 if (path->walked)
806 continue;
807
808 if (path->source && path->connect) {
809 path->walked = 1;
810 con += is_connected_input_ep(path->source);
811 }
812 }
813
Mark Brown024dc072011-10-09 11:52:05 +0100814 widget->inputs = con;
815
Richard Purdie2b97eab2006-10-06 18:32:18 +0200816 return con;
817}
818
819/*
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300820 * Handler for generic register modifier widget.
821 */
822int dapm_reg_event(struct snd_soc_dapm_widget *w,
823 struct snd_kcontrol *kcontrol, int event)
824{
825 unsigned int val;
826
827 if (SND_SOC_DAPM_EVENT_ON(event))
828 val = w->on_val;
829 else
830 val = w->off_val;
831
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100832 soc_widget_update_bits(w, -(w->reg + 1),
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300833 w->mask << w->shift, val << w->shift);
834
835 return 0;
836}
Mark Brown11589412008-07-29 11:42:23 +0100837EXPORT_SYMBOL_GPL(dapm_reg_event);
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300838
Mark Brown62ea8742012-01-21 21:14:48 +0000839/*
840 * Handler for regulator supply widget.
841 */
842int dapm_regulator_event(struct snd_soc_dapm_widget *w,
843 struct snd_kcontrol *kcontrol, int event)
844{
845 if (SND_SOC_DAPM_EVENT_ON(event))
846 return regulator_enable(w->priv);
847 else
848 return regulator_disable_deferred(w->priv, w->shift);
849}
850EXPORT_SYMBOL_GPL(dapm_regulator_event);
851
Mark Brownd8050022011-09-28 18:28:23 +0100852static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
853{
Mark Brown9b8a83b2011-10-04 22:15:59 +0100854 if (w->power_checked)
855 return w->new_power;
856
Mark Brownd8050022011-09-28 18:28:23 +0100857 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +0100858 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +0100859 else
Mark Brown9b8a83b2011-10-04 22:15:59 +0100860 w->new_power = w->power_check(w);
861
862 w->power_checked = true;
863
864 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +0100865}
866
Mark Browncd0f2d42009-04-20 16:56:59 +0100867/* Generic check to see if a widget should be powered.
868 */
869static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
870{
871 int in, out;
872
Mark Brownde02d072011-09-20 21:43:24 +0100873 DAPM_UPDATE_STAT(w, power_checks);
874
Mark Browncd0f2d42009-04-20 16:56:59 +0100875 in = is_connected_input_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200876 dapm_clear_walk(w->dapm);
Mark Browncd0f2d42009-04-20 16:56:59 +0100877 out = is_connected_output_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200878 dapm_clear_walk(w->dapm);
Mark Browncd0f2d42009-04-20 16:56:59 +0100879 return out != 0 && in != 0;
880}
881
Mark Brown6ea31b92009-04-20 17:15:41 +0100882/* Check to see if an ADC has power */
883static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
884{
885 int in;
886
Mark Brownde02d072011-09-20 21:43:24 +0100887 DAPM_UPDATE_STAT(w, power_checks);
888
Mark Brown6ea31b92009-04-20 17:15:41 +0100889 if (w->active) {
890 in = is_connected_input_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200891 dapm_clear_walk(w->dapm);
Mark Brown6ea31b92009-04-20 17:15:41 +0100892 return in != 0;
893 } else {
894 return dapm_generic_check_power(w);
895 }
896}
897
898/* Check to see if a DAC has power */
899static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
900{
901 int out;
902
Mark Brownde02d072011-09-20 21:43:24 +0100903 DAPM_UPDATE_STAT(w, power_checks);
904
Mark Brown6ea31b92009-04-20 17:15:41 +0100905 if (w->active) {
906 out = is_connected_output_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200907 dapm_clear_walk(w->dapm);
Mark Brown6ea31b92009-04-20 17:15:41 +0100908 return out != 0;
909 } else {
910 return dapm_generic_check_power(w);
911 }
912}
913
Mark Brown246d0a12009-04-22 18:24:55 +0100914/* Check to see if a power supply is needed */
915static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
916{
917 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +0100918
Mark Brownde02d072011-09-20 21:43:24 +0100919 DAPM_UPDATE_STAT(w, power_checks);
920
Mark Brown246d0a12009-04-22 18:24:55 +0100921 /* Check if one of our outputs is connected */
922 list_for_each_entry(path, &w->sinks, list_source) {
Mark Browna8fdac82011-09-28 18:20:26 +0100923 DAPM_UPDATE_STAT(w, neighbour_checks);
924
Mark Brownbf3a9e12011-06-13 16:42:29 +0100925 if (path->weak)
926 continue;
927
Mark Brown215edda2009-09-08 18:59:05 +0100928 if (path->connected &&
929 !path->connected(path->source, path->sink))
930 continue;
931
Mark Brown30173582011-02-11 11:42:19 +0000932 if (!path->sink)
933 continue;
934
Mark Brownf68d7e12011-10-04 22:57:50 +0100935 if (dapm_widget_power_check(path->sink))
936 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +0100937 }
938
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200939 dapm_clear_walk(w->dapm);
Mark Brown246d0a12009-04-22 18:24:55 +0100940
Mark Brownf68d7e12011-10-04 22:57:50 +0100941 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +0100942}
943
Mark Brown35c64bc2011-09-28 18:23:53 +0100944static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
945{
946 return 1;
947}
948
Mark Brown38357ab2009-06-06 19:03:23 +0100949static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
950 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +0000951 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +0000952{
Mark Brown828a8422011-01-15 13:14:30 +0000953 int *sort;
954
955 if (power_up)
956 sort = dapm_up_seq;
957 else
958 sort = dapm_down_seq;
959
Mark Brown38357ab2009-06-06 19:03:23 +0100960 if (sort[a->id] != sort[b->id])
961 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +0000962 if (a->subseq != b->subseq) {
963 if (power_up)
964 return a->subseq - b->subseq;
965 else
966 return b->subseq - a->subseq;
967 }
Mark Brownb22ead22009-06-07 12:51:26 +0100968 if (a->reg != b->reg)
969 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +0000970 if (a->dapm != b->dapm)
971 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +0000972
Mark Brown38357ab2009-06-06 19:03:23 +0100973 return 0;
974}
Mark Brown42aa3412009-03-01 19:21:10 +0000975
Mark Brown38357ab2009-06-06 19:03:23 +0100976/* Insert a widget in order into a DAPM power sequence. */
977static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
978 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +0000979 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +0100980{
981 struct snd_soc_dapm_widget *w;
982
983 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +0000984 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +0100985 list_add_tail(&new_widget->power_list, &w->power_list);
986 return;
Mark Brown42aa3412009-03-01 19:21:10 +0000987 }
Mark Brown6ea31b92009-04-20 17:15:41 +0100988
Mark Brown38357ab2009-06-06 19:03:23 +0100989 list_add_tail(&new_widget->power_list, list);
990}
Mark Brown42aa3412009-03-01 19:21:10 +0000991
Mark Brown68f89ad2010-11-03 23:51:49 -0400992static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
993 struct snd_soc_dapm_widget *w, int event)
994{
995 struct snd_soc_card *card = dapm->card;
996 const char *ev_name;
997 int power, ret;
998
999 switch (event) {
1000 case SND_SOC_DAPM_PRE_PMU:
1001 ev_name = "PRE_PMU";
1002 power = 1;
1003 break;
1004 case SND_SOC_DAPM_POST_PMU:
1005 ev_name = "POST_PMU";
1006 power = 1;
1007 break;
1008 case SND_SOC_DAPM_PRE_PMD:
1009 ev_name = "PRE_PMD";
1010 power = 0;
1011 break;
1012 case SND_SOC_DAPM_POST_PMD:
1013 ev_name = "POST_PMD";
1014 power = 0;
1015 break;
1016 default:
1017 BUG();
1018 return;
1019 }
1020
1021 if (w->power != power)
1022 return;
1023
1024 if (w->event && (w->event_flags & event)) {
1025 pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
1026 w->name, ev_name);
Mark Brown84e90932010-11-04 00:07:02 -04001027 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001028 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001029 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001030 if (ret < 0)
1031 pr_err("%s: %s event failed: %d\n",
1032 ev_name, w->name, ret);
1033 }
1034}
1035
Mark Brownb22ead22009-06-07 12:51:26 +01001036/* Apply the coalesced changes from a DAPM sequence */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001037static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
Mark Brownb22ead22009-06-07 12:51:26 +01001038 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001039{
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001040 struct snd_soc_card *card = dapm->card;
Mark Brown68f89ad2010-11-03 23:51:49 -04001041 struct snd_soc_dapm_widget *w;
1042 int reg, power;
Mark Brownb22ead22009-06-07 12:51:26 +01001043 unsigned int value = 0;
1044 unsigned int mask = 0;
1045 unsigned int cur_mask;
1046
1047 reg = list_first_entry(pending, struct snd_soc_dapm_widget,
1048 power_list)->reg;
1049
1050 list_for_each_entry(w, pending, power_list) {
1051 cur_mask = 1 << w->shift;
1052 BUG_ON(reg != w->reg);
1053
1054 if (w->invert)
1055 power = !w->power;
1056 else
1057 power = w->power;
1058
1059 mask |= cur_mask;
1060 if (power)
1061 value |= cur_mask;
1062
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001063 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001064 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1065 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001066
Mark Brown68f89ad2010-11-03 23:51:49 -04001067 /* Check for events */
1068 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
1069 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001070 }
1071
Mark Brown81628102009-06-07 13:21:24 +01001072 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001073 /* Any widget will do, they should all be updating the
1074 * same register.
1075 */
1076 w = list_first_entry(pending, struct snd_soc_dapm_widget,
1077 power_list);
1078
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001079 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001080 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001081 value, mask, reg, card->pop_time);
1082 pop_wait(card->pop_time);
Liam Girdwood0445bdf2011-06-13 19:37:36 +01001083 soc_widget_update_bits(w, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001084 }
1085
1086 list_for_each_entry(w, pending, power_list) {
Mark Brown68f89ad2010-11-03 23:51:49 -04001087 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
1088 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001089 }
Mark Brown42aa3412009-03-01 19:21:10 +00001090}
1091
Mark Brownb22ead22009-06-07 12:51:26 +01001092/* Apply a DAPM power sequence.
1093 *
1094 * We walk over a pre-sorted list of widgets to apply power to. In
1095 * order to minimise the number of writes to the device required
1096 * multiple widgets will be updated in a single write where possible.
1097 * Currently anything that requires more than a single write is not
1098 * handled.
1099 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001100static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
Mark Brown828a8422011-01-15 13:14:30 +00001101 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001102{
1103 struct snd_soc_dapm_widget *w, *n;
1104 LIST_HEAD(pending);
1105 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001106 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001107 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001108 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001109 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001110 int *sort;
1111
1112 if (power_up)
1113 sort = dapm_up_seq;
1114 else
1115 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001116
Mark Brownb22ead22009-06-07 12:51:26 +01001117 list_for_each_entry_safe(w, n, list, power_list) {
1118 ret = 0;
1119
1120 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001121 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001122 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001123 if (!list_empty(&pending))
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001124 dapm_seq_run_coalesced(cur_dapm, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001125
Mark Brown474b62d2011-01-18 16:14:44 +00001126 if (cur_dapm && cur_dapm->seq_notifier) {
1127 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1128 if (sort[i] == cur_sort)
1129 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001130 i,
1131 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001132 }
1133
Mark Brownb22ead22009-06-07 12:51:26 +01001134 INIT_LIST_HEAD(&pending);
1135 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001136 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001137 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001138 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001139 }
1140
Mark Brown163cac02009-06-07 10:12:52 +01001141 switch (w->id) {
1142 case snd_soc_dapm_pre:
1143 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001144 list_for_each_entry_safe_continue(w, n, list,
1145 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001146
Mark Brownb22ead22009-06-07 12:51:26 +01001147 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001148 ret = w->event(w,
1149 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001150 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001151 ret = w->event(w,
1152 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001153 break;
1154
1155 case snd_soc_dapm_post:
1156 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001157 list_for_each_entry_safe_continue(w, n, list,
1158 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001159
Mark Brownb22ead22009-06-07 12:51:26 +01001160 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001161 ret = w->event(w,
1162 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001163 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001164 ret = w->event(w,
1165 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001166 break;
1167
Mark Brown163cac02009-06-07 10:12:52 +01001168 default:
Mark Brown81628102009-06-07 13:21:24 +01001169 /* Queue it up for application */
1170 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001171 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001172 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001173 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001174 list_move(&w->power_list, &pending);
1175 break;
Mark Brown163cac02009-06-07 10:12:52 +01001176 }
Mark Brownb22ead22009-06-07 12:51:26 +01001177
1178 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001179 dev_err(w->dapm->dev,
1180 "Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001181 }
Mark Brownb22ead22009-06-07 12:51:26 +01001182
1183 if (!list_empty(&pending))
Mark Brown28e86802011-03-08 19:29:53 +00001184 dapm_seq_run_coalesced(cur_dapm, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001185
1186 if (cur_dapm && cur_dapm->seq_notifier) {
1187 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1188 if (sort[i] == cur_sort)
1189 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001190 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001191 }
Mark Brown163cac02009-06-07 10:12:52 +01001192}
1193
Mark Brown97404f22010-12-14 16:13:57 +00001194static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
1195{
1196 struct snd_soc_dapm_update *update = dapm->update;
1197 struct snd_soc_dapm_widget *w;
1198 int ret;
1199
1200 if (!update)
1201 return;
1202
1203 w = update->widget;
1204
1205 if (w->event &&
1206 (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1207 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1208 if (ret != 0)
1209 pr_err("%s DAPM pre-event failed: %d\n",
1210 w->name, ret);
1211 }
1212
1213 ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
1214 update->val);
1215 if (ret < 0)
1216 pr_err("%s DAPM update failed: %d\n", w->name, ret);
1217
1218 if (w->event &&
1219 (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1220 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1221 if (ret != 0)
1222 pr_err("%s DAPM post-event failed: %d\n",
1223 w->name, ret);
1224 }
1225}
1226
Mark Brown9d0624a2011-02-18 11:49:43 -08001227/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1228 * they're changing state.
1229 */
1230static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1231{
1232 struct snd_soc_dapm_context *d = data;
1233 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001234
Mark Brown56fba412011-06-04 11:25:10 +01001235 /* If we're off and we're not supposed to be go into STANDBY */
1236 if (d->bias_level == SND_SOC_BIAS_OFF &&
1237 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001238 if (d->dev)
1239 pm_runtime_get_sync(d->dev);
1240
Mark Brown9d0624a2011-02-18 11:49:43 -08001241 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1242 if (ret != 0)
1243 dev_err(d->dev,
1244 "Failed to turn on bias: %d\n", ret);
1245 }
1246
Mark Brown56fba412011-06-04 11:25:10 +01001247 /* Prepare for a STADDBY->ON or ON->STANDBY transition */
1248 if (d->bias_level != d->target_bias_level) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001249 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1250 if (ret != 0)
1251 dev_err(d->dev,
1252 "Failed to prepare bias: %d\n", ret);
1253 }
1254}
1255
1256/* Async callback run prior to DAPM sequences - brings to their final
1257 * state.
1258 */
1259static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1260{
1261 struct snd_soc_dapm_context *d = data;
1262 int ret;
1263
1264 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001265 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1266 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1267 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001268 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1269 if (ret != 0)
1270 dev_err(d->dev, "Failed to apply standby bias: %d\n",
1271 ret);
1272 }
1273
1274 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001275 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1276 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001277 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1278 if (ret != 0)
1279 dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001280
1281 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001282 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001283 }
1284
1285 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001286 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1287 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001288 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1289 if (ret != 0)
1290 dev_err(d->dev, "Failed to apply active bias: %d\n",
1291 ret);
1292 }
1293}
Mark Brown97404f22010-12-14 16:13:57 +00001294
Mark Brownfe4fda52011-10-03 22:36:57 +01001295static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1296 bool power, bool connect)
1297{
1298 /* If a connection is being made or broken then that update
1299 * will have marked the peer dirty, otherwise the widgets are
1300 * not connected and this update has no impact. */
1301 if (!connect)
1302 return;
1303
1304 /* If the peer is already in the state we're moving to then we
1305 * won't have an impact on it. */
1306 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001307 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001308}
1309
Mark Brown05623c42011-09-28 17:02:31 +01001310static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1311 struct list_head *up_list,
1312 struct list_head *down_list)
1313{
Mark Browndb432b42011-10-03 21:06:40 +01001314 struct snd_soc_dapm_path *path;
1315
Mark Brown05623c42011-09-28 17:02:31 +01001316 if (w->power == power)
1317 return;
1318
1319 trace_snd_soc_dapm_widget_power(w, power);
1320
Mark Browndb432b42011-10-03 21:06:40 +01001321 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001322 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001323 */
1324 list_for_each_entry(path, &w->sources, list_sink) {
1325 if (path->source) {
Mark Brownfe4fda52011-10-03 22:36:57 +01001326 dapm_widget_set_peer_power(path->source, power,
1327 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001328 }
1329 }
Mark Brownf3bf3e42011-10-04 22:43:31 +01001330 switch (w->id) {
1331 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001332 case snd_soc_dapm_regulator_supply:
Mark Brownf3bf3e42011-10-04 22:43:31 +01001333 /* Supplies can't affect their outputs, only their inputs */
1334 break;
1335 default:
1336 list_for_each_entry(path, &w->sinks, list_source) {
1337 if (path->sink) {
1338 dapm_widget_set_peer_power(path->sink, power,
1339 path->connect);
1340 }
Mark Browndb432b42011-10-03 21:06:40 +01001341 }
Mark Brownf3bf3e42011-10-04 22:43:31 +01001342 break;
Mark Browndb432b42011-10-03 21:06:40 +01001343 }
1344
Mark Brown05623c42011-09-28 17:02:31 +01001345 if (power)
1346 dapm_seq_insert(w, up_list, true);
1347 else
1348 dapm_seq_insert(w, down_list, false);
1349
1350 w->power = power;
1351}
1352
Mark Brown7c81beb2011-09-20 22:22:32 +01001353static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1354 struct list_head *up_list,
1355 struct list_head *down_list)
1356{
Mark Brown7c81beb2011-09-20 22:22:32 +01001357 int power;
1358
1359 switch (w->id) {
1360 case snd_soc_dapm_pre:
1361 dapm_seq_insert(w, down_list, false);
1362 break;
1363 case snd_soc_dapm_post:
1364 dapm_seq_insert(w, up_list, true);
1365 break;
1366
1367 default:
Mark Brownd8050022011-09-28 18:28:23 +01001368 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001369
Mark Brown05623c42011-09-28 17:02:31 +01001370 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001371 break;
1372 }
1373}
1374
Mark Brown42aa3412009-03-01 19:21:10 +00001375/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001376 * Scan each dapm widget for complete audio path.
1377 * A complete path is a route that has valid endpoints i.e.:-
1378 *
1379 * o DAC to output pin.
1380 * o Input Pin to ADC.
1381 * o Input pin to Output pin (bypass, sidetone)
1382 * o DAC to ADC (loopback).
1383 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001384static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001385{
Mark Brown12ea2c72011-03-02 18:17:32 +00001386 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001387 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001388 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001389 LIST_HEAD(up_list);
1390 LIST_HEAD(down_list);
Mark Brown9d0624a2011-02-18 11:49:43 -08001391 LIST_HEAD(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001392 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001393
Mark Brown84e90932010-11-04 00:07:02 -04001394 trace_snd_soc_dapm_start(card);
1395
Mark Brown56fba412011-06-04 11:25:10 +01001396 list_for_each_entry(d, &card->dapm_list, list) {
1397 if (d->n_widgets || d->codec == NULL) {
1398 if (d->idle_bias_off)
1399 d->target_bias_level = SND_SOC_BIAS_OFF;
1400 else
1401 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1402 }
1403 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001404
Mark Brownde02d072011-09-20 21:43:24 +01001405 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
1406
Mark Brown9b8a83b2011-10-04 22:15:59 +01001407 list_for_each_entry(w, &card->widgets, list) {
1408 w->power_checked = false;
Mark Brown024dc072011-10-09 11:52:05 +01001409 w->inputs = -1;
1410 w->outputs = -1;
Mark Brown9b8a83b2011-10-04 22:15:59 +01001411 }
1412
Mark Brown6d3ddc82009-05-16 17:47:29 +01001413 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001414 * lists indicating if they should be powered up or down. We
1415 * only check widgets that have been flagged as dirty but note
1416 * that new widgets may be added to the dirty list while we
1417 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001418 */
Mark Browndb432b42011-10-03 21:06:40 +01001419 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001420 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001421 }
1422
Mark Brownf9de6d72011-09-28 17:19:47 +01001423 list_for_each_entry(w, &card->widgets, list) {
Mark Browndb432b42011-10-03 21:06:40 +01001424 list_del_init(&w->dirty);
1425
Mark Brownf9de6d72011-09-28 17:19:47 +01001426 if (w->power) {
1427 d = w->dapm;
1428
1429 /* Supplies and micbiases only bring the
1430 * context up to STANDBY as unless something
1431 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001432 * generally don't require full power. Signal
1433 * generators are virtual pins and have no
1434 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001435 */
1436 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001437 case snd_soc_dapm_siggen:
1438 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001439 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001440 case snd_soc_dapm_regulator_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001441 case snd_soc_dapm_micbias:
1442 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1443 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1444 break;
1445 default:
1446 d->target_bias_level = SND_SOC_BIAS_ON;
1447 break;
1448 }
1449 }
1450
1451 }
1452
Mark Brownb14b76a2009-08-17 11:55:38 +01001453 /* If there are no DAPM widgets then try to figure out power from the
1454 * event type.
1455 */
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001456 if (!dapm->n_widgets) {
Mark Brownb14b76a2009-08-17 11:55:38 +01001457 switch (event) {
1458 case SND_SOC_DAPM_STREAM_START:
1459 case SND_SOC_DAPM_STREAM_RESUME:
Mark Brown56fba412011-06-04 11:25:10 +01001460 dapm->target_bias_level = SND_SOC_BIAS_ON;
Mark Brownb14b76a2009-08-17 11:55:38 +01001461 break;
Jarkko Nikula862af8a2010-12-10 20:53:55 +02001462 case SND_SOC_DAPM_STREAM_STOP:
Liam Girdwoode7c80e22012-01-16 15:23:31 +00001463 if (dapm->codec && dapm->codec->active)
Mark Brown56fba412011-06-04 11:25:10 +01001464 dapm->target_bias_level = SND_SOC_BIAS_ON;
1465 else
1466 dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
Jarkko Nikula862af8a2010-12-10 20:53:55 +02001467 break;
Mark Brown50b6bce2009-11-23 13:11:53 +00001468 case SND_SOC_DAPM_STREAM_SUSPEND:
Mark Brown56fba412011-06-04 11:25:10 +01001469 dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown50b6bce2009-11-23 13:11:53 +00001470 break;
Mark Brownb14b76a2009-08-17 11:55:38 +01001471 case SND_SOC_DAPM_STREAM_NOP:
Mark Brown56fba412011-06-04 11:25:10 +01001472 dapm->target_bias_level = dapm->bias_level;
Mark Brown50b6bce2009-11-23 13:11:53 +00001473 break;
Mark Brownb14b76a2009-08-17 11:55:38 +01001474 default:
1475 break;
1476 }
1477 }
1478
Mark Brown85a843c2011-09-21 21:29:47 +01001479 /* Force all contexts in the card to the same bias state if
1480 * they're not ground referenced.
1481 */
Mark Brown56fba412011-06-04 11:25:10 +01001482 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001483 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001484 if (d->target_bias_level > bias)
1485 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001486 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown85a843c2011-09-21 21:29:47 +01001487 if (!d->idle_bias_off)
1488 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001489
Mark Brownde02d072011-09-20 21:43:24 +01001490 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001491
Mark Brown9d0624a2011-02-18 11:49:43 -08001492 /* Run all the bias changes in parallel */
1493 list_for_each_entry(d, &dapm->card->dapm_list, list)
1494 async_schedule_domain(dapm_pre_sequence_async, d,
1495 &async_domain);
1496 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001497
Mark Brown6d3ddc82009-05-16 17:47:29 +01001498 /* Power down widgets first; try to avoid amplifying pops. */
Mark Brown828a8422011-01-15 13:14:30 +00001499 dapm_seq_run(dapm, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001500
Mark Brown97404f22010-12-14 16:13:57 +00001501 dapm_widget_update(dapm);
1502
Mark Brown6d3ddc82009-05-16 17:47:29 +01001503 /* Now power up. */
Mark Brown828a8422011-01-15 13:14:30 +00001504 dapm_seq_run(dapm, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001505
Mark Brown9d0624a2011-02-18 11:49:43 -08001506 /* Run all the bias changes in parallel */
1507 list_for_each_entry(d, &dapm->card->dapm_list, list)
1508 async_schedule_domain(dapm_post_sequence_async, d,
1509 &async_domain);
1510 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001511
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001512 pop_dbg(dapm->dev, card->pop_time,
1513 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001514 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001515
Mark Brown84e90932010-11-04 00:07:02 -04001516 trace_snd_soc_dapm_done(card);
1517
Mark Brown42aa3412009-03-01 19:21:10 +00001518 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001519}
1520
Mark Brown79fb9382009-08-21 16:38:13 +01001521#ifdef CONFIG_DEBUG_FS
1522static int dapm_widget_power_open_file(struct inode *inode, struct file *file)
1523{
1524 file->private_data = inode->i_private;
1525 return 0;
1526}
1527
1528static ssize_t dapm_widget_power_read_file(struct file *file,
1529 char __user *user_buf,
1530 size_t count, loff_t *ppos)
1531{
1532 struct snd_soc_dapm_widget *w = file->private_data;
1533 char *buf;
1534 int in, out;
1535 ssize_t ret;
1536 struct snd_soc_dapm_path *p = NULL;
1537
1538 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1539 if (!buf)
1540 return -ENOMEM;
1541
1542 in = is_connected_input_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001543 dapm_clear_walk(w->dapm);
Mark Brown79fb9382009-08-21 16:38:13 +01001544 out = is_connected_output_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001545 dapm_clear_walk(w->dapm);
Mark Brown79fb9382009-08-21 16:38:13 +01001546
Mark Brownd033c362009-12-04 15:25:56 +00001547 ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d",
Mark Brown79fb9382009-08-21 16:38:13 +01001548 w->name, w->power ? "On" : "Off", in, out);
1549
Mark Brownd033c362009-12-04 15:25:56 +00001550 if (w->reg >= 0)
1551 ret += snprintf(buf + ret, PAGE_SIZE - ret,
1552 " - R%d(0x%x) bit %d",
1553 w->reg, w->reg, w->shift);
1554
1555 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1556
Mark Brown3eef08b2009-09-14 16:49:00 +01001557 if (w->sname)
1558 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1559 w->sname,
1560 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001561
1562 list_for_each_entry(p, &w->sources, list_sink) {
Mark Brown215edda2009-09-08 18:59:05 +01001563 if (p->connected && !p->connected(w, p->sink))
1564 continue;
1565
Mark Brown79fb9382009-08-21 16:38:13 +01001566 if (p->connect)
1567 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001568 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001569 p->name ? p->name : "static",
1570 p->source->name);
1571 }
1572 list_for_each_entry(p, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001573 if (p->connected && !p->connected(w, p->sink))
1574 continue;
1575
Mark Brown79fb9382009-08-21 16:38:13 +01001576 if (p->connect)
1577 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001578 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001579 p->name ? p->name : "static",
1580 p->sink->name);
1581 }
1582
1583 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1584
1585 kfree(buf);
1586 return ret;
1587}
1588
1589static const struct file_operations dapm_widget_power_fops = {
1590 .open = dapm_widget_power_open_file,
1591 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001592 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001593};
1594
Mark Brownef49e4f2011-04-04 20:48:13 +09001595static int dapm_bias_open_file(struct inode *inode, struct file *file)
1596{
1597 file->private_data = inode->i_private;
1598 return 0;
1599}
1600
1601static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1602 size_t count, loff_t *ppos)
1603{
1604 struct snd_soc_dapm_context *dapm = file->private_data;
1605 char *level;
1606
1607 switch (dapm->bias_level) {
1608 case SND_SOC_BIAS_ON:
1609 level = "On\n";
1610 break;
1611 case SND_SOC_BIAS_PREPARE:
1612 level = "Prepare\n";
1613 break;
1614 case SND_SOC_BIAS_STANDBY:
1615 level = "Standby\n";
1616 break;
1617 case SND_SOC_BIAS_OFF:
1618 level = "Off\n";
1619 break;
1620 default:
1621 BUG();
1622 level = "Unknown\n";
1623 break;
1624 }
1625
1626 return simple_read_from_buffer(user_buf, count, ppos, level,
1627 strlen(level));
1628}
1629
1630static const struct file_operations dapm_bias_fops = {
1631 .open = dapm_bias_open_file,
1632 .read = dapm_bias_read_file,
1633 .llseek = default_llseek,
1634};
1635
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001636void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1637 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001638{
Mark Brown79fb9382009-08-21 16:38:13 +01001639 struct dentry *d;
1640
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001641 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
1642
1643 if (!dapm->debugfs_dapm) {
1644 printk(KERN_WARNING
1645 "Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001646 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001647 }
Mark Brown79fb9382009-08-21 16:38:13 +01001648
Mark Brownef49e4f2011-04-04 20:48:13 +09001649 d = debugfs_create_file("bias_level", 0444,
1650 dapm->debugfs_dapm, dapm,
1651 &dapm_bias_fops);
1652 if (!d)
1653 dev_warn(dapm->dev,
1654 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001655}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001656
1657static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1658{
1659 struct snd_soc_dapm_context *dapm = w->dapm;
1660 struct dentry *d;
1661
1662 if (!dapm->debugfs_dapm || !w->name)
1663 return;
1664
1665 d = debugfs_create_file(w->name, 0444,
1666 dapm->debugfs_dapm, w,
1667 &dapm_widget_power_fops);
1668 if (!d)
1669 dev_warn(w->dapm->dev,
1670 "ASoC: Failed to create %s debugfs file\n",
1671 w->name);
1672}
1673
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001674static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1675{
1676 debugfs_remove_recursive(dapm->debugfs_dapm);
1677}
1678
Mark Brown79fb9382009-08-21 16:38:13 +01001679#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001680void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1681 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001682{
1683}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001684
1685static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1686{
1687}
1688
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001689static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1690{
1691}
1692
Mark Brown79fb9382009-08-21 16:38:13 +01001693#endif
1694
Richard Purdie2b97eab2006-10-06 18:32:18 +02001695/* test and update the power status of a mux widget */
Liam Girdwood40f02cd2012-02-06 16:05:14 +00001696int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1697 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001698{
1699 struct snd_soc_dapm_path *path;
1700 int found = 0;
1701
Peter Ujfalusieff317d2009-01-15 14:40:47 +02001702 if (widget->id != snd_soc_dapm_mux &&
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00001703 widget->id != snd_soc_dapm_virt_mux &&
Peter Ujfalusieff317d2009-01-15 14:40:47 +02001704 widget->id != snd_soc_dapm_value_mux)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001705 return -ENODEV;
1706
Richard Purdie2b97eab2006-10-06 18:32:18 +02001707 /* find dapm widget path assoc with kcontrol */
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001708 list_for_each_entry(path, &widget->dapm->card->paths, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001709 if (path->kcontrol != kcontrol)
1710 continue;
1711
Richard Zhaocb01e2b2008-10-07 08:05:20 +08001712 if (!path->name || !e->texts[mux])
Richard Purdie2b97eab2006-10-06 18:32:18 +02001713 continue;
1714
1715 found = 1;
1716 /* we now need to match the string in the enum to the path */
Mark Browndb432b42011-10-03 21:06:40 +01001717 if (!(strcmp(path->name, e->texts[mux]))) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001718 path->connect = 1; /* new connection */
Mark Brown75c1f892011-10-04 22:28:08 +01001719 dapm_mark_dirty(path->source, "mux connection");
Mark Browndb432b42011-10-03 21:06:40 +01001720 } else {
1721 if (path->connect)
Mark Brown75c1f892011-10-04 22:28:08 +01001722 dapm_mark_dirty(path->source,
1723 "mux disconnection");
Richard Purdie2b97eab2006-10-06 18:32:18 +02001724 path->connect = 0; /* old connection must be powered down */
Mark Browndb432b42011-10-03 21:06:40 +01001725 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001726 }
1727
Mark Browndb432b42011-10-03 21:06:40 +01001728 if (found) {
Mark Brown75c1f892011-10-04 22:28:08 +01001729 dapm_mark_dirty(widget, "mux change");
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001730 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
Mark Browndb432b42011-10-03 21:06:40 +01001731 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001732
1733 return 0;
1734}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00001735EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001736
Milan plzik1b075e32008-01-10 14:39:46 +01001737/* test and update the power status of a mixer or switch widget */
Liam Girdwood40f02cd2012-02-06 16:05:14 +00001738int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
Mark Brown283375c2009-12-07 18:09:03 +00001739 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001740{
1741 struct snd_soc_dapm_path *path;
1742 int found = 0;
1743
Milan plzik1b075e32008-01-10 14:39:46 +01001744 if (widget->id != snd_soc_dapm_mixer &&
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001745 widget->id != snd_soc_dapm_mixer_named_ctl &&
Milan plzik1b075e32008-01-10 14:39:46 +01001746 widget->id != snd_soc_dapm_switch)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001747 return -ENODEV;
1748
Richard Purdie2b97eab2006-10-06 18:32:18 +02001749 /* find dapm widget path assoc with kcontrol */
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001750 list_for_each_entry(path, &widget->dapm->card->paths, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001751 if (path->kcontrol != kcontrol)
1752 continue;
1753
1754 /* found, now check type */
1755 found = 1;
Mark Brown283375c2009-12-07 18:09:03 +00001756 path->connect = connect;
Mark Brown75c1f892011-10-04 22:28:08 +01001757 dapm_mark_dirty(path->source, "mixer connection");
Richard Purdie2b97eab2006-10-06 18:32:18 +02001758 }
1759
Mark Browndb432b42011-10-03 21:06:40 +01001760 if (found) {
Mark Brown75c1f892011-10-04 22:28:08 +01001761 dapm_mark_dirty(widget, "mixer update");
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001762 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
Mark Browndb432b42011-10-03 21:06:40 +01001763 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001764
1765 return 0;
1766}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00001767EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001768
1769/* show dapm widget status in sys fs */
1770static ssize_t dapm_widget_show(struct device *dev,
1771 struct device_attribute *attr, char *buf)
1772{
Mark Brown36ae1a92012-01-06 17:12:45 -08001773 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001774 struct snd_soc_codec *codec =rtd->codec;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001775 struct snd_soc_dapm_widget *w;
1776 int count = 0;
1777 char *state = "not set";
1778
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001779 list_for_each_entry(w, &codec->card->widgets, list) {
1780 if (w->dapm != &codec->dapm)
1781 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001782
1783 /* only display widgets that burnm power */
1784 switch (w->id) {
1785 case snd_soc_dapm_hp:
1786 case snd_soc_dapm_mic:
1787 case snd_soc_dapm_spk:
1788 case snd_soc_dapm_line:
1789 case snd_soc_dapm_micbias:
1790 case snd_soc_dapm_dac:
1791 case snd_soc_dapm_adc:
1792 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06001793 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001794 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001795 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01001796 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001797 case snd_soc_dapm_regulator_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001798 if (w->name)
1799 count += sprintf(buf + count, "%s: %s\n",
1800 w->name, w->power ? "On":"Off");
1801 break;
1802 default:
1803 break;
1804 }
1805 }
1806
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001807 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02001808 case SND_SOC_BIAS_ON:
1809 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001810 break;
Mark Brown0be98982008-05-19 12:31:28 +02001811 case SND_SOC_BIAS_PREPARE:
1812 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001813 break;
Mark Brown0be98982008-05-19 12:31:28 +02001814 case SND_SOC_BIAS_STANDBY:
1815 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001816 break;
Mark Brown0be98982008-05-19 12:31:28 +02001817 case SND_SOC_BIAS_OFF:
1818 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001819 break;
1820 }
1821 count += sprintf(buf + count, "PM State: %s\n", state);
1822
1823 return count;
1824}
1825
1826static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
1827
1828int snd_soc_dapm_sys_add(struct device *dev)
1829{
Troy Kisky12ef1932008-10-13 17:42:14 -07001830 return device_create_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001831}
1832
1833static void snd_soc_dapm_sys_remove(struct device *dev)
1834{
Mark Brownaef90842009-05-16 17:53:16 +01001835 device_remove_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001836}
1837
1838/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001839static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001840{
1841 struct snd_soc_dapm_widget *w, *next_w;
1842 struct snd_soc_dapm_path *p, *next_p;
1843
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001844 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
1845 if (w->dapm != dapm)
1846 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001847 list_del(&w->list);
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001848 /*
1849 * remove source and sink paths associated to this widget.
1850 * While removing the path, remove reference to it from both
1851 * source and sink widgets so that path is removed only once.
1852 */
1853 list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
1854 list_del(&p->list_sink);
1855 list_del(&p->list_source);
1856 list_del(&p->list);
1857 kfree(p->long_name);
1858 kfree(p);
1859 }
1860 list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
1861 list_del(&p->list_sink);
1862 list_del(&p->list_source);
1863 list_del(&p->list);
1864 kfree(p->long_name);
1865 kfree(p);
1866 }
Stephen Warrenfad59882011-04-28 17:37:59 -06001867 kfree(w->kcontrols);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001868 kfree(w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001869 kfree(w);
1870 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001871}
1872
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001873static struct snd_soc_dapm_widget *dapm_find_widget(
1874 struct snd_soc_dapm_context *dapm, const char *pin,
1875 bool search_other_contexts)
1876{
1877 struct snd_soc_dapm_widget *w;
1878 struct snd_soc_dapm_widget *fallback = NULL;
1879
1880 list_for_each_entry(w, &dapm->card->widgets, list) {
1881 if (!strcmp(w->name, pin)) {
1882 if (w->dapm == dapm)
1883 return w;
1884 else
1885 fallback = w;
1886 }
1887 }
1888
1889 if (search_other_contexts)
1890 return fallback;
1891
1892 return NULL;
1893}
1894
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001895static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00001896 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01001897{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001898 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01001899
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001900 if (!w) {
1901 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
1902 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01001903 }
1904
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001905 w->connected = status;
1906 if (status == 0)
1907 w->force = 0;
Mark Brown75c1f892011-10-04 22:28:08 +01001908 dapm_mark_dirty(w, "pin configuration");
Mark Brown0d867332011-04-06 11:38:14 +09001909
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001910 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01001911}
1912
Richard Purdie2b97eab2006-10-06 18:32:18 +02001913/**
Liam Girdwooda5302182008-07-07 13:35:17 +01001914 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001915 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02001916 *
1917 * Walks all dapm audio paths and powers widgets according to their
1918 * stream or path usage.
1919 *
1920 * Returns 0 for success.
1921 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001922int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001923{
Mark Brown4f4c0072011-10-07 14:29:19 +01001924 /*
1925 * Suppress early reports (eg, jacks syncing their state) to avoid
1926 * silly DAPM runs during card startup.
1927 */
1928 if (!dapm->card || !dapm->card->instantiated)
1929 return 0;
1930
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001931 return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001932}
Liam Girdwooda5302182008-07-07 13:35:17 +01001933EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001934
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001935static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Mark Brown215edda2009-09-08 18:59:05 +01001936 const struct snd_soc_dapm_route *route)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001937{
1938 struct snd_soc_dapm_path *path;
1939 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001940 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001941 const char *sink;
Mark Brown215edda2009-09-08 18:59:05 +01001942 const char *control = route->control;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001943 const char *source;
1944 char prefixed_sink[80];
1945 char prefixed_source[80];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001946 int ret = 0;
1947
Mark Brown88e8b9a2011-03-02 18:18:24 +00001948 if (dapm->codec && dapm->codec->name_prefix) {
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001949 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
1950 dapm->codec->name_prefix, route->sink);
1951 sink = prefixed_sink;
1952 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
1953 dapm->codec->name_prefix, route->source);
1954 source = prefixed_source;
1955 } else {
1956 sink = route->sink;
1957 source = route->source;
1958 }
1959
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001960 /*
1961 * find src and dest widgets over all widgets but favor a widget from
1962 * current DAPM context
1963 */
1964 list_for_each_entry(w, &dapm->card->widgets, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001965 if (!wsink && !(strcmp(w->name, sink))) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001966 wtsink = w;
1967 if (w->dapm == dapm)
1968 wsink = w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001969 continue;
1970 }
1971 if (!wsource && !(strcmp(w->name, source))) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001972 wtsource = w;
1973 if (w->dapm == dapm)
1974 wsource = w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001975 }
1976 }
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001977 /* use widget from another DAPM context if not found from this */
1978 if (!wsink)
1979 wsink = wtsink;
1980 if (!wsource)
1981 wsource = wtsource;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001982
1983 if (wsource == NULL || wsink == NULL)
1984 return -ENODEV;
1985
1986 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
1987 if (!path)
1988 return -ENOMEM;
1989
1990 path->source = wsource;
1991 path->sink = wsink;
Mark Brown215edda2009-09-08 18:59:05 +01001992 path->connected = route->connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001993 INIT_LIST_HEAD(&path->list);
1994 INIT_LIST_HEAD(&path->list_source);
1995 INIT_LIST_HEAD(&path->list_sink);
1996
1997 /* check for external widgets */
1998 if (wsink->id == snd_soc_dapm_input) {
1999 if (wsource->id == snd_soc_dapm_micbias ||
2000 wsource->id == snd_soc_dapm_mic ||
Rongrong Cao087d53a2009-07-10 20:13:30 +01002001 wsource->id == snd_soc_dapm_line ||
2002 wsource->id == snd_soc_dapm_output)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002003 wsink->ext = 1;
2004 }
2005 if (wsource->id == snd_soc_dapm_output) {
2006 if (wsink->id == snd_soc_dapm_spk ||
2007 wsink->id == snd_soc_dapm_hp ||
Seth Forshee1e392212007-04-16 15:36:42 +02002008 wsink->id == snd_soc_dapm_line ||
2009 wsink->id == snd_soc_dapm_input)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002010 wsource->ext = 1;
2011 }
2012
2013 /* connect static paths */
2014 if (control == NULL) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002015 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002016 list_add(&path->list_sink, &wsink->sources);
2017 list_add(&path->list_source, &wsource->sinks);
2018 path->connect = 1;
2019 return 0;
2020 }
2021
2022 /* connect dynamic paths */
Lu Guanqundc2bea62011-04-20 16:00:36 +08002023 switch (wsink->id) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002024 case snd_soc_dapm_adc:
2025 case snd_soc_dapm_dac:
2026 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002027 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002028 case snd_soc_dapm_input:
2029 case snd_soc_dapm_output:
Mark Brown1ab97c82011-11-27 16:21:51 +00002030 case snd_soc_dapm_siggen:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002031 case snd_soc_dapm_micbias:
2032 case snd_soc_dapm_vmid:
2033 case snd_soc_dapm_pre:
2034 case snd_soc_dapm_post:
Mark Brown246d0a12009-04-22 18:24:55 +01002035 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002036 case snd_soc_dapm_regulator_supply:
Mark Brown010ff262009-08-17 17:39:22 +01002037 case snd_soc_dapm_aif_in:
2038 case snd_soc_dapm_aif_out:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002039 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002040 list_add(&path->list_sink, &wsink->sources);
2041 list_add(&path->list_source, &wsource->sinks);
2042 path->connect = 1;
2043 return 0;
2044 case snd_soc_dapm_mux:
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00002045 case snd_soc_dapm_virt_mux:
Peter Ujfalusi74155552009-01-08 13:34:29 +02002046 case snd_soc_dapm_value_mux:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002047 ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
Stephen Warren82cfecd2011-04-28 17:37:58 -06002048 &wsink->kcontrol_news[0]);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002049 if (ret != 0)
2050 goto err;
2051 break;
2052 case snd_soc_dapm_switch:
2053 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002054 case snd_soc_dapm_mixer_named_ctl:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002055 ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002056 if (ret != 0)
2057 goto err;
2058 break;
2059 case snd_soc_dapm_hp:
2060 case snd_soc_dapm_mic:
2061 case snd_soc_dapm_line:
2062 case snd_soc_dapm_spk:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002063 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002064 list_add(&path->list_sink, &wsink->sources);
2065 list_add(&path->list_source, &wsource->sinks);
2066 path->connect = 0;
2067 return 0;
2068 }
2069 return 0;
2070
2071err:
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002072 dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n",
2073 source, control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002074 kfree(path);
2075 return ret;
2076}
Mark Brown105f1c22008-05-13 14:52:19 +02002077
2078/**
Mark Brown105f1c22008-05-13 14:52:19 +02002079 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002080 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002081 * @route: audio routes
2082 * @num: number of routes
2083 *
2084 * Connects 2 dapm widgets together via a named audio path. The sink is
2085 * the widget receiving the audio signal, whilst the source is the sender
2086 * of the audio signal.
2087 *
2088 * Returns 0 for success else error. On error all resources can be freed
2089 * with a call to snd_soc_card_free().
2090 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002091int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002092 const struct snd_soc_dapm_route *route, int num)
2093{
2094 int i, ret;
2095
2096 for (i = 0; i < num; i++) {
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002097 ret = snd_soc_dapm_add_route(dapm, route);
Mark Brown105f1c22008-05-13 14:52:19 +02002098 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002099 dev_err(dapm->dev, "Failed to add route %s->%s\n",
2100 route->source, route->sink);
Mark Brown105f1c22008-05-13 14:52:19 +02002101 return ret;
2102 }
2103 route++;
2104 }
2105
2106 return 0;
2107}
2108EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2109
Mark Brownbf3a9e12011-06-13 16:42:29 +01002110static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2111 const struct snd_soc_dapm_route *route)
2112{
2113 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2114 route->source,
2115 true);
2116 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2117 route->sink,
2118 true);
2119 struct snd_soc_dapm_path *path;
2120 int count = 0;
2121
2122 if (!source) {
2123 dev_err(dapm->dev, "Unable to find source %s for weak route\n",
2124 route->source);
2125 return -ENODEV;
2126 }
2127
2128 if (!sink) {
2129 dev_err(dapm->dev, "Unable to find sink %s for weak route\n",
2130 route->sink);
2131 return -ENODEV;
2132 }
2133
2134 if (route->control || route->connected)
2135 dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n",
2136 route->source, route->sink);
2137
2138 list_for_each_entry(path, &source->sinks, list_source) {
2139 if (path->sink == sink) {
2140 path->weak = 1;
2141 count++;
2142 }
2143 }
2144
2145 if (count == 0)
2146 dev_err(dapm->dev, "No path found for weak route %s->%s\n",
2147 route->source, route->sink);
2148 if (count > 1)
2149 dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n",
2150 count, route->source, route->sink);
2151
2152 return 0;
2153}
2154
2155/**
2156 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2157 * @dapm: DAPM context
2158 * @route: audio routes
2159 * @num: number of routes
2160 *
2161 * Mark existing routes matching those specified in the passed array
2162 * as being weak, meaning that they are ignored for the purpose of
2163 * power decisions. The main intended use case is for sidetone paths
2164 * which couple audio between other independent paths if they are both
2165 * active in order to make the combination work better at the user
2166 * level but which aren't intended to be "used".
2167 *
2168 * Note that CODEC drivers should not use this as sidetone type paths
2169 * can frequently also be used as bypass paths.
2170 */
2171int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2172 const struct snd_soc_dapm_route *route, int num)
2173{
2174 int i, err;
2175 int ret = 0;
2176
2177 for (i = 0; i < num; i++) {
2178 err = snd_soc_dapm_weak_route(dapm, route);
2179 if (err)
2180 ret = err;
2181 route++;
2182 }
2183
2184 return ret;
2185}
2186EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2187
Mark Brown105f1c22008-05-13 14:52:19 +02002188/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002189 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002190 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002191 *
2192 * Checks the codec for any new dapm widgets and creates them if found.
2193 *
2194 * Returns 0 for success.
2195 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002196int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002197{
2198 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002199 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002200
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002201 list_for_each_entry(w, &dapm->card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002202 {
2203 if (w->new)
2204 continue;
2205
Stephen Warrenfad59882011-04-28 17:37:59 -06002206 if (w->num_kcontrols) {
2207 w->kcontrols = kzalloc(w->num_kcontrols *
2208 sizeof(struct snd_kcontrol *),
2209 GFP_KERNEL);
2210 if (!w->kcontrols)
2211 return -ENOMEM;
2212 }
2213
Richard Purdie2b97eab2006-10-06 18:32:18 +02002214 switch(w->id) {
2215 case snd_soc_dapm_switch:
2216 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002217 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002218 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002219 break;
2220 case snd_soc_dapm_mux:
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00002221 case snd_soc_dapm_virt_mux:
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002222 case snd_soc_dapm_value_mux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002223 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002224 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002225 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002226 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002227 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002228 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002229 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002230 break;
2231 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002232
2233 /* Read the initial power state from the device */
2234 if (w->reg >= 0) {
Liam Girdwood0445bdf2011-06-13 19:37:36 +01002235 val = soc_widget_read(w, w->reg);
Mark Brownb66a70d2011-02-09 18:04:11 +00002236 val &= 1 << w->shift;
2237 if (w->invert)
2238 val = !val;
2239
2240 if (val)
2241 w->power = 1;
2242 }
2243
Richard Purdie2b97eab2006-10-06 18:32:18 +02002244 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002245
Mark Brown7508b122011-10-05 12:09:12 +01002246 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002247 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002248 }
2249
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002250 dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002251 return 0;
2252}
2253EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2254
2255/**
2256 * snd_soc_dapm_get_volsw - dapm mixer get callback
2257 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002258 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002259 *
2260 * Callback to get the value of a dapm mixer control.
2261 *
2262 * Returns 0 for success.
2263 */
2264int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2265 struct snd_ctl_elem_value *ucontrol)
2266{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002267 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2268 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Jon Smirl4eaa9812008-07-29 11:42:26 +01002269 struct soc_mixer_control *mc =
2270 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002271 unsigned int reg = mc->reg;
2272 unsigned int shift = mc->shift;
2273 unsigned int rshift = mc->rshift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002274 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002275 unsigned int invert = mc->invert;
2276 unsigned int mask = (1 << fls(max)) - 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002277
Richard Purdie2b97eab2006-10-06 18:32:18 +02002278 ucontrol->value.integer.value[0] =
2279 (snd_soc_read(widget->codec, reg) >> shift) & mask;
2280 if (shift != rshift)
2281 ucontrol->value.integer.value[1] =
2282 (snd_soc_read(widget->codec, reg) >> rshift) & mask;
2283 if (invert) {
2284 ucontrol->value.integer.value[0] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002285 max - ucontrol->value.integer.value[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002286 if (shift != rshift)
2287 ucontrol->value.integer.value[1] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002288 max - ucontrol->value.integer.value[1];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002289 }
2290
2291 return 0;
2292}
2293EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
2294
2295/**
2296 * snd_soc_dapm_put_volsw - dapm mixer set callback
2297 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002298 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002299 *
2300 * Callback to set the value of a dapm mixer control.
2301 *
2302 * Returns 0 for success.
2303 */
2304int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2305 struct snd_ctl_elem_value *ucontrol)
2306{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002307 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2308 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2309 struct snd_soc_codec *codec = widget->codec;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002310 struct soc_mixer_control *mc =
2311 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002312 unsigned int reg = mc->reg;
2313 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002314 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04002315 unsigned int mask = (1 << fls(max)) - 1;
2316 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002317 unsigned int val;
Mark Brown97404f22010-12-14 16:13:57 +00002318 int connect, change;
2319 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002320 int wi;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002321
2322 val = (ucontrol->value.integer.value[0] & mask);
2323
2324 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002325 val = max - val;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002326 mask = mask << shift;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002327 val = val << shift;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002328
Stephen Warrenfafd2172011-04-28 17:38:00 -06002329 if (val)
2330 /* new connection */
2331 connect = invert ? 0 : 1;
2332 else
2333 /* old connection must be powered down */
2334 connect = invert ? 1 : 0;
2335
2336 mutex_lock(&codec->mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002337
Stephen Warrene9cf7042011-01-27 14:54:05 -07002338 change = snd_soc_test_bits(widget->codec, reg, mask, val);
Mark Brown97404f22010-12-14 16:13:57 +00002339 if (change) {
Stephen Warrenfafd2172011-04-28 17:38:00 -06002340 for (wi = 0; wi < wlist->num_widgets; wi++) {
2341 widget = wlist->widgets[wi];
Mark Brown283375c2009-12-07 18:09:03 +00002342
Stephen Warrenfafd2172011-04-28 17:38:00 -06002343 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002344
Stephen Warrenfafd2172011-04-28 17:38:00 -06002345 update.kcontrol = kcontrol;
2346 update.widget = widget;
2347 update.reg = reg;
2348 update.mask = mask;
2349 update.val = val;
2350 widget->dapm->update = &update;
Mark Brown97404f22010-12-14 16:13:57 +00002351
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002352 snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002353
2354 widget->dapm->update = NULL;
2355 }
Mark Brown283375c2009-12-07 18:09:03 +00002356 }
2357
Stephen Warrenfafd2172011-04-28 17:38:00 -06002358 mutex_unlock(&codec->mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002359 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002360}
2361EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
2362
2363/**
2364 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
2365 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002366 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002367 *
2368 * Callback to get the value of a dapm enumerated double mixer control.
2369 *
2370 * Returns 0 for success.
2371 */
2372int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
2373 struct snd_ctl_elem_value *ucontrol)
2374{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002375 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2376 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002377 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002378 unsigned int val, bitmask;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002379
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002380 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002381 ;
2382 val = snd_soc_read(widget->codec, e->reg);
2383 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
2384 if (e->shift_l != e->shift_r)
2385 ucontrol->value.enumerated.item[1] =
2386 (val >> e->shift_r) & (bitmask - 1);
2387
2388 return 0;
2389}
2390EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
2391
2392/**
2393 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
2394 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002395 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002396 *
2397 * Callback to set the value of a dapm enumerated double mixer control.
2398 *
2399 * Returns 0 for success.
2400 */
2401int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
2402 struct snd_ctl_elem_value *ucontrol)
2403{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002404 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2405 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2406 struct snd_soc_codec *codec = widget->codec;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002407 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Mark Brown3a655772009-10-05 17:23:30 +01002408 unsigned int val, mux, change;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002409 unsigned int mask, bitmask;
Mark Brown97404f22010-12-14 16:13:57 +00002410 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002411 int wi;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002412
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002413 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002414 ;
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002415 if (ucontrol->value.enumerated.item[0] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002416 return -EINVAL;
2417 mux = ucontrol->value.enumerated.item[0];
2418 val = mux << e->shift_l;
2419 mask = (bitmask - 1) << e->shift_l;
2420 if (e->shift_l != e->shift_r) {
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002421 if (ucontrol->value.enumerated.item[1] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002422 return -EINVAL;
2423 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
2424 mask |= (bitmask - 1) << e->shift_r;
2425 }
2426
Stephen Warrenfafd2172011-04-28 17:38:00 -06002427 mutex_lock(&codec->mutex);
2428
Mark Brown3a655772009-10-05 17:23:30 +01002429 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002430 if (change) {
2431 for (wi = 0; wi < wlist->num_widgets; wi++) {
2432 widget = wlist->widgets[wi];
Mark Brown97404f22010-12-14 16:13:57 +00002433
Stephen Warrenfafd2172011-04-28 17:38:00 -06002434 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002435
Stephen Warrenfafd2172011-04-28 17:38:00 -06002436 update.kcontrol = kcontrol;
2437 update.widget = widget;
2438 update.reg = e->reg;
2439 update.mask = mask;
2440 update.val = val;
2441 widget->dapm->update = &update;
Mark Brown1642e3d2009-10-05 16:24:26 +01002442
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002443 snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
Mark Brown1642e3d2009-10-05 16:24:26 +01002444
Stephen Warrenfafd2172011-04-28 17:38:00 -06002445 widget->dapm->update = NULL;
2446 }
2447 }
2448
2449 mutex_unlock(&codec->mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002450 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002451}
2452EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
2453
2454/**
Mark Brownd2b247a2009-10-06 15:21:04 +01002455 * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
2456 * @kcontrol: mixer control
2457 * @ucontrol: control element information
2458 *
2459 * Returns 0 for success.
2460 */
2461int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
2462 struct snd_ctl_elem_value *ucontrol)
2463{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002464 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2465 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Mark Brownd2b247a2009-10-06 15:21:04 +01002466
2467 ucontrol->value.enumerated.item[0] = widget->value;
2468
2469 return 0;
2470}
2471EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
2472
2473/**
2474 * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
2475 * @kcontrol: mixer control
2476 * @ucontrol: control element information
2477 *
2478 * Returns 0 for success.
2479 */
2480int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
2481 struct snd_ctl_elem_value *ucontrol)
2482{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002483 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2484 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2485 struct snd_soc_codec *codec = widget->codec;
Mark Brownd2b247a2009-10-06 15:21:04 +01002486 struct soc_enum *e =
2487 (struct soc_enum *)kcontrol->private_value;
2488 int change;
2489 int ret = 0;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002490 int wi;
Mark Brownd2b247a2009-10-06 15:21:04 +01002491
2492 if (ucontrol->value.enumerated.item[0] >= e->max)
2493 return -EINVAL;
2494
Stephen Warrenfafd2172011-04-28 17:38:00 -06002495 mutex_lock(&codec->mutex);
Mark Brownd2b247a2009-10-06 15:21:04 +01002496
2497 change = widget->value != ucontrol->value.enumerated.item[0];
Stephen Warrenfafd2172011-04-28 17:38:00 -06002498 if (change) {
2499 for (wi = 0; wi < wlist->num_widgets; wi++) {
2500 widget = wlist->widgets[wi];
Mark Brownd2b247a2009-10-06 15:21:04 +01002501
Stephen Warrenfafd2172011-04-28 17:38:00 -06002502 widget->value = ucontrol->value.enumerated.item[0];
2503
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002504 snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002505 }
2506 }
2507
2508 mutex_unlock(&codec->mutex);
Mark Brownd2b247a2009-10-06 15:21:04 +01002509 return ret;
2510}
2511EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
2512
2513/**
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002514 * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
2515 * callback
2516 * @kcontrol: mixer control
2517 * @ucontrol: control element information
2518 *
2519 * Callback to get the value of a dapm semi enumerated double mixer control.
2520 *
2521 * Semi enumerated mixer: the enumerated items are referred as values. Can be
2522 * used for handling bitfield coded enumeration for example.
2523 *
2524 * Returns 0 for success.
2525 */
2526int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
2527 struct snd_ctl_elem_value *ucontrol)
2528{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002529 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2530 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Peter Ujfalusi74155552009-01-08 13:34:29 +02002531 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002532 unsigned int reg_val, val, mux;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002533
2534 reg_val = snd_soc_read(widget->codec, e->reg);
2535 val = (reg_val >> e->shift_l) & e->mask;
2536 for (mux = 0; mux < e->max; mux++) {
2537 if (val == e->values[mux])
2538 break;
2539 }
2540 ucontrol->value.enumerated.item[0] = mux;
2541 if (e->shift_l != e->shift_r) {
2542 val = (reg_val >> e->shift_r) & e->mask;
2543 for (mux = 0; mux < e->max; mux++) {
2544 if (val == e->values[mux])
2545 break;
2546 }
2547 ucontrol->value.enumerated.item[1] = mux;
2548 }
2549
2550 return 0;
2551}
2552EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
2553
2554/**
2555 * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
2556 * callback
2557 * @kcontrol: mixer control
2558 * @ucontrol: control element information
2559 *
2560 * Callback to set the value of a dapm semi enumerated double mixer control.
2561 *
2562 * Semi enumerated mixer: the enumerated items are referred as values. Can be
2563 * used for handling bitfield coded enumeration for example.
2564 *
2565 * Returns 0 for success.
2566 */
2567int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
2568 struct snd_ctl_elem_value *ucontrol)
2569{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002570 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2571 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2572 struct snd_soc_codec *codec = widget->codec;
Peter Ujfalusi74155552009-01-08 13:34:29 +02002573 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Mark Brown3a655772009-10-05 17:23:30 +01002574 unsigned int val, mux, change;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002575 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00002576 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002577 int wi;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002578
2579 if (ucontrol->value.enumerated.item[0] > e->max - 1)
2580 return -EINVAL;
2581 mux = ucontrol->value.enumerated.item[0];
2582 val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
2583 mask = e->mask << e->shift_l;
2584 if (e->shift_l != e->shift_r) {
2585 if (ucontrol->value.enumerated.item[1] > e->max - 1)
2586 return -EINVAL;
2587 val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
2588 mask |= e->mask << e->shift_r;
2589 }
2590
Stephen Warrenfafd2172011-04-28 17:38:00 -06002591 mutex_lock(&codec->mutex);
2592
Mark Brown3a655772009-10-05 17:23:30 +01002593 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002594 if (change) {
2595 for (wi = 0; wi < wlist->num_widgets; wi++) {
2596 widget = wlist->widgets[wi];
Mark Brown97404f22010-12-14 16:13:57 +00002597
Stephen Warrenfafd2172011-04-28 17:38:00 -06002598 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002599
Stephen Warrenfafd2172011-04-28 17:38:00 -06002600 update.kcontrol = kcontrol;
2601 update.widget = widget;
2602 update.reg = e->reg;
2603 update.mask = mask;
2604 update.val = val;
2605 widget->dapm->update = &update;
Mark Brown1642e3d2009-10-05 16:24:26 +01002606
Liam Girdwood40f02cd2012-02-06 16:05:14 +00002607 snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
Mark Brown1642e3d2009-10-05 16:24:26 +01002608
Stephen Warrenfafd2172011-04-28 17:38:00 -06002609 widget->dapm->update = NULL;
2610 }
2611 }
2612
2613 mutex_unlock(&codec->mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002614 return change;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002615}
2616EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
2617
2618/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00002619 * snd_soc_dapm_info_pin_switch - Info for a pin switch
2620 *
2621 * @kcontrol: mixer control
2622 * @uinfo: control element information
2623 *
2624 * Callback to provide information about a pin switch control.
2625 */
2626int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
2627 struct snd_ctl_elem_info *uinfo)
2628{
2629 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2630 uinfo->count = 1;
2631 uinfo->value.integer.min = 0;
2632 uinfo->value.integer.max = 1;
2633
2634 return 0;
2635}
2636EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
2637
2638/**
2639 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
2640 *
2641 * @kcontrol: mixer control
2642 * @ucontrol: Value
2643 */
2644int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
2645 struct snd_ctl_elem_value *ucontrol)
2646{
2647 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2648 const char *pin = (const char *)kcontrol->private_value;
2649
2650 mutex_lock(&codec->mutex);
2651
2652 ucontrol->value.integer.value[0] =
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002653 snd_soc_dapm_get_pin_status(&codec->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002654
2655 mutex_unlock(&codec->mutex);
2656
2657 return 0;
2658}
2659EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
2660
2661/**
2662 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
2663 *
2664 * @kcontrol: mixer control
2665 * @ucontrol: Value
2666 */
2667int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
2668 struct snd_ctl_elem_value *ucontrol)
2669{
2670 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2671 const char *pin = (const char *)kcontrol->private_value;
2672
2673 mutex_lock(&codec->mutex);
2674
2675 if (ucontrol->value.integer.value[0])
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002676 snd_soc_dapm_enable_pin(&codec->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002677 else
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002678 snd_soc_dapm_disable_pin(&codec->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002679
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002680 snd_soc_dapm_sync(&codec->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002681
2682 mutex_unlock(&codec->mutex);
2683
2684 return 0;
2685}
2686EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
2687
2688/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002689 * snd_soc_dapm_new_control - create new dapm control
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002690 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002691 * @widget: widget template
2692 *
2693 * Creates a new dapm control based upon the template.
2694 *
2695 * Returns 0 for success else error.
2696 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002697int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +02002698 const struct snd_soc_dapm_widget *widget)
2699{
2700 struct snd_soc_dapm_widget *w;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002701 size_t name_len;
Mark Brown62ea8742012-01-21 21:14:48 +00002702 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002703
2704 if ((w = dapm_cnew_widget(widget)) == NULL)
2705 return -ENOMEM;
2706
Mark Brown62ea8742012-01-21 21:14:48 +00002707 switch (w->id) {
2708 case snd_soc_dapm_regulator_supply:
2709 w->priv = devm_regulator_get(dapm->dev, w->name);
2710 if (IS_ERR(w->priv)) {
2711 ret = PTR_ERR(w->priv);
2712 dev_err(dapm->dev, "Failed to request %s: %d\n",
2713 w->name, ret);
2714 return ret;
2715 }
2716 break;
2717 default:
2718 break;
2719 }
2720
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002721 name_len = strlen(widget->name) + 1;
Mark Brown88e8b9a2011-03-02 18:18:24 +00002722 if (dapm->codec && dapm->codec->name_prefix)
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002723 name_len += 1 + strlen(dapm->codec->name_prefix);
2724 w->name = kmalloc(name_len, GFP_KERNEL);
2725 if (w->name == NULL) {
2726 kfree(w);
2727 return -ENOMEM;
2728 }
Mark Brown88e8b9a2011-03-02 18:18:24 +00002729 if (dapm->codec && dapm->codec->name_prefix)
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002730 snprintf(w->name, name_len, "%s %s",
2731 dapm->codec->name_prefix, widget->name);
2732 else
2733 snprintf(w->name, name_len, "%s", widget->name);
2734
Mark Brown7ca3a182011-10-08 14:04:50 +01002735 switch (w->id) {
2736 case snd_soc_dapm_switch:
2737 case snd_soc_dapm_mixer:
2738 case snd_soc_dapm_mixer_named_ctl:
2739 w->power_check = dapm_generic_check_power;
2740 break;
2741 case snd_soc_dapm_mux:
2742 case snd_soc_dapm_virt_mux:
2743 case snd_soc_dapm_value_mux:
2744 w->power_check = dapm_generic_check_power;
2745 break;
2746 case snd_soc_dapm_adc:
2747 case snd_soc_dapm_aif_out:
2748 w->power_check = dapm_adc_check_power;
2749 break;
2750 case snd_soc_dapm_dac:
2751 case snd_soc_dapm_aif_in:
2752 w->power_check = dapm_dac_check_power;
2753 break;
2754 case snd_soc_dapm_pga:
2755 case snd_soc_dapm_out_drv:
2756 case snd_soc_dapm_input:
2757 case snd_soc_dapm_output:
2758 case snd_soc_dapm_micbias:
2759 case snd_soc_dapm_spk:
2760 case snd_soc_dapm_hp:
2761 case snd_soc_dapm_mic:
2762 case snd_soc_dapm_line:
2763 w->power_check = dapm_generic_check_power;
2764 break;
2765 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002766 case snd_soc_dapm_regulator_supply:
Mark Brown7ca3a182011-10-08 14:04:50 +01002767 w->power_check = dapm_supply_check_power;
2768 break;
2769 default:
2770 w->power_check = dapm_always_on_check_power;
2771 break;
2772 }
2773
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002774 dapm->n_widgets++;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002775 w->dapm = dapm;
2776 w->codec = dapm->codec;
Liam Girdwoodb7950642011-07-04 22:10:52 +01002777 w->platform = dapm->platform;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002778 INIT_LIST_HEAD(&w->sources);
2779 INIT_LIST_HEAD(&w->sinks);
2780 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01002781 INIT_LIST_HEAD(&w->dirty);
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002782 list_add(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002783
2784 /* machine layer set ups unconnected pins and insertions */
2785 w->connected = 1;
2786 return 0;
2787}
2788EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
2789
2790/**
Mark Brown4ba13272008-05-13 14:51:19 +02002791 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002792 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02002793 * @widget: widget array
2794 * @num: number of widgets
2795 *
2796 * Creates new DAPM controls based upon the templates.
2797 *
2798 * Returns 0 for success else error.
2799 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002800int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02002801 const struct snd_soc_dapm_widget *widget,
2802 int num)
2803{
2804 int i, ret;
2805
2806 for (i = 0; i < num; i++) {
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002807 ret = snd_soc_dapm_new_control(dapm, widget);
Mark Brownb8b33cb2008-12-18 11:19:30 +00002808 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002809 dev_err(dapm->dev,
2810 "ASoC: Failed to create DAPM control %s: %d\n",
2811 widget->name, ret);
Mark Brown4ba13272008-05-13 14:51:19 +02002812 return ret;
Mark Brownb8b33cb2008-12-18 11:19:30 +00002813 }
Mark Brown4ba13272008-05-13 14:51:19 +02002814 widget++;
2815 }
2816 return 0;
2817}
2818EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
2819
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002820static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00002821 const char *stream, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002822{
2823 struct snd_soc_dapm_widget *w;
2824
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002825 list_for_each_entry(w, &dapm->card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002826 {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002827 if (!w->sname || w->dapm != dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002828 continue;
Liam Girdwoodee47b362011-07-25 11:15:50 +01002829 dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002830 w->name, w->sname, stream, event);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002831 if (strstr(w->sname, stream)) {
Mark Brown75c1f892011-10-04 22:28:08 +01002832 dapm_mark_dirty(w, "stream event");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002833 switch(event) {
2834 case SND_SOC_DAPM_STREAM_START:
2835 w->active = 1;
2836 break;
2837 case SND_SOC_DAPM_STREAM_STOP:
2838 w->active = 0;
2839 break;
2840 case SND_SOC_DAPM_STREAM_SUSPEND:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002841 case SND_SOC_DAPM_STREAM_RESUME:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002842 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002843 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
2844 break;
2845 }
2846 }
2847 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002848
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002849 dapm_power_widgets(dapm, event);
Liam Girdwood64a648c2011-07-25 11:15:15 +01002850
2851 /* do we need to notify any clients that DAPM stream is complete */
2852 if (dapm->stream_event)
2853 dapm->stream_event(dapm, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002854}
2855
2856/**
2857 * snd_soc_dapm_stream_event - send a stream event to the dapm core
2858 * @rtd: PCM runtime data
2859 * @stream: stream name
2860 * @event: stream event
2861 *
2862 * Sends a stream event to the dapm core. The core then makes any
2863 * necessary widget power changes.
2864 *
2865 * Returns 0 for success else error.
2866 */
2867int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
2868 const char *stream, int event)
2869{
2870 struct snd_soc_codec *codec = rtd->codec;
2871
2872 if (stream == NULL)
2873 return 0;
2874
2875 mutex_lock(&codec->mutex);
2876 soc_dapm_stream_event(&codec->dapm, stream, event);
Eero Nurkkala8e8b2d62009-10-12 08:41:59 +03002877 mutex_unlock(&codec->mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002878 return 0;
2879}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002880
2881/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002882 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002883 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01002884 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02002885 *
Mark Brown74b8f952009-06-06 11:26:15 +01002886 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01002887 * a valid audio route and active audio stream.
2888 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2889 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02002890 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002891int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002892{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002893 return snd_soc_dapm_set_pin(dapm, pin, 1);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002894}
Liam Girdwooda5302182008-07-07 13:35:17 +01002895EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002896
2897/**
Mark Brownda341832010-03-15 19:23:37 +00002898 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002899 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00002900 * @pin: pin name
2901 *
2902 * Enables input/output pin regardless of any other state. This is
2903 * intended for use with microphone bias supplies used in microphone
2904 * jack detection.
2905 *
2906 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2907 * do any widget power switching.
2908 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002909int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
2910 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00002911{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002912 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Mark Brownda341832010-03-15 19:23:37 +00002913
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002914 if (!w) {
2915 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
2916 return -EINVAL;
Mark Brownda341832010-03-15 19:23:37 +00002917 }
2918
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002919 dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
2920 w->connected = 1;
2921 w->force = 1;
Mark Brown75c1f892011-10-04 22:28:08 +01002922 dapm_mark_dirty(w, "force enable");
Mark Brown0d867332011-04-06 11:38:14 +09002923
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002924 return 0;
Mark Brownda341832010-03-15 19:23:37 +00002925}
2926EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
2927
2928/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002929 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002930 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01002931 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002932 *
Mark Brown74b8f952009-06-06 11:26:15 +01002933 * Disables input/output pin and its parents or children widgets.
Liam Girdwooda5302182008-07-07 13:35:17 +01002934 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2935 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002936 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002937int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
2938 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01002939{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002940 return snd_soc_dapm_set_pin(dapm, pin, 0);
Liam Girdwooda5302182008-07-07 13:35:17 +01002941}
2942EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
2943
2944/**
Mark Brown5817b522008-09-24 11:23:11 +01002945 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002946 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01002947 * @pin: pin name
2948 *
2949 * Marks the specified pin as being not connected, disabling it along
2950 * any parent or child widgets. At present this is identical to
2951 * snd_soc_dapm_disable_pin() but in future it will be extended to do
2952 * additional things such as disabling controls which only affect
2953 * paths through the pin.
2954 *
2955 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2956 * do any widget power switching.
2957 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002958int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01002959{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002960 return snd_soc_dapm_set_pin(dapm, pin, 0);
Mark Brown5817b522008-09-24 11:23:11 +01002961}
2962EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
2963
2964/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002965 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002966 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01002967 * @pin: audio signal pin endpoint (or start point)
2968 *
2969 * Get audio pin status - connected or disconnected.
2970 *
2971 * Returns 1 for connected otherwise 0.
2972 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002973int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
2974 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002975{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002976 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002977
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002978 if (w)
2979 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06002980
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002981 return 0;
2982}
Liam Girdwooda5302182008-07-07 13:35:17 +01002983EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002984
2985/**
Mark Brown1547aba2010-05-07 21:11:40 +01002986 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002987 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01002988 * @pin: audio signal pin endpoint (or start point)
2989 *
2990 * Mark the given endpoint or pin as ignoring suspend. When the
2991 * system is disabled a path between two endpoints flagged as ignoring
2992 * suspend will not be disabled. The path must already be enabled via
2993 * normal means at suspend time, it will not be turned on if it was not
2994 * already enabled.
2995 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002996int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
2997 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01002998{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002999 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01003000
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003001 if (!w) {
3002 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
3003 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01003004 }
3005
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003006 w->ignore_suspend = 1;
3007
3008 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01003009}
3010EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
3011
Stephen Warren16332812011-11-23 12:42:04 -07003012static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
3013 struct snd_soc_dapm_widget *w)
3014{
3015 struct snd_soc_dapm_path *p;
3016
3017 list_for_each_entry(p, &card->paths, list) {
3018 if ((p->source == w) || (p->sink == w)) {
3019 dev_dbg(card->dev,
3020 "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
3021 p->source->name, p->source->id, p->source->dapm,
3022 p->sink->name, p->sink->id, p->sink->dapm);
3023
3024 /* Connected to something other than the codec */
3025 if (p->source->dapm != p->sink->dapm)
3026 return true;
3027 /*
3028 * Loopback connection from codec external pin to
3029 * codec external pin
3030 */
3031 if (p->sink->id == snd_soc_dapm_input) {
3032 switch (p->source->id) {
3033 case snd_soc_dapm_output:
3034 case snd_soc_dapm_micbias:
3035 return true;
3036 default:
3037 break;
3038 }
3039 }
3040 }
3041 }
3042
3043 return false;
3044}
3045
3046/**
3047 * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins
3048 * @codec: The codec whose pins should be processed
3049 *
3050 * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec
3051 * which are unused. Pins are used if they are connected externally to the
3052 * codec, whether that be to some other device, or a loop-back connection to
3053 * the codec itself.
3054 */
3055void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec)
3056{
3057 struct snd_soc_card *card = codec->card;
3058 struct snd_soc_dapm_context *dapm = &codec->dapm;
3059 struct snd_soc_dapm_widget *w;
3060
Mark Browna094b802011-11-27 19:42:20 +00003061 dev_dbg(codec->dev, "Auto NC: DAPMs: card:%p codec:%p\n",
Stephen Warren16332812011-11-23 12:42:04 -07003062 &card->dapm, &codec->dapm);
3063
3064 list_for_each_entry(w, &card->widgets, list) {
3065 if (w->dapm != dapm)
3066 continue;
3067 switch (w->id) {
3068 case snd_soc_dapm_input:
3069 case snd_soc_dapm_output:
3070 case snd_soc_dapm_micbias:
Mark Browna094b802011-11-27 19:42:20 +00003071 dev_dbg(codec->dev, "Auto NC: Checking widget %s\n",
Stephen Warren16332812011-11-23 12:42:04 -07003072 w->name);
3073 if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
Mark Browna094b802011-11-27 19:42:20 +00003074 dev_dbg(codec->dev,
Stephen Warren16332812011-11-23 12:42:04 -07003075 "... Not in map; disabling\n");
3076 snd_soc_dapm_nc_pin(dapm, w->name);
3077 }
3078 break;
3079 default:
3080 break;
3081 }
3082 }
3083}
3084
Mark Brown1547aba2010-05-07 21:11:40 +01003085/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02003086 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03003087 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02003088 *
3089 * Free all dapm widgets and resources.
3090 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003091void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003092{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003093 snd_soc_dapm_sys_remove(dapm->dev);
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02003094 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003095 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02003096 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003097}
3098EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
3099
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003100static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01003101{
Mark Brown51737472009-06-22 13:16:51 +01003102 struct snd_soc_dapm_widget *w;
3103 LIST_HEAD(down_list);
3104 int powerdown = 0;
3105
Jarkko Nikula97c866d2010-12-14 12:18:31 +02003106 list_for_each_entry(w, &dapm->card->widgets, list) {
3107 if (w->dapm != dapm)
3108 continue;
Mark Brown51737472009-06-22 13:16:51 +01003109 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00003110 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01003111 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01003112 powerdown = 1;
3113 }
3114 }
3115
3116 /* If there were no widgets to power down we're already in
3117 * standby.
3118 */
3119 if (powerdown) {
Mark Browned5a4c42011-02-18 11:12:42 -08003120 snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE);
Mark Brown828a8422011-01-15 13:14:30 +00003121 dapm_seq_run(dapm, &down_list, 0, false);
Mark Browned5a4c42011-02-18 11:12:42 -08003122 snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01003123 }
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00003124}
Mark Brown51737472009-06-22 13:16:51 +01003125
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00003126/*
3127 * snd_soc_dapm_shutdown - callback for system shutdown
3128 */
3129void snd_soc_dapm_shutdown(struct snd_soc_card *card)
3130{
3131 struct snd_soc_codec *codec;
3132
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003133 list_for_each_entry(codec, &card->codec_dev_list, list) {
3134 soc_dapm_shutdown_codec(&codec->dapm);
Mark Browned5a4c42011-02-18 11:12:42 -08003135 snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003136 }
Mark Brown51737472009-06-22 13:16:51 +01003137}
3138
Richard Purdie2b97eab2006-10-06 18:32:18 +02003139/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01003140MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02003141MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
3142MODULE_LICENSE("GPL");