blob: a66379accec9ca1d8f9770df1b2db7b511120518 [file] [log] [blame]
Richard Purdie2b97eab2006-10-06 18:32:18 +02001/*
2 * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
3 *
4 * Copyright 2005 Wolfson Microelectronics PLC.
Liam Girdwoodd3311242008-10-12 13:17:36 +01005 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
Richard Purdie2b97eab2006-10-06 18:32:18 +02006 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
Richard Purdie2b97eab2006-10-06 18:32:18 +020012 * Features:
13 * o Changes power status of internal codec blocks depending on the
14 * dynamic configuration of codec internal audio paths and active
Mark Brown74b8f952009-06-06 11:26:15 +010015 * DACs/ADCs.
Richard Purdie2b97eab2006-10-06 18:32:18 +020016 * o Platform power domain - can support external components i.e. amps and
Liam Girdwood612a3fe2012-02-06 16:05:29 +000017 * mic/headphone insertion events.
Richard Purdie2b97eab2006-10-06 18:32:18 +020018 * o Automatic Mic Bias support
19 * o Jack insertion power event initiation - e.g. hp insertion will enable
20 * sinks, dacs, etc
Liam Girdwood612a3fe2012-02-06 16:05:29 +000021 * o Delayed power down of audio subsystem to reduce pops between a quick
Richard Purdie2b97eab2006-10-06 18:32:18 +020022 * device reopen.
23 *
Richard Purdie2b97eab2006-10-06 18:32:18 +020024 */
25
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/init.h>
Mark Brown9d0624a2011-02-18 11:49:43 -080029#include <linux/async.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020030#include <linux/delay.h>
31#include <linux/pm.h>
32#include <linux/bitops.h>
33#include <linux/platform_device.h>
34#include <linux/jiffies.h>
Takashi Iwai20496ff2009-08-24 09:40:34 +020035#include <linux/debugfs.h>
Mark Brownf1aac482011-12-05 15:17:06 +000036#include <linux/pm_runtime.h>
Mark Brown62ea8742012-01-21 21:14:48 +000037#include <linux/regulator/consumer.h>
Ola Liljad7e7eb92012-05-24 15:26:25 +020038#include <linux/clk.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090039#include <linux/slab.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020040#include <sound/core.h>
41#include <sound/pcm.h>
42#include <sound/pcm_params.h>
Liam Girdwoodce6120c2010-11-05 15:53:46 +020043#include <sound/soc.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020044#include <sound/initval.h>
45
Mark Brown84e90932010-11-04 00:07:02 -040046#include <trace/events/asoc.h>
47
Mark Brownde02d072011-09-20 21:43:24 +010048#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
49
Richard Purdie2b97eab2006-10-06 18:32:18 +020050/* dapm power sequences - make this per codec in the future */
51static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010052 [snd_soc_dapm_pre] = 0,
53 [snd_soc_dapm_supply] = 1,
Mark Brown62ea8742012-01-21 21:14:48 +000054 [snd_soc_dapm_regulator_supply] = 1,
Ola Liljad7e7eb92012-05-24 15:26:25 +020055 [snd_soc_dapm_clock_supply] = 1,
Mark Brown38357ab2009-06-06 19:03:23 +010056 [snd_soc_dapm_micbias] = 2,
Mark Brownc74184e2012-04-04 22:12:09 +010057 [snd_soc_dapm_dai_link] = 2,
Mark Brown888df392012-02-16 19:37:51 -080058 [snd_soc_dapm_dai] = 3,
Mark Brown010ff262009-08-17 17:39:22 +010059 [snd_soc_dapm_aif_in] = 3,
60 [snd_soc_dapm_aif_out] = 3,
61 [snd_soc_dapm_mic] = 4,
62 [snd_soc_dapm_mux] = 5,
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +000063 [snd_soc_dapm_virt_mux] = 5,
Mark Brown010ff262009-08-17 17:39:22 +010064 [snd_soc_dapm_value_mux] = 5,
65 [snd_soc_dapm_dac] = 6,
66 [snd_soc_dapm_mixer] = 7,
67 [snd_soc_dapm_mixer_named_ctl] = 7,
68 [snd_soc_dapm_pga] = 8,
69 [snd_soc_dapm_adc] = 9,
Olaya, Margaritad88429a2010-12-10 21:11:44 -060070 [snd_soc_dapm_out_drv] = 10,
Mark Brown010ff262009-08-17 17:39:22 +010071 [snd_soc_dapm_hp] = 10,
72 [snd_soc_dapm_spk] = 10,
Mark Brown7e1f7c82012-04-12 17:29:36 +010073 [snd_soc_dapm_line] = 10,
Mark Brown010ff262009-08-17 17:39:22 +010074 [snd_soc_dapm_post] = 11,
Richard Purdie2b97eab2006-10-06 18:32:18 +020075};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000076
Richard Purdie2b97eab2006-10-06 18:32:18 +020077static int dapm_down_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010078 [snd_soc_dapm_pre] = 0,
79 [snd_soc_dapm_adc] = 1,
80 [snd_soc_dapm_hp] = 2,
Mark Brown1ca04062009-08-17 16:26:59 +010081 [snd_soc_dapm_spk] = 2,
Mark Brown7e1f7c82012-04-12 17:29:36 +010082 [snd_soc_dapm_line] = 2,
Olaya, Margaritad88429a2010-12-10 21:11:44 -060083 [snd_soc_dapm_out_drv] = 2,
Mark Brown38357ab2009-06-06 19:03:23 +010084 [snd_soc_dapm_pga] = 4,
85 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +010086 [snd_soc_dapm_mixer] = 5,
87 [snd_soc_dapm_dac] = 6,
88 [snd_soc_dapm_mic] = 7,
89 [snd_soc_dapm_micbias] = 8,
90 [snd_soc_dapm_mux] = 9,
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +000091 [snd_soc_dapm_virt_mux] = 9,
Mark Browne3d4dab2009-06-07 13:08:45 +010092 [snd_soc_dapm_value_mux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +010093 [snd_soc_dapm_aif_in] = 10,
94 [snd_soc_dapm_aif_out] = 10,
Mark Brown888df392012-02-16 19:37:51 -080095 [snd_soc_dapm_dai] = 10,
Mark Brownc74184e2012-04-04 22:12:09 +010096 [snd_soc_dapm_dai_link] = 11,
Ola Liljad7e7eb92012-05-24 15:26:25 +020097 [snd_soc_dapm_clock_supply] = 12,
Mark Brownc74184e2012-04-04 22:12:09 +010098 [snd_soc_dapm_regulator_supply] = 12,
99 [snd_soc_dapm_supply] = 12,
100 [snd_soc_dapm_post] = 13,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200101};
102
Troy Kisky12ef1932008-10-13 17:42:14 -0700103static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +0100104{
105 if (pop_time)
106 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
107}
108
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200109static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100110{
111 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200112 char *buf;
113
114 if (!pop_time)
115 return;
116
117 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
118 if (buf == NULL)
119 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100120
121 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200122 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100123 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100124 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200125
126 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100127}
128
Mark Browndb432b42011-10-03 21:06:40 +0100129static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w)
130{
131 return !list_empty(&w->dirty);
132}
133
Mark Brown25c77c52011-10-08 13:36:03 +0100134void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
Mark Browndb432b42011-10-03 21:06:40 +0100135{
Mark Brown75c1f892011-10-04 22:28:08 +0100136 if (!dapm_dirty_widget(w)) {
137 dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n",
138 w->name, reason);
Mark Browndb432b42011-10-03 21:06:40 +0100139 list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty);
Mark Brown75c1f892011-10-04 22:28:08 +0100140 }
Mark Browndb432b42011-10-03 21:06:40 +0100141}
Mark Brown25c77c52011-10-08 13:36:03 +0100142EXPORT_SYMBOL_GPL(dapm_mark_dirty);
Mark Browndb432b42011-10-03 21:06:40 +0100143
Richard Purdie2b97eab2006-10-06 18:32:18 +0200144/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100145static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200146 const struct snd_soc_dapm_widget *_widget)
147{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100148 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200149}
150
Liam Girdwood48056082011-07-20 12:23:33 +0100151/* get snd_card from DAPM context */
152static inline struct snd_card *dapm_get_snd_card(
153 struct snd_soc_dapm_context *dapm)
154{
155 if (dapm->codec)
156 return dapm->codec->card->snd_card;
157 else if (dapm->platform)
158 return dapm->platform->card->snd_card;
159 else
160 BUG();
161
162 /* unreachable */
163 return NULL;
164}
165
166/* get soc_card from DAPM context */
167static inline struct snd_soc_card *dapm_get_soc_card(
168 struct snd_soc_dapm_context *dapm)
169{
170 if (dapm->codec)
171 return dapm->codec->card;
172 else if (dapm->platform)
173 return dapm->platform->card;
174 else
175 BUG();
176
177 /* unreachable */
178 return NULL;
179}
180
Liam Girdwood6c120e12012-02-15 15:15:34 +0000181static void dapm_reset(struct snd_soc_card *card)
182{
183 struct snd_soc_dapm_widget *w;
184
185 memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
186
187 list_for_each_entry(w, &card->widgets, list) {
188 w->power_checked = false;
189 w->inputs = -1;
190 w->outputs = -1;
191 }
192}
193
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100194static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
195{
196 if (w->codec)
197 return snd_soc_read(w->codec, reg);
Liam Girdwoodb7950642011-07-04 22:10:52 +0100198 else if (w->platform)
199 return snd_soc_platform_read(w->platform, reg);
200
201 dev_err(w->dapm->dev, "no valid widget read method\n");
202 return -1;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100203}
204
205static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
206{
207 if (w->codec)
208 return snd_soc_write(w->codec, reg, val);
Liam Girdwoodb7950642011-07-04 22:10:52 +0100209 else if (w->platform)
210 return snd_soc_platform_write(w->platform, reg, val);
211
212 dev_err(w->dapm->dev, "no valid widget write method\n");
213 return -1;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100214}
215
Liam Girdwood49575fb52012-03-06 18:16:19 +0000216static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
217{
Mark Browne06ab3b2012-03-06 23:58:22 +0000218 if (w->codec && !w->codec->using_regmap)
Liam Girdwood49575fb52012-03-06 18:16:19 +0000219 mutex_lock(&w->codec->mutex);
220 else if (w->platform)
221 mutex_lock(&w->platform->mutex);
222}
223
224static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
225{
Mark Browne06ab3b2012-03-06 23:58:22 +0000226 if (w->codec && !w->codec->using_regmap)
Liam Girdwood49575fb52012-03-06 18:16:19 +0000227 mutex_unlock(&w->codec->mutex);
228 else if (w->platform)
229 mutex_unlock(&w->platform->mutex);
230}
231
232static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100233 unsigned short reg, unsigned int mask, unsigned int value)
234{
Mark Brown8a713da2011-12-03 12:33:55 +0000235 bool change;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100236 unsigned int old, new;
237 int ret;
238
Mark Brown8a713da2011-12-03 12:33:55 +0000239 if (w->codec && w->codec->using_regmap) {
240 ret = regmap_update_bits_check(w->codec->control_data,
241 reg, mask, value, &change);
242 if (ret != 0)
243 return ret;
244 } else {
Liam Girdwood49575fb52012-03-06 18:16:19 +0000245 soc_widget_lock(w);
Mark Brown8a713da2011-12-03 12:33:55 +0000246 ret = soc_widget_read(w, reg);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000247 if (ret < 0) {
248 soc_widget_unlock(w);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100249 return ret;
Liam Girdwood49575fb52012-03-06 18:16:19 +0000250 }
Mark Brown8a713da2011-12-03 12:33:55 +0000251
252 old = ret;
253 new = (old & ~mask) | (value & mask);
254 change = old != new;
255 if (change) {
256 ret = soc_widget_write(w, reg, new);
Liam Girdwood49575fb52012-03-06 18:16:19 +0000257 if (ret < 0) {
258 soc_widget_unlock(w);
Mark Brown8a713da2011-12-03 12:33:55 +0000259 return ret;
Liam Girdwood49575fb52012-03-06 18:16:19 +0000260 }
Mark Brown8a713da2011-12-03 12:33:55 +0000261 }
Liam Girdwood49575fb52012-03-06 18:16:19 +0000262 soc_widget_unlock(w);
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100263 }
264
265 return change;
266}
267
Mark Brown452c5ea2009-05-17 21:41:23 +0100268/**
269 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800270 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100271 * @level: level to configure
272 *
273 * Configure the bias (power) levels for the SoC audio device.
274 *
275 * Returns 0 for success else error.
276 */
Mark Browned5a4c42011-02-18 11:12:42 -0800277static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200278 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100279{
Mark Browned5a4c42011-02-18 11:12:42 -0800280 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100281 int ret = 0;
282
Mark Brown84e90932010-11-04 00:07:02 -0400283 trace_snd_soc_bias_level_start(card, level);
284
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000285 if (card && card->set_bias_level)
Mark Brownd4c60052011-06-06 19:13:23 +0100286 ret = card->set_bias_level(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100287 if (ret != 0)
288 goto out;
Mark Brown452c5ea2009-05-17 21:41:23 +0100289
Mark Browncc4c6702011-06-06 19:03:34 +0100290 if (dapm->codec) {
291 if (dapm->codec->driver->set_bias_level)
292 ret = dapm->codec->driver->set_bias_level(dapm->codec,
293 level);
294 else
295 dapm->bias_level = level;
296 }
Mark Brown171ec6b2011-06-06 18:15:19 +0100297 if (ret != 0)
298 goto out;
299
300 if (card && card->set_bias_level_post)
Mark Brownd4c60052011-06-06 19:13:23 +0100301 ret = card->set_bias_level_post(card, dapm, level);
Mark Brown171ec6b2011-06-06 18:15:19 +0100302out:
Mark Brown84e90932010-11-04 00:07:02 -0400303 trace_snd_soc_bias_level_done(card, level);
304
Mark Brown452c5ea2009-05-17 21:41:23 +0100305 return ret;
306}
307
Richard Purdie2b97eab2006-10-06 18:32:18 +0200308/* set up initial codec paths */
309static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
310 struct snd_soc_dapm_path *p, int i)
311{
312 switch (w->id) {
313 case snd_soc_dapm_switch:
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000314 case snd_soc_dapm_mixer:
315 case snd_soc_dapm_mixer_named_ctl: {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200316 int val;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100317 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Stephen Warren82cfecd2011-04-28 17:37:58 -0600318 w->kcontrol_news[i].private_value;
Jon Smirl815ecf82008-07-29 10:22:24 -0400319 unsigned int reg = mc->reg;
320 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100321 int max = mc->max;
Jon Smirl815ecf82008-07-29 10:22:24 -0400322 unsigned int mask = (1 << fls(max)) - 1;
323 unsigned int invert = mc->invert;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200324
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100325 val = soc_widget_read(w, reg);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200326 val = (val >> shift) & mask;
327
328 if ((invert && !val) || (!invert && val))
329 p->connect = 1;
330 else
331 p->connect = 0;
332 }
333 break;
334 case snd_soc_dapm_mux: {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600335 struct soc_enum *e = (struct soc_enum *)
336 w->kcontrol_news[i].private_value;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200337 int val, item, bitmask;
338
Jon Smirlf8ba0b7b2008-07-29 11:42:27 +0100339 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Mark Brown88d96082011-06-06 16:16:34 +0100340 ;
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100341 val = soc_widget_read(w, e->reg);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200342 item = (val >> e->shift_l) & (bitmask - 1);
343
344 p->connect = 0;
Jon Smirlf8ba0b7b2008-07-29 11:42:27 +0100345 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200346 if (!(strcmp(p->name, e->texts[i])) && item == i)
347 p->connect = 1;
348 }
349 }
350 break;
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +0000351 case snd_soc_dapm_virt_mux: {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600352 struct soc_enum *e = (struct soc_enum *)
353 w->kcontrol_news[i].private_value;
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +0000354
355 p->connect = 0;
356 /* since a virtual mux has no backing registers to
357 * decide which path to connect, it will try to match
358 * with the first enumeration. This is to ensure
359 * that the default mux choice (the first) will be
360 * correctly powered up during initialization.
361 */
362 if (!strcmp(p->name, e->texts[0]))
363 p->connect = 1;
364 }
365 break;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200366 case snd_soc_dapm_value_mux: {
Peter Ujfalusi74155552009-01-08 13:34:29 +0200367 struct soc_enum *e = (struct soc_enum *)
Stephen Warren82cfecd2011-04-28 17:37:58 -0600368 w->kcontrol_news[i].private_value;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200369 int val, item;
370
Liam Girdwood0445bdf2011-06-13 19:37:36 +0100371 val = soc_widget_read(w, e->reg);
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200372 val = (val >> e->shift_l) & e->mask;
373 for (item = 0; item < e->max; item++) {
374 if (val == e->values[item])
375 break;
376 }
377
378 p->connect = 0;
379 for (i = 0; i < e->max; i++) {
380 if (!(strcmp(p->name, e->texts[i])) && item == i)
381 p->connect = 1;
382 }
383 }
384 break;
Mark Brown56563102011-10-03 22:41:09 +0100385 /* does not affect routing - always connected */
Richard Purdie2b97eab2006-10-06 18:32:18 +0200386 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -0600387 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200388 case snd_soc_dapm_output:
389 case snd_soc_dapm_adc:
390 case snd_soc_dapm_input:
Mark Brown1ab97c82011-11-27 16:21:51 +0000391 case snd_soc_dapm_siggen:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200392 case snd_soc_dapm_dac:
393 case snd_soc_dapm_micbias:
394 case snd_soc_dapm_vmid:
Mark Brown246d0a12009-04-22 18:24:55 +0100395 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +0000396 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +0200397 case snd_soc_dapm_clock_supply:
Mark Brown010ff262009-08-17 17:39:22 +0100398 case snd_soc_dapm_aif_in:
399 case snd_soc_dapm_aif_out:
Mark Brown888df392012-02-16 19:37:51 -0800400 case snd_soc_dapm_dai:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200401 case snd_soc_dapm_hp:
402 case snd_soc_dapm_mic:
403 case snd_soc_dapm_spk:
404 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +0100405 case snd_soc_dapm_dai_link:
Mark Brown56563102011-10-03 22:41:09 +0100406 p->connect = 1;
407 break;
408 /* does affect routing - dynamically connected */
Richard Purdie2b97eab2006-10-06 18:32:18 +0200409 case snd_soc_dapm_pre:
410 case snd_soc_dapm_post:
411 p->connect = 0;
412 break;
413 }
414}
415
Mark Brown74b8f952009-06-06 11:26:15 +0100416/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200417static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200418 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
419 struct snd_soc_dapm_path *path, const char *control_name,
420 const struct snd_kcontrol_new *kcontrol)
421{
422 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
423 int i;
424
Jon Smirlf8ba0b7b2008-07-29 11:42:27 +0100425 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200426 if (!(strcmp(control_name, e->texts[i]))) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200427 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200428 list_add(&path->list_sink, &dest->sources);
429 list_add(&path->list_source, &src->sinks);
430 path->name = (char*)e->texts[i];
431 dapm_set_path_status(dest, path, 0);
432 return 0;
433 }
434 }
435
436 return -ENODEV;
437}
438
Mark Brown74b8f952009-06-06 11:26:15 +0100439/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200440static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200441 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
442 struct snd_soc_dapm_path *path, const char *control_name)
443{
444 int i;
445
446 /* search for mixer kcontrol */
447 for (i = 0; i < dest->num_kcontrols; i++) {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600448 if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200449 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200450 list_add(&path->list_sink, &dest->sources);
451 list_add(&path->list_source, &src->sinks);
Stephen Warren82cfecd2011-04-28 17:37:58 -0600452 path->name = dest->kcontrol_news[i].name;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200453 dapm_set_path_status(dest, path, i);
454 return 0;
455 }
456 }
457 return -ENODEV;
458}
459
Stephen Warrenaf468002011-04-28 17:38:01 -0600460static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600461 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600462 const struct snd_kcontrol_new *kcontrol_new,
463 struct snd_kcontrol **kcontrol)
464{
465 struct snd_soc_dapm_widget *w;
466 int i;
467
468 *kcontrol = NULL;
469
470 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600471 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
472 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600473 for (i = 0; i < w->num_kcontrols; i++) {
474 if (&w->kcontrol_news[i] == kcontrol_new) {
475 if (w->kcontrols)
476 *kcontrol = w->kcontrols[i];
477 return 1;
478 }
479 }
480 }
481
482 return 0;
483}
484
Richard Purdie2b97eab2006-10-06 18:32:18 +0200485/* create new dapm mixer control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200486static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200487{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200488 struct snd_soc_dapm_context *dapm = w->dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200489 int i, ret = 0;
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000490 size_t name_len, prefix_len;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200491 struct snd_soc_dapm_path *path;
Mark Brown12ea2c72011-03-02 18:17:32 +0000492 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000493 const char *prefix;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600494 struct snd_soc_dapm_widget_list *wlist;
495 size_t wlistsize;
Mark Brownefb7ac32011-03-08 17:23:24 +0000496
497 if (dapm->codec)
498 prefix = dapm->codec->name_prefix;
499 else
500 prefix = NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200501
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000502 if (prefix)
503 prefix_len = strlen(prefix) + 1;
504 else
505 prefix_len = 0;
506
Richard Purdie2b97eab2006-10-06 18:32:18 +0200507 /* add kcontrol */
508 for (i = 0; i < w->num_kcontrols; i++) {
509
510 /* match name */
511 list_for_each_entry(path, &w->sources, list_sink) {
512
513 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600514 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200515 continue;
516
Lars-Peter Clausen82cd8762011-08-15 20:15:21 +0200517 if (w->kcontrols[i]) {
518 path->kcontrol = w->kcontrols[i];
519 continue;
520 }
521
Stephen Warrenfafd2172011-04-28 17:38:00 -0600522 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
523 sizeof(struct snd_soc_dapm_widget *),
524 wlist = kzalloc(wlistsize, GFP_KERNEL);
525 if (wlist == NULL) {
526 dev_err(dapm->dev,
527 "asoc: can't allocate widget list for %s\n",
528 w->name);
529 return -ENOMEM;
530 }
531 wlist->num_widgets = 1;
532 wlist->widgets[0] = w;
533
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000534 /* add dapm control with long name.
535 * for dapm_mixer this is the concatenation of the
536 * mixer and kcontrol name.
537 * for dapm_mixer_named_ctl this is simply the
538 * kcontrol name.
539 */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600540 name_len = strlen(w->kcontrol_news[i].name) + 1;
Mark Brown07495f32009-03-05 17:06:23 +0000541 if (w->id != snd_soc_dapm_mixer_named_ctl)
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000542 name_len += 1 + strlen(w->name);
543
Mark Brown219b93f2008-10-28 13:02:31 +0000544 path->long_name = kmalloc(name_len, GFP_KERNEL);
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000545
Stephen Warrenfafd2172011-04-28 17:38:00 -0600546 if (path->long_name == NULL) {
547 kfree(wlist);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200548 return -ENOMEM;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600549 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200550
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000551 switch (w->id) {
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000552 default:
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000553 /* The control will get a prefix from
554 * the control creation process but
555 * we're also using the same prefix
556 * for widgets so cut the prefix off
557 * the front of the widget name.
558 */
Mark Brown888df392012-02-16 19:37:51 -0800559 snprintf((char *)path->long_name, name_len,
560 "%s %s", w->name + prefix_len,
Stephen Warren82cfecd2011-04-28 17:37:58 -0600561 w->kcontrol_news[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000562 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000563 case snd_soc_dapm_mixer_named_ctl:
Mark Brown888df392012-02-16 19:37:51 -0800564 snprintf((char *)path->long_name, name_len,
565 "%s", w->kcontrol_news[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000566 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000567 }
568
Mark Brown888df392012-02-16 19:37:51 -0800569 ((char *)path->long_name)[name_len - 1] = '\0';
Mark Brown219b93f2008-10-28 13:02:31 +0000570
Stephen Warrenfafd2172011-04-28 17:38:00 -0600571 path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
572 wlist, path->long_name,
573 prefix);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200574 ret = snd_ctl_add(card, path->kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200575 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200576 dev_err(dapm->dev,
577 "asoc: failed to add dapm kcontrol %s: %d\n",
578 path->long_name, ret);
Stephen Warrenfafd2172011-04-28 17:38:00 -0600579 kfree(wlist);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200580 kfree(path->long_name);
581 path->long_name = NULL;
582 return ret;
583 }
Stephen Warrenfad59882011-04-28 17:37:59 -0600584 w->kcontrols[i] = path->kcontrol;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200585 }
586 }
587 return ret;
588}
589
590/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200591static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200592{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200593 struct snd_soc_dapm_context *dapm = w->dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200594 struct snd_soc_dapm_path *path = NULL;
595 struct snd_kcontrol *kcontrol;
Mark Brown12ea2c72011-03-02 18:17:32 +0000596 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000597 const char *prefix;
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000598 size_t prefix_len;
Stephen Warrenaf468002011-04-28 17:38:01 -0600599 int ret;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600600 struct snd_soc_dapm_widget_list *wlist;
Stephen Warrenaf468002011-04-28 17:38:01 -0600601 int shared, wlistentries;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600602 size_t wlistsize;
Mark Brown888df392012-02-16 19:37:51 -0800603 const char *name;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200604
Stephen Warrenaf468002011-04-28 17:38:01 -0600605 if (w->num_kcontrols != 1) {
606 dev_err(dapm->dev,
607 "asoc: mux %s has incorrect number of controls\n",
608 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200609 return -EINVAL;
610 }
611
Stephen Warren1007da02011-05-26 09:57:33 -0600612 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
Stephen Warrenaf468002011-04-28 17:38:01 -0600613 &kcontrol);
614 if (kcontrol) {
615 wlist = kcontrol->private_data;
616 wlistentries = wlist->num_widgets + 1;
617 } else {
618 wlist = NULL;
619 wlistentries = 1;
620 }
Stephen Warrenfafd2172011-04-28 17:38:00 -0600621 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
Stephen Warrenaf468002011-04-28 17:38:01 -0600622 wlistentries * sizeof(struct snd_soc_dapm_widget *),
623 wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
Stephen Warrenfafd2172011-04-28 17:38:00 -0600624 if (wlist == NULL) {
625 dev_err(dapm->dev,
626 "asoc: can't allocate widget list for %s\n", w->name);
627 return -ENOMEM;
628 }
Stephen Warrenaf468002011-04-28 17:38:01 -0600629 wlist->num_widgets = wlistentries;
630 wlist->widgets[wlistentries - 1] = w;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600631
Stephen Warrenaf468002011-04-28 17:38:01 -0600632 if (!kcontrol) {
633 if (dapm->codec)
634 prefix = dapm->codec->name_prefix;
635 else
636 prefix = NULL;
Mark Brownefb7ac32011-03-08 17:23:24 +0000637
Stephen Warrenaf468002011-04-28 17:38:01 -0600638 if (shared) {
639 name = w->kcontrol_news[0].name;
640 prefix_len = 0;
641 } else {
642 name = w->name;
643 if (prefix)
644 prefix_len = strlen(prefix) + 1;
645 else
646 prefix_len = 0;
647 }
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000648
Stephen Warrenaf468002011-04-28 17:38:01 -0600649 /*
650 * The control will get a prefix from the control creation
651 * process but we're also using the same prefix for widgets so
652 * cut the prefix off the front of the widget name.
653 */
654 kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
655 name + prefix_len, prefix);
656 ret = snd_ctl_add(card, kcontrol);
657 if (ret < 0) {
Mark Brown53daf202011-09-05 10:51:05 -0700658 dev_err(dapm->dev, "failed to add kcontrol %s: %d\n",
659 w->name, ret);
Stephen Warrenaf468002011-04-28 17:38:01 -0600660 kfree(wlist);
661 return ret;
662 }
663 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200664
Stephen Warrenaf468002011-04-28 17:38:01 -0600665 kcontrol->private_data = wlist;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200666
Stephen Warrenfad59882011-04-28 17:37:59 -0600667 w->kcontrols[0] = kcontrol;
668
Richard Purdie2b97eab2006-10-06 18:32:18 +0200669 list_for_each_entry(path, &w->sources, list_sink)
670 path->kcontrol = kcontrol;
671
Stephen Warrenaf468002011-04-28 17:38:01 -0600672 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200673}
674
675/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200676static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200677{
Mark Browna6c65732010-03-03 17:45:21 +0000678 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200679 dev_err(w->dapm->dev,
680 "asoc: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200681
Mark Browna6c65732010-03-03 17:45:21 +0000682 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200683}
684
685/* reset 'walked' bit for each dapm path */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200686static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200687{
688 struct snd_soc_dapm_path *p;
689
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200690 list_for_each_entry(p, &dapm->card->paths, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200691 p->walked = 0;
692}
693
Mark Brown99497882010-05-07 20:24:05 +0100694/* We implement power down on suspend by checking the power state of
695 * the ALSA card - when we are suspending the ALSA state for the card
696 * is set to D3.
697 */
698static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
699{
Mark Brown12ea2c72011-03-02 18:17:32 +0000700 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +0100701
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000702 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +0100703 case SNDRV_CTL_POWER_D3hot:
704 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +0100705 if (widget->ignore_suspend)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200706 dev_dbg(widget->dapm->dev, "%s ignoring suspend\n",
707 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +0100708 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +0100709 default:
710 return 1;
711 }
712}
713
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100714/* add widget to list if it's not already in the list */
715static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
716 struct snd_soc_dapm_widget *w)
717{
718 struct snd_soc_dapm_widget_list *wlist;
719 int wlistsize, wlistentries, i;
720
721 if (*list == NULL)
722 return -EINVAL;
723
724 wlist = *list;
725
726 /* is this widget already in the list */
727 for (i = 0; i < wlist->num_widgets; i++) {
728 if (wlist->widgets[i] == w)
729 return 0;
730 }
731
732 /* allocate some new space */
733 wlistentries = wlist->num_widgets + 1;
734 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
735 wlistentries * sizeof(struct snd_soc_dapm_widget *);
736 *list = krealloc(wlist, wlistsize, GFP_KERNEL);
737 if (*list == NULL) {
738 dev_err(w->dapm->dev, "can't allocate widget list for %s\n",
739 w->name);
740 return -ENOMEM;
741 }
742 wlist = *list;
743
744 /* insert the widget */
745 dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n",
746 w->name, wlist->num_widgets);
747
748 wlist->widgets[wlist->num_widgets] = w;
749 wlist->num_widgets++;
750 return 1;
751}
752
Richard Purdie2b97eab2006-10-06 18:32:18 +0200753/*
754 * Recursively check for a completed path to an active or physically connected
755 * output widget. Returns number of complete paths.
756 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100757static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
758 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200759{
760 struct snd_soc_dapm_path *path;
761 int con = 0;
762
Mark Brown024dc072011-10-09 11:52:05 +0100763 if (widget->outputs >= 0)
764 return widget->outputs;
765
Mark Brownde02d072011-09-20 21:43:24 +0100766 DAPM_UPDATE_STAT(widget, path_checks);
767
Mark Brown62ea8742012-01-21 21:14:48 +0000768 switch (widget->id) {
769 case snd_soc_dapm_supply:
770 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +0200771 case snd_soc_dapm_clock_supply:
Mark Brown246d0a12009-04-22 18:24:55 +0100772 return 0;
Mark Brown62ea8742012-01-21 21:14:48 +0000773 default:
774 break;
775 }
Mark Brown246d0a12009-04-22 18:24:55 +0100776
Mark Brown010ff262009-08-17 17:39:22 +0100777 switch (widget->id) {
778 case snd_soc_dapm_adc:
779 case snd_soc_dapm_aif_out:
Mark Brown888df392012-02-16 19:37:51 -0800780 case snd_soc_dapm_dai:
Mark Brown024dc072011-10-09 11:52:05 +0100781 if (widget->active) {
782 widget->outputs = snd_soc_dapm_suspend_check(widget);
783 return widget->outputs;
784 }
Mark Brown010ff262009-08-17 17:39:22 +0100785 default:
786 break;
787 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200788
789 if (widget->connected) {
790 /* connected pin ? */
Mark Brown024dc072011-10-09 11:52:05 +0100791 if (widget->id == snd_soc_dapm_output && !widget->ext) {
792 widget->outputs = snd_soc_dapm_suspend_check(widget);
793 return widget->outputs;
794 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200795
796 /* connected jack or spk ? */
Mark Brown024dc072011-10-09 11:52:05 +0100797 if (widget->id == snd_soc_dapm_hp ||
798 widget->id == snd_soc_dapm_spk ||
799 (widget->id == snd_soc_dapm_line &&
800 !list_empty(&widget->sources))) {
801 widget->outputs = snd_soc_dapm_suspend_check(widget);
802 return widget->outputs;
803 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200804 }
805
806 list_for_each_entry(path, &widget->sinks, list_source) {
Mark Browne56235e2011-09-21 18:19:14 +0100807 DAPM_UPDATE_STAT(widget, neighbour_checks);
808
Mark Brownbf3a9e12011-06-13 16:42:29 +0100809 if (path->weak)
810 continue;
811
Richard Purdie2b97eab2006-10-06 18:32:18 +0200812 if (path->walked)
813 continue;
814
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100815 trace_snd_soc_dapm_output_path(widget, path);
816
Richard Purdie2b97eab2006-10-06 18:32:18 +0200817 if (path->sink && path->connect) {
818 path->walked = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100819
820 /* do we need to add this widget to the list ? */
821 if (list) {
822 int err;
823 err = dapm_list_add_widget(list, path->sink);
824 if (err < 0) {
825 dev_err(widget->dapm->dev, "could not add widget %s\n",
826 widget->name);
827 return con;
828 }
829 }
830
831 con += is_connected_output_ep(path->sink, list);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200832 }
833 }
834
Mark Brown024dc072011-10-09 11:52:05 +0100835 widget->outputs = con;
836
Richard Purdie2b97eab2006-10-06 18:32:18 +0200837 return con;
838}
839
840/*
841 * Recursively check for a completed path to an active or physically connected
842 * input widget. Returns number of complete paths.
843 */
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100844static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
845 struct snd_soc_dapm_widget_list **list)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200846{
847 struct snd_soc_dapm_path *path;
848 int con = 0;
849
Mark Brown024dc072011-10-09 11:52:05 +0100850 if (widget->inputs >= 0)
851 return widget->inputs;
852
Mark Brownde02d072011-09-20 21:43:24 +0100853 DAPM_UPDATE_STAT(widget, path_checks);
854
Mark Brown62ea8742012-01-21 21:14:48 +0000855 switch (widget->id) {
856 case snd_soc_dapm_supply:
857 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +0200858 case snd_soc_dapm_clock_supply:
Mark Brown246d0a12009-04-22 18:24:55 +0100859 return 0;
Mark Brown62ea8742012-01-21 21:14:48 +0000860 default:
861 break;
862 }
Mark Brown246d0a12009-04-22 18:24:55 +0100863
Richard Purdie2b97eab2006-10-06 18:32:18 +0200864 /* active stream ? */
Mark Brown010ff262009-08-17 17:39:22 +0100865 switch (widget->id) {
866 case snd_soc_dapm_dac:
867 case snd_soc_dapm_aif_in:
Mark Brown888df392012-02-16 19:37:51 -0800868 case snd_soc_dapm_dai:
Mark Brown024dc072011-10-09 11:52:05 +0100869 if (widget->active) {
870 widget->inputs = snd_soc_dapm_suspend_check(widget);
871 return widget->inputs;
872 }
Mark Brown010ff262009-08-17 17:39:22 +0100873 default:
874 break;
875 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200876
877 if (widget->connected) {
878 /* connected pin ? */
Mark Brown024dc072011-10-09 11:52:05 +0100879 if (widget->id == snd_soc_dapm_input && !widget->ext) {
880 widget->inputs = snd_soc_dapm_suspend_check(widget);
881 return widget->inputs;
882 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200883
884 /* connected VMID/Bias for lower pops */
Mark Brown024dc072011-10-09 11:52:05 +0100885 if (widget->id == snd_soc_dapm_vmid) {
886 widget->inputs = snd_soc_dapm_suspend_check(widget);
887 return widget->inputs;
888 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200889
890 /* connected jack ? */
Peter Ujfalusieaeae5d2009-09-30 09:27:24 +0300891 if (widget->id == snd_soc_dapm_mic ||
Mark Brown024dc072011-10-09 11:52:05 +0100892 (widget->id == snd_soc_dapm_line &&
893 !list_empty(&widget->sinks))) {
894 widget->inputs = snd_soc_dapm_suspend_check(widget);
895 return widget->inputs;
896 }
897
Mark Brown1ab97c82011-11-27 16:21:51 +0000898 /* signal generator */
899 if (widget->id == snd_soc_dapm_siggen) {
900 widget->inputs = snd_soc_dapm_suspend_check(widget);
901 return widget->inputs;
902 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200903 }
904
905 list_for_each_entry(path, &widget->sources, list_sink) {
Mark Browne56235e2011-09-21 18:19:14 +0100906 DAPM_UPDATE_STAT(widget, neighbour_checks);
907
Mark Brownbf3a9e12011-06-13 16:42:29 +0100908 if (path->weak)
909 continue;
910
Richard Purdie2b97eab2006-10-06 18:32:18 +0200911 if (path->walked)
912 continue;
913
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100914 trace_snd_soc_dapm_input_path(widget, path);
915
Richard Purdie2b97eab2006-10-06 18:32:18 +0200916 if (path->source && path->connect) {
917 path->walked = 1;
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100918
919 /* do we need to add this widget to the list ? */
920 if (list) {
921 int err;
922 err = dapm_list_add_widget(list, path->sink);
923 if (err < 0) {
924 dev_err(widget->dapm->dev, "could not add widget %s\n",
925 widget->name);
926 return con;
927 }
928 }
929
930 con += is_connected_input_ep(path->source, list);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200931 }
932 }
933
Mark Brown024dc072011-10-09 11:52:05 +0100934 widget->inputs = con;
935
Richard Purdie2b97eab2006-10-06 18:32:18 +0200936 return con;
937}
938
Liam Girdwoodec2e3032012-04-18 11:41:11 +0100939/**
940 * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
941 * @dai: the soc DAI.
942 * @stream: stream direction.
943 * @list: list of active widgets for this stream.
944 *
945 * Queries DAPM graph as to whether an valid audio stream path exists for
946 * the initial stream specified by name. This takes into account
947 * current mixer and mux kcontrol settings. Creates list of valid widgets.
948 *
949 * Returns the number of valid paths or negative error.
950 */
951int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
952 struct snd_soc_dapm_widget_list **list)
953{
954 struct snd_soc_card *card = dai->card;
955 int paths;
956
957 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
958 dapm_reset(card);
959
960 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
961 paths = is_connected_output_ep(dai->playback_widget, list);
962 else
963 paths = is_connected_input_ep(dai->playback_widget, list);
964
965 trace_snd_soc_dapm_connected(paths, stream);
966 dapm_clear_walk(&card->dapm);
967 mutex_unlock(&card->dapm_mutex);
968
969 return paths;
970}
971
Richard Purdie2b97eab2006-10-06 18:32:18 +0200972/*
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300973 * Handler for generic register modifier widget.
974 */
975int dapm_reg_event(struct snd_soc_dapm_widget *w,
976 struct snd_kcontrol *kcontrol, int event)
977{
978 unsigned int val;
979
980 if (SND_SOC_DAPM_EVENT_ON(event))
981 val = w->on_val;
982 else
983 val = w->off_val;
984
Liam Girdwood49575fb52012-03-06 18:16:19 +0000985 soc_widget_update_bits_locked(w, -(w->reg + 1),
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300986 w->mask << w->shift, val << w->shift);
987
988 return 0;
989}
Mark Brown11589412008-07-29 11:42:23 +0100990EXPORT_SYMBOL_GPL(dapm_reg_event);
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300991
Mark Brown62ea8742012-01-21 21:14:48 +0000992/*
993 * Handler for regulator supply widget.
994 */
995int dapm_regulator_event(struct snd_soc_dapm_widget *w,
996 struct snd_kcontrol *kcontrol, int event)
997{
998 if (SND_SOC_DAPM_EVENT_ON(event))
Liam Girdwooda3cc0562012-03-09 17:20:16 +0000999 return regulator_enable(w->regulator);
Mark Brown62ea8742012-01-21 21:14:48 +00001000 else
Liam Girdwooda3cc0562012-03-09 17:20:16 +00001001 return regulator_disable_deferred(w->regulator, w->shift);
Mark Brown62ea8742012-01-21 21:14:48 +00001002}
1003EXPORT_SYMBOL_GPL(dapm_regulator_event);
1004
Ola Liljad7e7eb92012-05-24 15:26:25 +02001005/*
1006 * Handler for clock supply widget.
1007 */
1008int dapm_clock_event(struct snd_soc_dapm_widget *w,
1009 struct snd_kcontrol *kcontrol, int event)
1010{
1011 if (!w->clk)
1012 return -EIO;
1013
1014 if (SND_SOC_DAPM_EVENT_ON(event)) {
1015 return clk_enable(w->clk);
1016 } else {
1017 clk_disable(w->clk);
1018 return 0;
1019 }
1020}
1021EXPORT_SYMBOL_GPL(dapm_clock_event);
1022
Mark Brownd8050022011-09-28 18:28:23 +01001023static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
1024{
Mark Brown9b8a83b2011-10-04 22:15:59 +01001025 if (w->power_checked)
1026 return w->new_power;
1027
Mark Brownd8050022011-09-28 18:28:23 +01001028 if (w->force)
Mark Brown9b8a83b2011-10-04 22:15:59 +01001029 w->new_power = 1;
Mark Brownd8050022011-09-28 18:28:23 +01001030 else
Mark Brown9b8a83b2011-10-04 22:15:59 +01001031 w->new_power = w->power_check(w);
1032
1033 w->power_checked = true;
1034
1035 return w->new_power;
Mark Brownd8050022011-09-28 18:28:23 +01001036}
1037
Mark Browncd0f2d42009-04-20 16:56:59 +01001038/* Generic check to see if a widget should be powered.
1039 */
1040static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
1041{
1042 int in, out;
1043
Mark Brownde02d072011-09-20 21:43:24 +01001044 DAPM_UPDATE_STAT(w, power_checks);
1045
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001046 in = is_connected_input_ep(w, NULL);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001047 dapm_clear_walk(w->dapm);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001048 out = is_connected_output_ep(w, NULL);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001049 dapm_clear_walk(w->dapm);
Mark Browncd0f2d42009-04-20 16:56:59 +01001050 return out != 0 && in != 0;
1051}
1052
Mark Brown888df392012-02-16 19:37:51 -08001053static int dapm_dai_check_power(struct snd_soc_dapm_widget *w)
1054{
1055 DAPM_UPDATE_STAT(w, power_checks);
1056
Mark Brown1eee1b32012-04-10 13:57:46 +01001057 if (w->active)
1058 return w->active;
1059
1060 return dapm_generic_check_power(w);
Mark Brown888df392012-02-16 19:37:51 -08001061}
1062
Mark Brown6ea31b92009-04-20 17:15:41 +01001063/* Check to see if an ADC has power */
1064static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
1065{
1066 int in;
1067
Mark Brownde02d072011-09-20 21:43:24 +01001068 DAPM_UPDATE_STAT(w, power_checks);
1069
Mark Brown6ea31b92009-04-20 17:15:41 +01001070 if (w->active) {
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001071 in = is_connected_input_ep(w, NULL);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001072 dapm_clear_walk(w->dapm);
Mark Brown6ea31b92009-04-20 17:15:41 +01001073 return in != 0;
1074 } else {
1075 return dapm_generic_check_power(w);
1076 }
1077}
1078
1079/* Check to see if a DAC has power */
1080static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
1081{
1082 int out;
1083
Mark Brownde02d072011-09-20 21:43:24 +01001084 DAPM_UPDATE_STAT(w, power_checks);
1085
Mark Brown6ea31b92009-04-20 17:15:41 +01001086 if (w->active) {
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001087 out = is_connected_output_ep(w, NULL);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001088 dapm_clear_walk(w->dapm);
Mark Brown6ea31b92009-04-20 17:15:41 +01001089 return out != 0;
1090 } else {
1091 return dapm_generic_check_power(w);
1092 }
1093}
1094
Mark Brown246d0a12009-04-22 18:24:55 +01001095/* Check to see if a power supply is needed */
1096static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
1097{
1098 struct snd_soc_dapm_path *path;
Mark Brown246d0a12009-04-22 18:24:55 +01001099
Mark Brownde02d072011-09-20 21:43:24 +01001100 DAPM_UPDATE_STAT(w, power_checks);
1101
Mark Brown246d0a12009-04-22 18:24:55 +01001102 /* Check if one of our outputs is connected */
1103 list_for_each_entry(path, &w->sinks, list_source) {
Mark Browna8fdac82011-09-28 18:20:26 +01001104 DAPM_UPDATE_STAT(w, neighbour_checks);
1105
Mark Brownbf3a9e12011-06-13 16:42:29 +01001106 if (path->weak)
1107 continue;
1108
Mark Brown215edda2009-09-08 18:59:05 +01001109 if (path->connected &&
1110 !path->connected(path->source, path->sink))
1111 continue;
1112
Mark Brown30173582011-02-11 11:42:19 +00001113 if (!path->sink)
1114 continue;
1115
Mark Brownf68d7e12011-10-04 22:57:50 +01001116 if (dapm_widget_power_check(path->sink))
1117 return 1;
Mark Brown246d0a12009-04-22 18:24:55 +01001118 }
1119
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001120 dapm_clear_walk(w->dapm);
Mark Brown246d0a12009-04-22 18:24:55 +01001121
Mark Brownf68d7e12011-10-04 22:57:50 +01001122 return 0;
Mark Brown246d0a12009-04-22 18:24:55 +01001123}
1124
Mark Brown35c64bca2011-09-28 18:23:53 +01001125static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w)
1126{
1127 return 1;
1128}
1129
Mark Brown38357ab2009-06-06 19:03:23 +01001130static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1131 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001132 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001133{
Mark Brown828a8422011-01-15 13:14:30 +00001134 int *sort;
1135
1136 if (power_up)
1137 sort = dapm_up_seq;
1138 else
1139 sort = dapm_down_seq;
1140
Mark Brown38357ab2009-06-06 19:03:23 +01001141 if (sort[a->id] != sort[b->id])
1142 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001143 if (a->subseq != b->subseq) {
1144 if (power_up)
1145 return a->subseq - b->subseq;
1146 else
1147 return b->subseq - a->subseq;
1148 }
Mark Brownb22ead22009-06-07 12:51:26 +01001149 if (a->reg != b->reg)
1150 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001151 if (a->dapm != b->dapm)
1152 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001153
Mark Brown38357ab2009-06-06 19:03:23 +01001154 return 0;
1155}
Mark Brown42aa3412009-03-01 19:21:10 +00001156
Mark Brown38357ab2009-06-06 19:03:23 +01001157/* Insert a widget in order into a DAPM power sequence. */
1158static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1159 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001160 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001161{
1162 struct snd_soc_dapm_widget *w;
1163
1164 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001165 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001166 list_add_tail(&new_widget->power_list, &w->power_list);
1167 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001168 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001169
Mark Brown38357ab2009-06-06 19:03:23 +01001170 list_add_tail(&new_widget->power_list, list);
1171}
Mark Brown42aa3412009-03-01 19:21:10 +00001172
Mark Brown68f89ad2010-11-03 23:51:49 -04001173static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
1174 struct snd_soc_dapm_widget *w, int event)
1175{
1176 struct snd_soc_card *card = dapm->card;
1177 const char *ev_name;
1178 int power, ret;
1179
1180 switch (event) {
1181 case SND_SOC_DAPM_PRE_PMU:
1182 ev_name = "PRE_PMU";
1183 power = 1;
1184 break;
1185 case SND_SOC_DAPM_POST_PMU:
1186 ev_name = "POST_PMU";
1187 power = 1;
1188 break;
1189 case SND_SOC_DAPM_PRE_PMD:
1190 ev_name = "PRE_PMD";
1191 power = 0;
1192 break;
1193 case SND_SOC_DAPM_POST_PMD:
1194 ev_name = "POST_PMD";
1195 power = 0;
1196 break;
1197 default:
1198 BUG();
1199 return;
1200 }
1201
1202 if (w->power != power)
1203 return;
1204
1205 if (w->event && (w->event_flags & event)) {
1206 pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
1207 w->name, ev_name);
Mark Brown84e90932010-11-04 00:07:02 -04001208 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001209 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001210 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001211 if (ret < 0)
1212 pr_err("%s: %s event failed: %d\n",
1213 ev_name, w->name, ret);
1214 }
1215}
1216
Mark Brownb22ead22009-06-07 12:51:26 +01001217/* Apply the coalesced changes from a DAPM sequence */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001218static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
Mark Brownb22ead22009-06-07 12:51:26 +01001219 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001220{
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001221 struct snd_soc_card *card = dapm->card;
Mark Brown68f89ad2010-11-03 23:51:49 -04001222 struct snd_soc_dapm_widget *w;
1223 int reg, power;
Mark Brownb22ead22009-06-07 12:51:26 +01001224 unsigned int value = 0;
1225 unsigned int mask = 0;
1226 unsigned int cur_mask;
1227
1228 reg = list_first_entry(pending, struct snd_soc_dapm_widget,
1229 power_list)->reg;
1230
1231 list_for_each_entry(w, pending, power_list) {
1232 cur_mask = 1 << w->shift;
1233 BUG_ON(reg != w->reg);
1234
1235 if (w->invert)
1236 power = !w->power;
1237 else
1238 power = w->power;
1239
1240 mask |= cur_mask;
1241 if (power)
1242 value |= cur_mask;
1243
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001244 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001245 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1246 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001247
Mark Brown68f89ad2010-11-03 23:51:49 -04001248 /* Check for events */
1249 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
1250 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001251 }
1252
Mark Brown81628102009-06-07 13:21:24 +01001253 if (reg >= 0) {
Mark Brown29376bc2011-06-19 13:49:28 +01001254 /* Any widget will do, they should all be updating the
1255 * same register.
1256 */
1257 w = list_first_entry(pending, struct snd_soc_dapm_widget,
1258 power_list);
1259
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001260 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001261 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001262 value, mask, reg, card->pop_time);
1263 pop_wait(card->pop_time);
Liam Girdwood49575fb52012-03-06 18:16:19 +00001264 soc_widget_update_bits_locked(w, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001265 }
1266
1267 list_for_each_entry(w, pending, power_list) {
Mark Brown68f89ad2010-11-03 23:51:49 -04001268 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
1269 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001270 }
Mark Brown42aa3412009-03-01 19:21:10 +00001271}
1272
Mark Brownb22ead22009-06-07 12:51:26 +01001273/* Apply a DAPM power sequence.
1274 *
1275 * We walk over a pre-sorted list of widgets to apply power to. In
1276 * order to minimise the number of writes to the device required
1277 * multiple widgets will be updated in a single write where possible.
1278 * Currently anything that requires more than a single write is not
1279 * handled.
1280 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001281static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
Mark Brown828a8422011-01-15 13:14:30 +00001282 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001283{
1284 struct snd_soc_dapm_widget *w, *n;
1285 LIST_HEAD(pending);
1286 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001287 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001288 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001289 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001290 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001291 int *sort;
1292
1293 if (power_up)
1294 sort = dapm_up_seq;
1295 else
1296 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001297
Mark Brownb22ead22009-06-07 12:51:26 +01001298 list_for_each_entry_safe(w, n, list, power_list) {
1299 ret = 0;
1300
1301 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001302 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001303 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001304 if (!list_empty(&pending))
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001305 dapm_seq_run_coalesced(cur_dapm, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001306
Mark Brown474b62d2011-01-18 16:14:44 +00001307 if (cur_dapm && cur_dapm->seq_notifier) {
1308 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1309 if (sort[i] == cur_sort)
1310 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001311 i,
1312 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001313 }
1314
Mark Brownb22ead22009-06-07 12:51:26 +01001315 INIT_LIST_HEAD(&pending);
1316 cur_sort = -1;
Mark Brownb0b3e6f2011-07-16 10:55:08 +09001317 cur_subseq = INT_MIN;
Mark Brownb22ead22009-06-07 12:51:26 +01001318 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001319 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001320 }
1321
Mark Brown163cac02009-06-07 10:12:52 +01001322 switch (w->id) {
1323 case snd_soc_dapm_pre:
1324 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001325 list_for_each_entry_safe_continue(w, n, list,
1326 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001327
Mark Brownb22ead22009-06-07 12:51:26 +01001328 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001329 ret = w->event(w,
1330 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001331 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001332 ret = w->event(w,
1333 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001334 break;
1335
1336 case snd_soc_dapm_post:
1337 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001338 list_for_each_entry_safe_continue(w, n, list,
1339 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001340
Mark Brownb22ead22009-06-07 12:51:26 +01001341 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001342 ret = w->event(w,
1343 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001344 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001345 ret = w->event(w,
1346 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001347 break;
1348
Mark Brown163cac02009-06-07 10:12:52 +01001349 default:
Mark Brown81628102009-06-07 13:21:24 +01001350 /* Queue it up for application */
1351 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001352 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001353 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001354 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001355 list_move(&w->power_list, &pending);
1356 break;
Mark Brown163cac02009-06-07 10:12:52 +01001357 }
Mark Brownb22ead22009-06-07 12:51:26 +01001358
1359 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001360 dev_err(w->dapm->dev,
1361 "Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001362 }
Mark Brownb22ead22009-06-07 12:51:26 +01001363
1364 if (!list_empty(&pending))
Mark Brown28e86802011-03-08 19:29:53 +00001365 dapm_seq_run_coalesced(cur_dapm, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001366
1367 if (cur_dapm && cur_dapm->seq_notifier) {
1368 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1369 if (sort[i] == cur_sort)
1370 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001371 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001372 }
Mark Brown163cac02009-06-07 10:12:52 +01001373}
1374
Mark Brown97404f22010-12-14 16:13:57 +00001375static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
1376{
1377 struct snd_soc_dapm_update *update = dapm->update;
1378 struct snd_soc_dapm_widget *w;
1379 int ret;
1380
1381 if (!update)
1382 return;
1383
1384 w = update->widget;
1385
1386 if (w->event &&
1387 (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1388 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1389 if (ret != 0)
1390 pr_err("%s DAPM pre-event failed: %d\n",
1391 w->name, ret);
1392 }
1393
Liam Girdwood49575fb52012-03-06 18:16:19 +00001394 ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
Mark Brown97404f22010-12-14 16:13:57 +00001395 update->val);
1396 if (ret < 0)
1397 pr_err("%s DAPM update failed: %d\n", w->name, ret);
1398
1399 if (w->event &&
1400 (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1401 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1402 if (ret != 0)
1403 pr_err("%s DAPM post-event failed: %d\n",
1404 w->name, ret);
1405 }
1406}
1407
Mark Brown9d0624a2011-02-18 11:49:43 -08001408/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1409 * they're changing state.
1410 */
1411static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1412{
1413 struct snd_soc_dapm_context *d = data;
1414 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001415
Mark Brown56fba412011-06-04 11:25:10 +01001416 /* If we're off and we're not supposed to be go into STANDBY */
1417 if (d->bias_level == SND_SOC_BIAS_OFF &&
1418 d->target_bias_level != SND_SOC_BIAS_OFF) {
Mark Brownf1aac482011-12-05 15:17:06 +00001419 if (d->dev)
1420 pm_runtime_get_sync(d->dev);
1421
Mark Brown9d0624a2011-02-18 11:49:43 -08001422 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1423 if (ret != 0)
1424 dev_err(d->dev,
1425 "Failed to turn on bias: %d\n", ret);
1426 }
1427
Mark Brown56fba412011-06-04 11:25:10 +01001428 /* Prepare for a STADDBY->ON or ON->STANDBY transition */
1429 if (d->bias_level != d->target_bias_level) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001430 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1431 if (ret != 0)
1432 dev_err(d->dev,
1433 "Failed to prepare bias: %d\n", ret);
1434 }
1435}
1436
1437/* Async callback run prior to DAPM sequences - brings to their final
1438 * state.
1439 */
1440static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1441{
1442 struct snd_soc_dapm_context *d = data;
1443 int ret;
1444
1445 /* If we just powered the last thing off drop to standby bias */
Mark Brown56fba412011-06-04 11:25:10 +01001446 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1447 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1448 d->target_bias_level == SND_SOC_BIAS_OFF)) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001449 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1450 if (ret != 0)
1451 dev_err(d->dev, "Failed to apply standby bias: %d\n",
1452 ret);
1453 }
1454
1455 /* If we're in standby and can support bias off then do that */
Mark Brown56fba412011-06-04 11:25:10 +01001456 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1457 d->target_bias_level == SND_SOC_BIAS_OFF) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001458 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1459 if (ret != 0)
1460 dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
Mark Brownf1aac482011-12-05 15:17:06 +00001461
1462 if (d->dev)
Mark Brownfb644e92012-01-25 19:53:58 +00001463 pm_runtime_put(d->dev);
Mark Brown9d0624a2011-02-18 11:49:43 -08001464 }
1465
1466 /* If we just powered up then move to active bias */
Mark Brown56fba412011-06-04 11:25:10 +01001467 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1468 d->target_bias_level == SND_SOC_BIAS_ON) {
Mark Brown9d0624a2011-02-18 11:49:43 -08001469 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1470 if (ret != 0)
1471 dev_err(d->dev, "Failed to apply active bias: %d\n",
1472 ret);
1473 }
1474}
Mark Brown97404f22010-12-14 16:13:57 +00001475
Mark Brownfe4fda52011-10-03 22:36:57 +01001476static void dapm_widget_set_peer_power(struct snd_soc_dapm_widget *peer,
1477 bool power, bool connect)
1478{
1479 /* If a connection is being made or broken then that update
1480 * will have marked the peer dirty, otherwise the widgets are
1481 * not connected and this update has no impact. */
1482 if (!connect)
1483 return;
1484
1485 /* If the peer is already in the state we're moving to then we
1486 * won't have an impact on it. */
1487 if (power != peer->power)
Mark Brown75c1f892011-10-04 22:28:08 +01001488 dapm_mark_dirty(peer, "peer state change");
Mark Brownfe4fda52011-10-03 22:36:57 +01001489}
1490
Mark Brown05623c42011-09-28 17:02:31 +01001491static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
1492 struct list_head *up_list,
1493 struct list_head *down_list)
1494{
Mark Browndb432b42011-10-03 21:06:40 +01001495 struct snd_soc_dapm_path *path;
1496
Mark Brown05623c42011-09-28 17:02:31 +01001497 if (w->power == power)
1498 return;
1499
1500 trace_snd_soc_dapm_widget_power(w, power);
1501
Mark Browndb432b42011-10-03 21:06:40 +01001502 /* If we changed our power state perhaps our neigbours changed
Mark Brownfe4fda52011-10-03 22:36:57 +01001503 * also.
Mark Browndb432b42011-10-03 21:06:40 +01001504 */
1505 list_for_each_entry(path, &w->sources, list_sink) {
1506 if (path->source) {
Mark Brownfe4fda52011-10-03 22:36:57 +01001507 dapm_widget_set_peer_power(path->source, power,
1508 path->connect);
Mark Browndb432b42011-10-03 21:06:40 +01001509 }
1510 }
Mark Brownf3bf3e42011-10-04 22:43:31 +01001511 switch (w->id) {
1512 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001513 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001514 case snd_soc_dapm_clock_supply:
Mark Brownf3bf3e42011-10-04 22:43:31 +01001515 /* Supplies can't affect their outputs, only their inputs */
1516 break;
1517 default:
1518 list_for_each_entry(path, &w->sinks, list_source) {
1519 if (path->sink) {
1520 dapm_widget_set_peer_power(path->sink, power,
1521 path->connect);
1522 }
Mark Browndb432b42011-10-03 21:06:40 +01001523 }
Mark Brownf3bf3e42011-10-04 22:43:31 +01001524 break;
Mark Browndb432b42011-10-03 21:06:40 +01001525 }
1526
Mark Brown05623c42011-09-28 17:02:31 +01001527 if (power)
1528 dapm_seq_insert(w, up_list, true);
1529 else
1530 dapm_seq_insert(w, down_list, false);
1531
1532 w->power = power;
1533}
1534
Mark Brown7c81beb2011-09-20 22:22:32 +01001535static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
1536 struct list_head *up_list,
1537 struct list_head *down_list)
1538{
Mark Brown7c81beb2011-09-20 22:22:32 +01001539 int power;
1540
1541 switch (w->id) {
1542 case snd_soc_dapm_pre:
1543 dapm_seq_insert(w, down_list, false);
1544 break;
1545 case snd_soc_dapm_post:
1546 dapm_seq_insert(w, up_list, true);
1547 break;
1548
1549 default:
Mark Brownd8050022011-09-28 18:28:23 +01001550 power = dapm_widget_power_check(w);
Mark Brown7c81beb2011-09-20 22:22:32 +01001551
Mark Brown05623c42011-09-28 17:02:31 +01001552 dapm_widget_set_power(w, power, up_list, down_list);
Mark Brown7c81beb2011-09-20 22:22:32 +01001553 break;
1554 }
1555}
1556
Mark Brown42aa3412009-03-01 19:21:10 +00001557/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001558 * Scan each dapm widget for complete audio path.
1559 * A complete path is a route that has valid endpoints i.e.:-
1560 *
1561 * o DAC to output pin.
1562 * o Input Pin to ADC.
1563 * o Input pin to Output pin (bypass, sidetone)
1564 * o DAC to ADC (loopback).
1565 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001566static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001567{
Mark Brown12ea2c72011-03-02 18:17:32 +00001568 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001569 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001570 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001571 LIST_HEAD(up_list);
1572 LIST_HEAD(down_list);
Mark Brown9d0624a2011-02-18 11:49:43 -08001573 LIST_HEAD(async_domain);
Mark Brown56fba412011-06-04 11:25:10 +01001574 enum snd_soc_bias_level bias;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001575
Mark Brown84e90932010-11-04 00:07:02 -04001576 trace_snd_soc_dapm_start(card);
1577
Mark Brown56fba412011-06-04 11:25:10 +01001578 list_for_each_entry(d, &card->dapm_list, list) {
Mark Brown497098b2012-03-08 15:06:09 +00001579 if (d->idle_bias_off)
1580 d->target_bias_level = SND_SOC_BIAS_OFF;
1581 else
1582 d->target_bias_level = SND_SOC_BIAS_STANDBY;
Mark Brown56fba412011-06-04 11:25:10 +01001583 }
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001584
Liam Girdwood6c120e12012-02-15 15:15:34 +00001585 dapm_reset(card);
Mark Brown9b8a83b2011-10-04 22:15:59 +01001586
Mark Brown6d3ddc82009-05-16 17:47:29 +01001587 /* Check which widgets we need to power and store them in
Mark Browndb432b42011-10-03 21:06:40 +01001588 * lists indicating if they should be powered up or down. We
1589 * only check widgets that have been flagged as dirty but note
1590 * that new widgets may be added to the dirty list while we
1591 * iterate.
Mark Brown6d3ddc82009-05-16 17:47:29 +01001592 */
Mark Browndb432b42011-10-03 21:06:40 +01001593 list_for_each_entry(w, &card->dapm_dirty, dirty) {
Mark Brown7c81beb2011-09-20 22:22:32 +01001594 dapm_power_one_widget(w, &up_list, &down_list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001595 }
1596
Mark Brownf9de6d72011-09-28 17:19:47 +01001597 list_for_each_entry(w, &card->widgets, list) {
Mark Browndb432b42011-10-03 21:06:40 +01001598 list_del_init(&w->dirty);
1599
Mark Brownf9de6d72011-09-28 17:19:47 +01001600 if (w->power) {
1601 d = w->dapm;
1602
1603 /* Supplies and micbiases only bring the
1604 * context up to STANDBY as unless something
1605 * else is active and passing audio they
Mark Brownafe62362012-01-25 19:55:22 +00001606 * generally don't require full power. Signal
1607 * generators are virtual pins and have no
1608 * power impact themselves.
Mark Brownf9de6d72011-09-28 17:19:47 +01001609 */
1610 switch (w->id) {
Mark Brownafe62362012-01-25 19:55:22 +00001611 case snd_soc_dapm_siggen:
1612 break;
Mark Brownf9de6d72011-09-28 17:19:47 +01001613 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001614 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001615 case snd_soc_dapm_clock_supply:
Mark Brownf9de6d72011-09-28 17:19:47 +01001616 case snd_soc_dapm_micbias:
1617 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1618 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1619 break;
1620 default:
1621 d->target_bias_level = SND_SOC_BIAS_ON;
1622 break;
1623 }
1624 }
1625
1626 }
1627
Mark Brown85a843c2011-09-21 21:29:47 +01001628 /* Force all contexts in the card to the same bias state if
1629 * they're not ground referenced.
1630 */
Mark Brown56fba412011-06-04 11:25:10 +01001631 bias = SND_SOC_BIAS_OFF;
Mark Brown52ba67b2011-04-04 21:05:11 +09001632 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown56fba412011-06-04 11:25:10 +01001633 if (d->target_bias_level > bias)
1634 bias = d->target_bias_level;
Mark Brown52ba67b2011-04-04 21:05:11 +09001635 list_for_each_entry(d, &card->dapm_list, list)
Mark Brown85a843c2011-09-21 21:29:47 +01001636 if (!d->idle_bias_off)
1637 d->target_bias_level = bias;
Mark Brown52ba67b2011-04-04 21:05:11 +09001638
Mark Brownde02d072011-09-20 21:43:24 +01001639 trace_snd_soc_dapm_walk_done(card);
Mark Brown52ba67b2011-04-04 21:05:11 +09001640
Mark Brown9d0624a2011-02-18 11:49:43 -08001641 /* Run all the bias changes in parallel */
1642 list_for_each_entry(d, &dapm->card->dapm_list, list)
1643 async_schedule_domain(dapm_pre_sequence_async, d,
1644 &async_domain);
1645 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001646
Mark Brown6d3ddc82009-05-16 17:47:29 +01001647 /* Power down widgets first; try to avoid amplifying pops. */
Mark Brown828a8422011-01-15 13:14:30 +00001648 dapm_seq_run(dapm, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001649
Mark Brown97404f22010-12-14 16:13:57 +00001650 dapm_widget_update(dapm);
1651
Mark Brown6d3ddc82009-05-16 17:47:29 +01001652 /* Now power up. */
Mark Brown828a8422011-01-15 13:14:30 +00001653 dapm_seq_run(dapm, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001654
Mark Brown9d0624a2011-02-18 11:49:43 -08001655 /* Run all the bias changes in parallel */
1656 list_for_each_entry(d, &dapm->card->dapm_list, list)
1657 async_schedule_domain(dapm_post_sequence_async, d,
1658 &async_domain);
1659 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001660
Liam Girdwood8078d872012-02-15 15:15:35 +00001661 /* do we need to notify any clients that DAPM event is complete */
1662 list_for_each_entry(d, &card->dapm_list, list) {
1663 if (d->stream_event)
1664 d->stream_event(d, event);
1665 }
1666
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001667 pop_dbg(dapm->dev, card->pop_time,
1668 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001669 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001670
Mark Brown84e90932010-11-04 00:07:02 -04001671 trace_snd_soc_dapm_done(card);
1672
Mark Brown42aa3412009-03-01 19:21:10 +00001673 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001674}
1675
Mark Brown79fb9382009-08-21 16:38:13 +01001676#ifdef CONFIG_DEBUG_FS
Mark Brown79fb9382009-08-21 16:38:13 +01001677static ssize_t dapm_widget_power_read_file(struct file *file,
1678 char __user *user_buf,
1679 size_t count, loff_t *ppos)
1680{
1681 struct snd_soc_dapm_widget *w = file->private_data;
1682 char *buf;
1683 int in, out;
1684 ssize_t ret;
1685 struct snd_soc_dapm_path *p = NULL;
1686
1687 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1688 if (!buf)
1689 return -ENOMEM;
1690
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001691 in = is_connected_input_ep(w, NULL);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001692 dapm_clear_walk(w->dapm);
Liam Girdwoodec2e3032012-04-18 11:41:11 +01001693 out = is_connected_output_ep(w, NULL);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001694 dapm_clear_walk(w->dapm);
Mark Brown79fb9382009-08-21 16:38:13 +01001695
Mark Brownf13ebad2012-03-03 18:01:01 +00001696 ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
1697 w->name, w->power ? "On" : "Off",
1698 w->force ? " (forced)" : "", in, out);
Mark Brown79fb9382009-08-21 16:38:13 +01001699
Mark Brownd033c362009-12-04 15:25:56 +00001700 if (w->reg >= 0)
1701 ret += snprintf(buf + ret, PAGE_SIZE - ret,
1702 " - R%d(0x%x) bit %d",
1703 w->reg, w->reg, w->shift);
1704
1705 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1706
Mark Brown3eef08b2009-09-14 16:49:00 +01001707 if (w->sname)
1708 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1709 w->sname,
1710 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001711
1712 list_for_each_entry(p, &w->sources, list_sink) {
Mark Brown215edda2009-09-08 18:59:05 +01001713 if (p->connected && !p->connected(w, p->sink))
1714 continue;
1715
Mark Brown79fb9382009-08-21 16:38:13 +01001716 if (p->connect)
1717 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001718 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001719 p->name ? p->name : "static",
1720 p->source->name);
1721 }
1722 list_for_each_entry(p, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001723 if (p->connected && !p->connected(w, p->sink))
1724 continue;
1725
Mark Brown79fb9382009-08-21 16:38:13 +01001726 if (p->connect)
1727 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001728 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001729 p->name ? p->name : "static",
1730 p->sink->name);
1731 }
1732
1733 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1734
1735 kfree(buf);
1736 return ret;
1737}
1738
1739static const struct file_operations dapm_widget_power_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001740 .open = simple_open,
Mark Brown79fb9382009-08-21 16:38:13 +01001741 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001742 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001743};
1744
Mark Brownef49e4f2011-04-04 20:48:13 +09001745static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1746 size_t count, loff_t *ppos)
1747{
1748 struct snd_soc_dapm_context *dapm = file->private_data;
1749 char *level;
1750
1751 switch (dapm->bias_level) {
1752 case SND_SOC_BIAS_ON:
1753 level = "On\n";
1754 break;
1755 case SND_SOC_BIAS_PREPARE:
1756 level = "Prepare\n";
1757 break;
1758 case SND_SOC_BIAS_STANDBY:
1759 level = "Standby\n";
1760 break;
1761 case SND_SOC_BIAS_OFF:
1762 level = "Off\n";
1763 break;
1764 default:
1765 BUG();
1766 level = "Unknown\n";
1767 break;
1768 }
1769
1770 return simple_read_from_buffer(user_buf, count, ppos, level,
1771 strlen(level));
1772}
1773
1774static const struct file_operations dapm_bias_fops = {
Stephen Boyd234e3402012-04-05 14:25:11 -07001775 .open = simple_open,
Mark Brownef49e4f2011-04-04 20:48:13 +09001776 .read = dapm_bias_read_file,
1777 .llseek = default_llseek,
1778};
1779
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001780void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1781 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001782{
Mark Brown79fb9382009-08-21 16:38:13 +01001783 struct dentry *d;
1784
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001785 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
1786
1787 if (!dapm->debugfs_dapm) {
Liam Girdwoodf1e90af2012-03-06 18:13:25 +00001788 dev_warn(dapm->dev,
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001789 "Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001790 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001791 }
Mark Brown79fb9382009-08-21 16:38:13 +01001792
Mark Brownef49e4f2011-04-04 20:48:13 +09001793 d = debugfs_create_file("bias_level", 0444,
1794 dapm->debugfs_dapm, dapm,
1795 &dapm_bias_fops);
1796 if (!d)
1797 dev_warn(dapm->dev,
1798 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001799}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001800
1801static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1802{
1803 struct snd_soc_dapm_context *dapm = w->dapm;
1804 struct dentry *d;
1805
1806 if (!dapm->debugfs_dapm || !w->name)
1807 return;
1808
1809 d = debugfs_create_file(w->name, 0444,
1810 dapm->debugfs_dapm, w,
1811 &dapm_widget_power_fops);
1812 if (!d)
1813 dev_warn(w->dapm->dev,
1814 "ASoC: Failed to create %s debugfs file\n",
1815 w->name);
1816}
1817
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001818static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1819{
1820 debugfs_remove_recursive(dapm->debugfs_dapm);
1821}
1822
Mark Brown79fb9382009-08-21 16:38:13 +01001823#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001824void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1825 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001826{
1827}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001828
1829static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1830{
1831}
1832
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001833static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1834{
1835}
1836
Mark Brown79fb9382009-08-21 16:38:13 +01001837#endif
1838
Richard Purdie2b97eab2006-10-06 18:32:18 +02001839/* test and update the power status of a mux widget */
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001840static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
Liam Girdwood40f02cd2012-02-06 16:05:14 +00001841 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001842{
1843 struct snd_soc_dapm_path *path;
1844 int found = 0;
1845
Peter Ujfalusieff317d2009-01-15 14:40:47 +02001846 if (widget->id != snd_soc_dapm_mux &&
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00001847 widget->id != snd_soc_dapm_virt_mux &&
Peter Ujfalusieff317d2009-01-15 14:40:47 +02001848 widget->id != snd_soc_dapm_value_mux)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001849 return -ENODEV;
1850
Richard Purdie2b97eab2006-10-06 18:32:18 +02001851 /* find dapm widget path assoc with kcontrol */
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001852 list_for_each_entry(path, &widget->dapm->card->paths, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001853 if (path->kcontrol != kcontrol)
1854 continue;
1855
Richard Zhaocb01e2b2008-10-07 08:05:20 +08001856 if (!path->name || !e->texts[mux])
Richard Purdie2b97eab2006-10-06 18:32:18 +02001857 continue;
1858
1859 found = 1;
1860 /* we now need to match the string in the enum to the path */
Mark Browndb432b42011-10-03 21:06:40 +01001861 if (!(strcmp(path->name, e->texts[mux]))) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001862 path->connect = 1; /* new connection */
Mark Brown75c1f892011-10-04 22:28:08 +01001863 dapm_mark_dirty(path->source, "mux connection");
Mark Browndb432b42011-10-03 21:06:40 +01001864 } else {
1865 if (path->connect)
Mark Brown75c1f892011-10-04 22:28:08 +01001866 dapm_mark_dirty(path->source,
1867 "mux disconnection");
Richard Purdie2b97eab2006-10-06 18:32:18 +02001868 path->connect = 0; /* old connection must be powered down */
Mark Browndb432b42011-10-03 21:06:40 +01001869 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001870 }
1871
Mark Browndb432b42011-10-03 21:06:40 +01001872 if (found) {
Mark Brown75c1f892011-10-04 22:28:08 +01001873 dapm_mark_dirty(widget, "mux change");
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001874 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
Mark Browndb432b42011-10-03 21:06:40 +01001875 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001876
Liam Girdwood618dae12012-04-25 12:12:51 +01001877 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001878}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001879
1880int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1881 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
1882{
1883 struct snd_soc_card *card = widget->dapm->card;
1884 int ret;
1885
Liam Girdwood3cd04342012-03-09 12:02:08 +00001886 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001887 ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
1888 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01001889 if (ret > 0)
1890 soc_dpcm_runtime_update(widget);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001891 return ret;
1892}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00001893EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001894
Milan plzik1b075e32008-01-10 14:39:46 +01001895/* test and update the power status of a mixer or switch widget */
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001896static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
Mark Brown283375c2009-12-07 18:09:03 +00001897 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001898{
1899 struct snd_soc_dapm_path *path;
1900 int found = 0;
1901
Milan plzik1b075e32008-01-10 14:39:46 +01001902 if (widget->id != snd_soc_dapm_mixer &&
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001903 widget->id != snd_soc_dapm_mixer_named_ctl &&
Milan plzik1b075e32008-01-10 14:39:46 +01001904 widget->id != snd_soc_dapm_switch)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001905 return -ENODEV;
1906
Richard Purdie2b97eab2006-10-06 18:32:18 +02001907 /* find dapm widget path assoc with kcontrol */
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001908 list_for_each_entry(path, &widget->dapm->card->paths, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001909 if (path->kcontrol != kcontrol)
1910 continue;
1911
1912 /* found, now check type */
1913 found = 1;
Mark Brown283375c2009-12-07 18:09:03 +00001914 path->connect = connect;
Mark Brown75c1f892011-10-04 22:28:08 +01001915 dapm_mark_dirty(path->source, "mixer connection");
Richard Purdie2b97eab2006-10-06 18:32:18 +02001916 }
1917
Mark Browndb432b42011-10-03 21:06:40 +01001918 if (found) {
Mark Brown75c1f892011-10-04 22:28:08 +01001919 dapm_mark_dirty(widget, "mixer update");
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001920 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
Mark Browndb432b42011-10-03 21:06:40 +01001921 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001922
Liam Girdwood618dae12012-04-25 12:12:51 +01001923 return found;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001924}
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001925
1926int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1927 struct snd_kcontrol *kcontrol, int connect)
1928{
1929 struct snd_soc_card *card = widget->dapm->card;
1930 int ret;
1931
Liam Girdwood3cd04342012-03-09 12:02:08 +00001932 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001933 ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
1934 mutex_unlock(&card->dapm_mutex);
Liam Girdwood618dae12012-04-25 12:12:51 +01001935 if (ret > 0)
1936 soc_dpcm_runtime_update(widget);
Liam Girdwood4edbb3452012-03-07 10:38:27 +00001937 return ret;
1938}
Liam Girdwood40f02cd2012-02-06 16:05:14 +00001939EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001940
1941/* show dapm widget status in sys fs */
1942static ssize_t dapm_widget_show(struct device *dev,
1943 struct device_attribute *attr, char *buf)
1944{
Mark Brown36ae1a92012-01-06 17:12:45 -08001945 struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00001946 struct snd_soc_codec *codec =rtd->codec;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001947 struct snd_soc_dapm_widget *w;
1948 int count = 0;
1949 char *state = "not set";
1950
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001951 list_for_each_entry(w, &codec->card->widgets, list) {
1952 if (w->dapm != &codec->dapm)
1953 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001954
1955 /* only display widgets that burnm power */
1956 switch (w->id) {
1957 case snd_soc_dapm_hp:
1958 case snd_soc_dapm_mic:
1959 case snd_soc_dapm_spk:
1960 case snd_soc_dapm_line:
1961 case snd_soc_dapm_micbias:
1962 case snd_soc_dapm_dac:
1963 case snd_soc_dapm_adc:
1964 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06001965 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001966 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001967 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01001968 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00001969 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02001970 case snd_soc_dapm_clock_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001971 if (w->name)
1972 count += sprintf(buf + count, "%s: %s\n",
1973 w->name, w->power ? "On":"Off");
1974 break;
1975 default:
1976 break;
1977 }
1978 }
1979
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001980 switch (codec->dapm.bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02001981 case SND_SOC_BIAS_ON:
1982 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001983 break;
Mark Brown0be98982008-05-19 12:31:28 +02001984 case SND_SOC_BIAS_PREPARE:
1985 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001986 break;
Mark Brown0be98982008-05-19 12:31:28 +02001987 case SND_SOC_BIAS_STANDBY:
1988 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001989 break;
Mark Brown0be98982008-05-19 12:31:28 +02001990 case SND_SOC_BIAS_OFF:
1991 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001992 break;
1993 }
1994 count += sprintf(buf + count, "PM State: %s\n", state);
1995
1996 return count;
1997}
1998
1999static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
2000
2001int snd_soc_dapm_sys_add(struct device *dev)
2002{
Troy Kisky12ef1932008-10-13 17:42:14 -07002003 return device_create_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002004}
2005
2006static void snd_soc_dapm_sys_remove(struct device *dev)
2007{
Mark Brownaef90842009-05-16 17:53:16 +01002008 device_remove_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002009}
2010
2011/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002012static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002013{
2014 struct snd_soc_dapm_widget *w, *next_w;
2015 struct snd_soc_dapm_path *p, *next_p;
2016
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002017 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
2018 if (w->dapm != dapm)
2019 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002020 list_del(&w->list);
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002021 /*
2022 * remove source and sink paths associated to this widget.
2023 * While removing the path, remove reference to it from both
2024 * source and sink widgets so that path is removed only once.
2025 */
2026 list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
2027 list_del(&p->list_sink);
2028 list_del(&p->list_source);
2029 list_del(&p->list);
2030 kfree(p->long_name);
2031 kfree(p);
2032 }
2033 list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
2034 list_del(&p->list_sink);
2035 list_del(&p->list_source);
2036 list_del(&p->list);
2037 kfree(p->long_name);
2038 kfree(p);
2039 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002040 kfree(w->kcontrols);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002041 kfree(w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002042 kfree(w);
2043 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002044}
2045
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002046static struct snd_soc_dapm_widget *dapm_find_widget(
2047 struct snd_soc_dapm_context *dapm, const char *pin,
2048 bool search_other_contexts)
2049{
2050 struct snd_soc_dapm_widget *w;
2051 struct snd_soc_dapm_widget *fallback = NULL;
2052
2053 list_for_each_entry(w, &dapm->card->widgets, list) {
2054 if (!strcmp(w->name, pin)) {
2055 if (w->dapm == dapm)
2056 return w;
2057 else
2058 fallback = w;
2059 }
2060 }
2061
2062 if (search_other_contexts)
2063 return fallback;
2064
2065 return NULL;
2066}
2067
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002068static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00002069 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01002070{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002071 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01002072
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002073 if (!w) {
2074 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
2075 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01002076 }
2077
Mark Brown1a8b2d92012-02-16 11:50:07 -08002078 if (w->connected != status)
2079 dapm_mark_dirty(w, "pin configuration");
2080
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002081 w->connected = status;
2082 if (status == 0)
2083 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09002084
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002085 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01002086}
2087
Richard Purdie2b97eab2006-10-06 18:32:18 +02002088/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002089 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002090 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002091 *
2092 * Walks all dapm audio paths and powers widgets according to their
2093 * stream or path usage.
2094 *
2095 * Returns 0 for success.
2096 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002097int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002098{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002099 int ret;
2100
Mark Brown4f4c0072011-10-07 14:29:19 +01002101 /*
2102 * Suppress early reports (eg, jacks syncing their state) to avoid
2103 * silly DAPM runs during card startup.
2104 */
2105 if (!dapm->card || !dapm->card->instantiated)
2106 return 0;
2107
Liam Girdwood3cd04342012-03-09 12:02:08 +00002108 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002109 ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
2110 mutex_unlock(&dapm->card->dapm_mutex);
2111 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002112}
Liam Girdwooda5302182008-07-07 13:35:17 +01002113EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002114
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002115static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Mark Brown215edda2009-09-08 18:59:05 +01002116 const struct snd_soc_dapm_route *route)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002117{
2118 struct snd_soc_dapm_path *path;
2119 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002120 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002121 const char *sink;
Mark Brown215edda2009-09-08 18:59:05 +01002122 const char *control = route->control;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002123 const char *source;
2124 char prefixed_sink[80];
2125 char prefixed_source[80];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002126 int ret = 0;
2127
Mark Brown88e8b9a2011-03-02 18:18:24 +00002128 if (dapm->codec && dapm->codec->name_prefix) {
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002129 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
2130 dapm->codec->name_prefix, route->sink);
2131 sink = prefixed_sink;
2132 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
2133 dapm->codec->name_prefix, route->source);
2134 source = prefixed_source;
2135 } else {
2136 sink = route->sink;
2137 source = route->source;
2138 }
2139
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002140 /*
2141 * find src and dest widgets over all widgets but favor a widget from
2142 * current DAPM context
2143 */
2144 list_for_each_entry(w, &dapm->card->widgets, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002145 if (!wsink && !(strcmp(w->name, sink))) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002146 wtsink = w;
2147 if (w->dapm == dapm)
2148 wsink = w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002149 continue;
2150 }
2151 if (!wsource && !(strcmp(w->name, source))) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002152 wtsource = w;
2153 if (w->dapm == dapm)
2154 wsource = w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002155 }
2156 }
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002157 /* use widget from another DAPM context if not found from this */
2158 if (!wsink)
2159 wsink = wtsink;
2160 if (!wsource)
2161 wsource = wtsource;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002162
2163 if (wsource == NULL || wsink == NULL)
2164 return -ENODEV;
2165
2166 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
2167 if (!path)
2168 return -ENOMEM;
2169
2170 path->source = wsource;
2171 path->sink = wsink;
Mark Brown215edda2009-09-08 18:59:05 +01002172 path->connected = route->connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002173 INIT_LIST_HEAD(&path->list);
2174 INIT_LIST_HEAD(&path->list_source);
2175 INIT_LIST_HEAD(&path->list_sink);
2176
2177 /* check for external widgets */
2178 if (wsink->id == snd_soc_dapm_input) {
2179 if (wsource->id == snd_soc_dapm_micbias ||
2180 wsource->id == snd_soc_dapm_mic ||
Rongrong Cao087d53a2009-07-10 20:13:30 +01002181 wsource->id == snd_soc_dapm_line ||
2182 wsource->id == snd_soc_dapm_output)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002183 wsink->ext = 1;
2184 }
2185 if (wsource->id == snd_soc_dapm_output) {
2186 if (wsink->id == snd_soc_dapm_spk ||
2187 wsink->id == snd_soc_dapm_hp ||
Seth Forshee1e392212007-04-16 15:36:42 +02002188 wsink->id == snd_soc_dapm_line ||
2189 wsink->id == snd_soc_dapm_input)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002190 wsource->ext = 1;
2191 }
2192
2193 /* connect static paths */
2194 if (control == NULL) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002195 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002196 list_add(&path->list_sink, &wsink->sources);
2197 list_add(&path->list_source, &wsource->sinks);
2198 path->connect = 1;
2199 return 0;
2200 }
2201
2202 /* connect dynamic paths */
Lu Guanqundc2bea62011-04-20 16:00:36 +08002203 switch (wsink->id) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02002204 case snd_soc_dapm_adc:
2205 case snd_soc_dapm_dac:
2206 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002207 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002208 case snd_soc_dapm_input:
2209 case snd_soc_dapm_output:
Mark Brown1ab97c82011-11-27 16:21:51 +00002210 case snd_soc_dapm_siggen:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002211 case snd_soc_dapm_micbias:
2212 case snd_soc_dapm_vmid:
2213 case snd_soc_dapm_pre:
2214 case snd_soc_dapm_post:
Mark Brown246d0a12009-04-22 18:24:55 +01002215 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002216 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002217 case snd_soc_dapm_clock_supply:
Mark Brown010ff262009-08-17 17:39:22 +01002218 case snd_soc_dapm_aif_in:
2219 case snd_soc_dapm_aif_out:
Mark Brown888df392012-02-16 19:37:51 -08002220 case snd_soc_dapm_dai:
Mark Brownc74184e2012-04-04 22:12:09 +01002221 case snd_soc_dapm_dai_link:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002222 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002223 list_add(&path->list_sink, &wsink->sources);
2224 list_add(&path->list_source, &wsource->sinks);
2225 path->connect = 1;
2226 return 0;
2227 case snd_soc_dapm_mux:
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00002228 case snd_soc_dapm_virt_mux:
Peter Ujfalusi74155552009-01-08 13:34:29 +02002229 case snd_soc_dapm_value_mux:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002230 ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
Stephen Warren82cfecd2011-04-28 17:37:58 -06002231 &wsink->kcontrol_news[0]);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002232 if (ret != 0)
2233 goto err;
2234 break;
2235 case snd_soc_dapm_switch:
2236 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002237 case snd_soc_dapm_mixer_named_ctl:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002238 ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002239 if (ret != 0)
2240 goto err;
2241 break;
2242 case snd_soc_dapm_hp:
2243 case snd_soc_dapm_mic:
2244 case snd_soc_dapm_line:
2245 case snd_soc_dapm_spk:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002246 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002247 list_add(&path->list_sink, &wsink->sources);
2248 list_add(&path->list_source, &wsource->sinks);
2249 path->connect = 0;
2250 return 0;
2251 }
2252 return 0;
2253
2254err:
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002255 dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n",
2256 source, control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002257 kfree(path);
2258 return ret;
2259}
Mark Brown105f1c22008-05-13 14:52:19 +02002260
2261/**
Mark Brown105f1c22008-05-13 14:52:19 +02002262 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002263 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002264 * @route: audio routes
2265 * @num: number of routes
2266 *
2267 * Connects 2 dapm widgets together via a named audio path. The sink is
2268 * the widget receiving the audio signal, whilst the source is the sender
2269 * of the audio signal.
2270 *
2271 * Returns 0 for success else error. On error all resources can be freed
2272 * with a call to snd_soc_card_free().
2273 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002274int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002275 const struct snd_soc_dapm_route *route, int num)
2276{
Dan Carpenter60884c22012-04-13 22:25:43 +03002277 int i, ret = 0;
Mark Brown105f1c22008-05-13 14:52:19 +02002278
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002279 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown105f1c22008-05-13 14:52:19 +02002280 for (i = 0; i < num; i++) {
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002281 ret = snd_soc_dapm_add_route(dapm, route);
Mark Brown105f1c22008-05-13 14:52:19 +02002282 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002283 dev_err(dapm->dev, "Failed to add route %s->%s\n",
2284 route->source, route->sink);
Dan Carpenter60884c22012-04-13 22:25:43 +03002285 break;
Mark Brown105f1c22008-05-13 14:52:19 +02002286 }
2287 route++;
2288 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002289 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brown105f1c22008-05-13 14:52:19 +02002290
Dan Carpenter60884c22012-04-13 22:25:43 +03002291 return ret;
Mark Brown105f1c22008-05-13 14:52:19 +02002292}
2293EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2294
Mark Brownbf3a9e12011-06-13 16:42:29 +01002295static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
2296 const struct snd_soc_dapm_route *route)
2297{
2298 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
2299 route->source,
2300 true);
2301 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
2302 route->sink,
2303 true);
2304 struct snd_soc_dapm_path *path;
2305 int count = 0;
2306
2307 if (!source) {
2308 dev_err(dapm->dev, "Unable to find source %s for weak route\n",
2309 route->source);
2310 return -ENODEV;
2311 }
2312
2313 if (!sink) {
2314 dev_err(dapm->dev, "Unable to find sink %s for weak route\n",
2315 route->sink);
2316 return -ENODEV;
2317 }
2318
2319 if (route->control || route->connected)
2320 dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n",
2321 route->source, route->sink);
2322
2323 list_for_each_entry(path, &source->sinks, list_source) {
2324 if (path->sink == sink) {
2325 path->weak = 1;
2326 count++;
2327 }
2328 }
2329
2330 if (count == 0)
2331 dev_err(dapm->dev, "No path found for weak route %s->%s\n",
2332 route->source, route->sink);
2333 if (count > 1)
2334 dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n",
2335 count, route->source, route->sink);
2336
2337 return 0;
2338}
2339
2340/**
2341 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
2342 * @dapm: DAPM context
2343 * @route: audio routes
2344 * @num: number of routes
2345 *
2346 * Mark existing routes matching those specified in the passed array
2347 * as being weak, meaning that they are ignored for the purpose of
2348 * power decisions. The main intended use case is for sidetone paths
2349 * which couple audio between other independent paths if they are both
2350 * active in order to make the combination work better at the user
2351 * level but which aren't intended to be "used".
2352 *
2353 * Note that CODEC drivers should not use this as sidetone type paths
2354 * can frequently also be used as bypass paths.
2355 */
2356int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
2357 const struct snd_soc_dapm_route *route, int num)
2358{
2359 int i, err;
2360 int ret = 0;
2361
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002362 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002363 for (i = 0; i < num; i++) {
2364 err = snd_soc_dapm_weak_route(dapm, route);
2365 if (err)
2366 ret = err;
2367 route++;
2368 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002369 mutex_unlock(&dapm->card->dapm_mutex);
Mark Brownbf3a9e12011-06-13 16:42:29 +01002370
2371 return ret;
2372}
2373EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
2374
Mark Brown105f1c22008-05-13 14:52:19 +02002375/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002376 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002377 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002378 *
2379 * Checks the codec for any new dapm widgets and creates them if found.
2380 *
2381 * Returns 0 for success.
2382 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002383int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002384{
2385 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002386 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002387
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002388 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
2389
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002390 list_for_each_entry(w, &dapm->card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002391 {
2392 if (w->new)
2393 continue;
2394
Stephen Warrenfad59882011-04-28 17:37:59 -06002395 if (w->num_kcontrols) {
2396 w->kcontrols = kzalloc(w->num_kcontrols *
2397 sizeof(struct snd_kcontrol *),
2398 GFP_KERNEL);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002399 if (!w->kcontrols) {
2400 mutex_unlock(&dapm->card->dapm_mutex);
Stephen Warrenfad59882011-04-28 17:37:59 -06002401 return -ENOMEM;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002402 }
Stephen Warrenfad59882011-04-28 17:37:59 -06002403 }
2404
Richard Purdie2b97eab2006-10-06 18:32:18 +02002405 switch(w->id) {
2406 case snd_soc_dapm_switch:
2407 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002408 case snd_soc_dapm_mixer_named_ctl:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002409 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002410 break;
2411 case snd_soc_dapm_mux:
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00002412 case snd_soc_dapm_virt_mux:
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002413 case snd_soc_dapm_value_mux:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002414 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002415 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002416 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002417 case snd_soc_dapm_out_drv:
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002418 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002419 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002420 default:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002421 break;
2422 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002423
2424 /* Read the initial power state from the device */
2425 if (w->reg >= 0) {
Liam Girdwood0445bdf2011-06-13 19:37:36 +01002426 val = soc_widget_read(w, w->reg);
Mark Brownb66a70d2011-02-09 18:04:11 +00002427 val &= 1 << w->shift;
2428 if (w->invert)
2429 val = !val;
2430
2431 if (val)
2432 w->power = 1;
2433 }
2434
Richard Purdie2b97eab2006-10-06 18:32:18 +02002435 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002436
Mark Brown7508b122011-10-05 12:09:12 +01002437 dapm_mark_dirty(w, "new widget");
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002438 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002439 }
2440
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002441 dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002442 mutex_unlock(&dapm->card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002443 return 0;
2444}
2445EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2446
2447/**
2448 * snd_soc_dapm_get_volsw - dapm mixer get callback
2449 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002450 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002451 *
2452 * Callback to get the value of a dapm mixer control.
2453 *
2454 * Returns 0 for success.
2455 */
2456int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2457 struct snd_ctl_elem_value *ucontrol)
2458{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002459 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2460 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Jon Smirl4eaa9812008-07-29 11:42:26 +01002461 struct soc_mixer_control *mc =
2462 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf82008-07-29 10:22:24 -04002463 unsigned int reg = mc->reg;
2464 unsigned int shift = mc->shift;
2465 unsigned int rshift = mc->rshift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002466 int max = mc->max;
Jon Smirl815ecf82008-07-29 10:22:24 -04002467 unsigned int invert = mc->invert;
2468 unsigned int mask = (1 << fls(max)) - 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002469
Richard Purdie2b97eab2006-10-06 18:32:18 +02002470 ucontrol->value.integer.value[0] =
2471 (snd_soc_read(widget->codec, reg) >> shift) & mask;
2472 if (shift != rshift)
2473 ucontrol->value.integer.value[1] =
2474 (snd_soc_read(widget->codec, reg) >> rshift) & mask;
2475 if (invert) {
2476 ucontrol->value.integer.value[0] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002477 max - ucontrol->value.integer.value[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002478 if (shift != rshift)
2479 ucontrol->value.integer.value[1] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002480 max - ucontrol->value.integer.value[1];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002481 }
2482
2483 return 0;
2484}
2485EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
2486
2487/**
2488 * snd_soc_dapm_put_volsw - dapm mixer set callback
2489 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002490 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002491 *
2492 * Callback to set the value of a dapm mixer control.
2493 *
2494 * Returns 0 for success.
2495 */
2496int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2497 struct snd_ctl_elem_value *ucontrol)
2498{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002499 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2500 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2501 struct snd_soc_codec *codec = widget->codec;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002502 struct snd_soc_card *card = codec->card;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002503 struct soc_mixer_control *mc =
2504 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf82008-07-29 10:22:24 -04002505 unsigned int reg = mc->reg;
2506 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002507 int max = mc->max;
Jon Smirl815ecf82008-07-29 10:22:24 -04002508 unsigned int mask = (1 << fls(max)) - 1;
2509 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002510 unsigned int val;
Mark Brown97404f22010-12-14 16:13:57 +00002511 int connect, change;
2512 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002513 int wi;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002514
2515 val = (ucontrol->value.integer.value[0] & mask);
2516
2517 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002518 val = max - val;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002519 mask = mask << shift;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002520 val = val << shift;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002521
Stephen Warrenfafd2172011-04-28 17:38:00 -06002522 if (val)
2523 /* new connection */
2524 connect = invert ? 0 : 1;
2525 else
2526 /* old connection must be powered down */
2527 connect = invert ? 1 : 0;
2528
Liam Girdwood3cd04342012-03-09 12:02:08 +00002529 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002530
Stephen Warrene9cf7042011-01-27 14:54:05 -07002531 change = snd_soc_test_bits(widget->codec, reg, mask, val);
Mark Brown97404f22010-12-14 16:13:57 +00002532 if (change) {
Stephen Warrenfafd2172011-04-28 17:38:00 -06002533 for (wi = 0; wi < wlist->num_widgets; wi++) {
2534 widget = wlist->widgets[wi];
Mark Brown283375c2009-12-07 18:09:03 +00002535
Stephen Warrenfafd2172011-04-28 17:38:00 -06002536 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002537
Stephen Warrenfafd2172011-04-28 17:38:00 -06002538 update.kcontrol = kcontrol;
2539 update.widget = widget;
2540 update.reg = reg;
2541 update.mask = mask;
2542 update.val = val;
2543 widget->dapm->update = &update;
Mark Brown97404f22010-12-14 16:13:57 +00002544
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002545 soc_dapm_mixer_update_power(widget, kcontrol, connect);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002546
2547 widget->dapm->update = NULL;
2548 }
Mark Brown283375c2009-12-07 18:09:03 +00002549 }
2550
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002551 mutex_unlock(&card->dapm_mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002552 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002553}
2554EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
2555
2556/**
2557 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
2558 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002559 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002560 *
2561 * Callback to get the value of a dapm enumerated double mixer control.
2562 *
2563 * Returns 0 for success.
2564 */
2565int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
2566 struct snd_ctl_elem_value *ucontrol)
2567{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002568 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2569 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002570 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002571 unsigned int val, bitmask;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002572
Jon Smirlf8ba0b7b2008-07-29 11:42:27 +01002573 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002574 ;
2575 val = snd_soc_read(widget->codec, e->reg);
2576 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
2577 if (e->shift_l != e->shift_r)
2578 ucontrol->value.enumerated.item[1] =
2579 (val >> e->shift_r) & (bitmask - 1);
2580
2581 return 0;
2582}
2583EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
2584
2585/**
2586 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
2587 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002588 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002589 *
2590 * Callback to set the value of a dapm enumerated double mixer control.
2591 *
2592 * Returns 0 for success.
2593 */
2594int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
2595 struct snd_ctl_elem_value *ucontrol)
2596{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002597 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2598 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2599 struct snd_soc_codec *codec = widget->codec;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002600 struct snd_soc_card *card = codec->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002601 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Mark Brown3a655772009-10-05 17:23:30 +01002602 unsigned int val, mux, change;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002603 unsigned int mask, bitmask;
Mark Brown97404f22010-12-14 16:13:57 +00002604 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002605 int wi;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002606
Jon Smirlf8ba0b7b2008-07-29 11:42:27 +01002607 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002608 ;
Jon Smirlf8ba0b7b2008-07-29 11:42:27 +01002609 if (ucontrol->value.enumerated.item[0] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002610 return -EINVAL;
2611 mux = ucontrol->value.enumerated.item[0];
2612 val = mux << e->shift_l;
2613 mask = (bitmask - 1) << e->shift_l;
2614 if (e->shift_l != e->shift_r) {
Jon Smirlf8ba0b7b2008-07-29 11:42:27 +01002615 if (ucontrol->value.enumerated.item[1] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002616 return -EINVAL;
2617 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
2618 mask |= (bitmask - 1) << e->shift_r;
2619 }
2620
Liam Girdwood3cd04342012-03-09 12:02:08 +00002621 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002622
Mark Brown3a655772009-10-05 17:23:30 +01002623 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002624 if (change) {
2625 for (wi = 0; wi < wlist->num_widgets; wi++) {
2626 widget = wlist->widgets[wi];
Mark Brown97404f22010-12-14 16:13:57 +00002627
Stephen Warrenfafd2172011-04-28 17:38:00 -06002628 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002629
Stephen Warrenfafd2172011-04-28 17:38:00 -06002630 update.kcontrol = kcontrol;
2631 update.widget = widget;
2632 update.reg = e->reg;
2633 update.mask = mask;
2634 update.val = val;
2635 widget->dapm->update = &update;
Mark Brown1642e3d2009-10-05 16:24:26 +01002636
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002637 soc_dapm_mux_update_power(widget, kcontrol, mux, e);
Mark Brown1642e3d2009-10-05 16:24:26 +01002638
Stephen Warrenfafd2172011-04-28 17:38:00 -06002639 widget->dapm->update = NULL;
2640 }
2641 }
2642
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002643 mutex_unlock(&card->dapm_mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002644 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002645}
2646EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
2647
2648/**
Mark Brownd2b247a2009-10-06 15:21:04 +01002649 * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
2650 * @kcontrol: mixer control
2651 * @ucontrol: control element information
2652 *
2653 * Returns 0 for success.
2654 */
2655int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
2656 struct snd_ctl_elem_value *ucontrol)
2657{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002658 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2659 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Mark Brownd2b247a2009-10-06 15:21:04 +01002660
2661 ucontrol->value.enumerated.item[0] = widget->value;
2662
2663 return 0;
2664}
2665EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
2666
2667/**
2668 * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
2669 * @kcontrol: mixer control
2670 * @ucontrol: control element information
2671 *
2672 * Returns 0 for success.
2673 */
2674int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
2675 struct snd_ctl_elem_value *ucontrol)
2676{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002677 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2678 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2679 struct snd_soc_codec *codec = widget->codec;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002680 struct snd_soc_card *card = codec->card;
Mark Brownd2b247a2009-10-06 15:21:04 +01002681 struct soc_enum *e =
2682 (struct soc_enum *)kcontrol->private_value;
2683 int change;
2684 int ret = 0;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002685 int wi;
Mark Brownd2b247a2009-10-06 15:21:04 +01002686
2687 if (ucontrol->value.enumerated.item[0] >= e->max)
2688 return -EINVAL;
2689
Liam Girdwood3cd04342012-03-09 12:02:08 +00002690 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brownd2b247a2009-10-06 15:21:04 +01002691
2692 change = widget->value != ucontrol->value.enumerated.item[0];
Stephen Warrenfafd2172011-04-28 17:38:00 -06002693 if (change) {
2694 for (wi = 0; wi < wlist->num_widgets; wi++) {
2695 widget = wlist->widgets[wi];
Mark Brownd2b247a2009-10-06 15:21:04 +01002696
Stephen Warrenfafd2172011-04-28 17:38:00 -06002697 widget->value = ucontrol->value.enumerated.item[0];
2698
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002699 soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002700 }
2701 }
2702
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002703 mutex_unlock(&card->dapm_mutex);
Mark Brownd2b247a2009-10-06 15:21:04 +01002704 return ret;
2705}
2706EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
2707
2708/**
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002709 * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
2710 * callback
2711 * @kcontrol: mixer control
2712 * @ucontrol: control element information
2713 *
2714 * Callback to get the value of a dapm semi enumerated double mixer control.
2715 *
2716 * Semi enumerated mixer: the enumerated items are referred as values. Can be
2717 * used for handling bitfield coded enumeration for example.
2718 *
2719 * Returns 0 for success.
2720 */
2721int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
2722 struct snd_ctl_elem_value *ucontrol)
2723{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002724 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2725 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Peter Ujfalusi74155552009-01-08 13:34:29 +02002726 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002727 unsigned int reg_val, val, mux;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002728
2729 reg_val = snd_soc_read(widget->codec, e->reg);
2730 val = (reg_val >> e->shift_l) & e->mask;
2731 for (mux = 0; mux < e->max; mux++) {
2732 if (val == e->values[mux])
2733 break;
2734 }
2735 ucontrol->value.enumerated.item[0] = mux;
2736 if (e->shift_l != e->shift_r) {
2737 val = (reg_val >> e->shift_r) & e->mask;
2738 for (mux = 0; mux < e->max; mux++) {
2739 if (val == e->values[mux])
2740 break;
2741 }
2742 ucontrol->value.enumerated.item[1] = mux;
2743 }
2744
2745 return 0;
2746}
2747EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
2748
2749/**
2750 * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
2751 * callback
2752 * @kcontrol: mixer control
2753 * @ucontrol: control element information
2754 *
2755 * Callback to set the value of a dapm semi enumerated double mixer control.
2756 *
2757 * Semi enumerated mixer: the enumerated items are referred as values. Can be
2758 * used for handling bitfield coded enumeration for example.
2759 *
2760 * Returns 0 for success.
2761 */
2762int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
2763 struct snd_ctl_elem_value *ucontrol)
2764{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002765 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2766 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2767 struct snd_soc_codec *codec = widget->codec;
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002768 struct snd_soc_card *card = codec->card;
Peter Ujfalusi74155552009-01-08 13:34:29 +02002769 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Mark Brown3a655772009-10-05 17:23:30 +01002770 unsigned int val, mux, change;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002771 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00002772 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002773 int wi;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002774
2775 if (ucontrol->value.enumerated.item[0] > e->max - 1)
2776 return -EINVAL;
2777 mux = ucontrol->value.enumerated.item[0];
2778 val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
2779 mask = e->mask << e->shift_l;
2780 if (e->shift_l != e->shift_r) {
2781 if (ucontrol->value.enumerated.item[1] > e->max - 1)
2782 return -EINVAL;
2783 val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
2784 mask |= e->mask << e->shift_r;
2785 }
2786
Liam Girdwood3cd04342012-03-09 12:02:08 +00002787 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002788
Mark Brown3a655772009-10-05 17:23:30 +01002789 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002790 if (change) {
2791 for (wi = 0; wi < wlist->num_widgets; wi++) {
2792 widget = wlist->widgets[wi];
Mark Brown97404f22010-12-14 16:13:57 +00002793
Stephen Warrenfafd2172011-04-28 17:38:00 -06002794 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002795
Stephen Warrenfafd2172011-04-28 17:38:00 -06002796 update.kcontrol = kcontrol;
2797 update.widget = widget;
2798 update.reg = e->reg;
2799 update.mask = mask;
2800 update.val = val;
2801 widget->dapm->update = &update;
Mark Brown1642e3d2009-10-05 16:24:26 +01002802
Liam Girdwood4edbb3452012-03-07 10:38:27 +00002803 soc_dapm_mux_update_power(widget, kcontrol, mux, e);
Mark Brown1642e3d2009-10-05 16:24:26 +01002804
Stephen Warrenfafd2172011-04-28 17:38:00 -06002805 widget->dapm->update = NULL;
2806 }
2807 }
2808
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002809 mutex_unlock(&card->dapm_mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002810 return change;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002811}
2812EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
2813
2814/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00002815 * snd_soc_dapm_info_pin_switch - Info for a pin switch
2816 *
2817 * @kcontrol: mixer control
2818 * @uinfo: control element information
2819 *
2820 * Callback to provide information about a pin switch control.
2821 */
2822int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
2823 struct snd_ctl_elem_info *uinfo)
2824{
2825 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2826 uinfo->count = 1;
2827 uinfo->value.integer.min = 0;
2828 uinfo->value.integer.max = 1;
2829
2830 return 0;
2831}
2832EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
2833
2834/**
2835 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
2836 *
2837 * @kcontrol: mixer control
2838 * @ucontrol: Value
2839 */
2840int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
2841 struct snd_ctl_elem_value *ucontrol)
2842{
Mark Brown48a8c392012-02-14 17:11:15 -08002843 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002844 const char *pin = (const char *)kcontrol->private_value;
2845
Liam Girdwood3cd04342012-03-09 12:02:08 +00002846 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002847
2848 ucontrol->value.integer.value[0] =
Mark Brown48a8c392012-02-14 17:11:15 -08002849 snd_soc_dapm_get_pin_status(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002850
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002851 mutex_unlock(&card->dapm_mutex);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002852
2853 return 0;
2854}
2855EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
2856
2857/**
2858 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
2859 *
2860 * @kcontrol: mixer control
2861 * @ucontrol: Value
2862 */
2863int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
2864 struct snd_ctl_elem_value *ucontrol)
2865{
Mark Brown48a8c392012-02-14 17:11:15 -08002866 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002867 const char *pin = (const char *)kcontrol->private_value;
2868
Liam Girdwood3cd04342012-03-09 12:02:08 +00002869 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002870
2871 if (ucontrol->value.integer.value[0])
Mark Brown48a8c392012-02-14 17:11:15 -08002872 snd_soc_dapm_enable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002873 else
Mark Brown48a8c392012-02-14 17:11:15 -08002874 snd_soc_dapm_disable_pin(&card->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002875
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00002876 mutex_unlock(&card->dapm_mutex);
2877
Mark Brown48a8c392012-02-14 17:11:15 -08002878 snd_soc_dapm_sync(&card->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002879 return 0;
2880}
2881EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
2882
Mark Brown5ba06fc2012-02-16 11:07:13 -08002883static struct snd_soc_dapm_widget *
2884snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
2885 const struct snd_soc_dapm_widget *widget)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002886{
2887 struct snd_soc_dapm_widget *w;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002888 size_t name_len;
Mark Brown62ea8742012-01-21 21:14:48 +00002889 int ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002890
2891 if ((w = dapm_cnew_widget(widget)) == NULL)
Mark Brown5ba06fc2012-02-16 11:07:13 -08002892 return NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002893
Mark Brown62ea8742012-01-21 21:14:48 +00002894 switch (w->id) {
2895 case snd_soc_dapm_regulator_supply:
Liam Girdwooda3cc0562012-03-09 17:20:16 +00002896 w->regulator = devm_regulator_get(dapm->dev, w->name);
2897 if (IS_ERR(w->regulator)) {
2898 ret = PTR_ERR(w->regulator);
Mark Brown62ea8742012-01-21 21:14:48 +00002899 dev_err(dapm->dev, "Failed to request %s: %d\n",
2900 w->name, ret);
Mark Brown5ba06fc2012-02-16 11:07:13 -08002901 return NULL;
Mark Brown62ea8742012-01-21 21:14:48 +00002902 }
2903 break;
Ola Liljad7e7eb92012-05-24 15:26:25 +02002904 case snd_soc_dapm_clock_supply:
Mark Brown695594f12012-06-04 08:14:13 +01002905 w->clk = devm_clk_get(dapm->dev, w->name);
Ola Liljad7e7eb92012-05-24 15:26:25 +02002906 if (IS_ERR(w->clk)) {
2907 ret = PTR_ERR(w->clk);
2908 dev_err(dapm->dev, "Failed to request %s: %d\n",
2909 w->name, ret);
2910 return NULL;
2911 }
2912 break;
Mark Brown62ea8742012-01-21 21:14:48 +00002913 default:
2914 break;
2915 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002916
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002917 name_len = strlen(widget->name) + 1;
Mark Brown88e8b9a2011-03-02 18:18:24 +00002918 if (dapm->codec && dapm->codec->name_prefix)
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002919 name_len += 1 + strlen(dapm->codec->name_prefix);
2920 w->name = kmalloc(name_len, GFP_KERNEL);
2921 if (w->name == NULL) {
2922 kfree(w);
Mark Brown5ba06fc2012-02-16 11:07:13 -08002923 return NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002924 }
Mark Brown88e8b9a2011-03-02 18:18:24 +00002925 if (dapm->codec && dapm->codec->name_prefix)
Mark Brown888df392012-02-16 19:37:51 -08002926 snprintf((char *)w->name, name_len, "%s %s",
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002927 dapm->codec->name_prefix, widget->name);
2928 else
Mark Brown888df392012-02-16 19:37:51 -08002929 snprintf((char *)w->name, name_len, "%s", widget->name);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002930
Mark Brown7ca3a182011-10-08 14:04:50 +01002931 switch (w->id) {
2932 case snd_soc_dapm_switch:
2933 case snd_soc_dapm_mixer:
2934 case snd_soc_dapm_mixer_named_ctl:
2935 w->power_check = dapm_generic_check_power;
2936 break;
2937 case snd_soc_dapm_mux:
2938 case snd_soc_dapm_virt_mux:
2939 case snd_soc_dapm_value_mux:
2940 w->power_check = dapm_generic_check_power;
2941 break;
2942 case snd_soc_dapm_adc:
2943 case snd_soc_dapm_aif_out:
2944 w->power_check = dapm_adc_check_power;
2945 break;
2946 case snd_soc_dapm_dac:
2947 case snd_soc_dapm_aif_in:
2948 w->power_check = dapm_dac_check_power;
2949 break;
2950 case snd_soc_dapm_pga:
2951 case snd_soc_dapm_out_drv:
2952 case snd_soc_dapm_input:
2953 case snd_soc_dapm_output:
2954 case snd_soc_dapm_micbias:
2955 case snd_soc_dapm_spk:
2956 case snd_soc_dapm_hp:
2957 case snd_soc_dapm_mic:
2958 case snd_soc_dapm_line:
Mark Brownc74184e2012-04-04 22:12:09 +01002959 case snd_soc_dapm_dai_link:
Mark Brown7ca3a182011-10-08 14:04:50 +01002960 w->power_check = dapm_generic_check_power;
2961 break;
2962 case snd_soc_dapm_supply:
Mark Brown62ea8742012-01-21 21:14:48 +00002963 case snd_soc_dapm_regulator_supply:
Ola Liljad7e7eb92012-05-24 15:26:25 +02002964 case snd_soc_dapm_clock_supply:
Mark Brown7ca3a182011-10-08 14:04:50 +01002965 w->power_check = dapm_supply_check_power;
2966 break;
Mark Brown888df392012-02-16 19:37:51 -08002967 case snd_soc_dapm_dai:
2968 w->power_check = dapm_dai_check_power;
2969 break;
Mark Brown7ca3a182011-10-08 14:04:50 +01002970 default:
2971 w->power_check = dapm_always_on_check_power;
2972 break;
2973 }
2974
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002975 dapm->n_widgets++;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002976 w->dapm = dapm;
2977 w->codec = dapm->codec;
Liam Girdwoodb7950642011-07-04 22:10:52 +01002978 w->platform = dapm->platform;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002979 INIT_LIST_HEAD(&w->sources);
2980 INIT_LIST_HEAD(&w->sinks);
2981 INIT_LIST_HEAD(&w->list);
Mark Browndb432b42011-10-03 21:06:40 +01002982 INIT_LIST_HEAD(&w->dirty);
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002983 list_add(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002984
2985 /* machine layer set ups unconnected pins and insertions */
2986 w->connected = 1;
Mark Brown5ba06fc2012-02-16 11:07:13 -08002987 return w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002988}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002989
2990/**
Mark Brown4ba13272008-05-13 14:51:19 +02002991 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002992 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02002993 * @widget: widget array
2994 * @num: number of widgets
2995 *
2996 * Creates new DAPM controls based upon the templates.
2997 *
2998 * Returns 0 for success else error.
2999 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003000int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02003001 const struct snd_soc_dapm_widget *widget,
3002 int num)
3003{
Mark Brown5ba06fc2012-02-16 11:07:13 -08003004 struct snd_soc_dapm_widget *w;
3005 int i;
Dan Carpenter60884c22012-04-13 22:25:43 +03003006 int ret = 0;
Mark Brown4ba13272008-05-13 14:51:19 +02003007
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003008 mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
Mark Brown4ba13272008-05-13 14:51:19 +02003009 for (i = 0; i < num; i++) {
Mark Brown5ba06fc2012-02-16 11:07:13 -08003010 w = snd_soc_dapm_new_control(dapm, widget);
3011 if (!w) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02003012 dev_err(dapm->dev,
Mark Brown5ba06fc2012-02-16 11:07:13 -08003013 "ASoC: Failed to create DAPM control %s\n",
3014 widget->name);
Dan Carpenter60884c22012-04-13 22:25:43 +03003015 ret = -ENOMEM;
3016 break;
Mark Brownb8b33cb2008-12-18 11:19:30 +00003017 }
Mark Brown4ba13272008-05-13 14:51:19 +02003018 widget++;
3019 }
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003020 mutex_unlock(&dapm->card->dapm_mutex);
Dan Carpenter60884c22012-04-13 22:25:43 +03003021 return ret;
Mark Brown4ba13272008-05-13 14:51:19 +02003022}
3023EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3024
Mark Brownc74184e2012-04-04 22:12:09 +01003025static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3026 struct snd_kcontrol *kcontrol, int event)
3027{
3028 struct snd_soc_dapm_path *source_p, *sink_p;
3029 struct snd_soc_dai *source, *sink;
3030 const struct snd_soc_pcm_stream *config = w->params;
3031 struct snd_pcm_substream substream;
Mark Brown9747cec2012-04-26 19:12:21 +01003032 struct snd_pcm_hw_params *params = NULL;
Mark Brownc74184e2012-04-04 22:12:09 +01003033 u64 fmt;
3034 int ret;
3035
3036 BUG_ON(!config);
3037 BUG_ON(list_empty(&w->sources) || list_empty(&w->sinks));
3038
3039 /* We only support a single source and sink, pick the first */
3040 source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
3041 list_sink);
3042 sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
3043 list_source);
3044
3045 BUG_ON(!source_p || !sink_p);
3046 BUG_ON(!sink_p->source || !source_p->sink);
3047 BUG_ON(!source_p->source || !sink_p->sink);
3048
3049 source = source_p->source->priv;
3050 sink = sink_p->sink->priv;
3051
3052 /* Be a little careful as we don't want to overflow the mask array */
3053 if (config->formats) {
3054 fmt = ffs(config->formats) - 1;
3055 } else {
Fabio Estevam516541a2012-04-16 10:53:09 -03003056 dev_warn(w->dapm->dev, "Invalid format %llx specified\n",
Mark Brownc74184e2012-04-04 22:12:09 +01003057 config->formats);
3058 fmt = 0;
3059 }
3060
3061 /* Currently very limited parameter selection */
Mark Brown9747cec2012-04-26 19:12:21 +01003062 params = kzalloc(sizeof(*params), GFP_KERNEL);
3063 if (!params) {
3064 ret = -ENOMEM;
3065 goto out;
3066 }
3067 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
Mark Brownc74184e2012-04-04 22:12:09 +01003068
Mark Brown9747cec2012-04-26 19:12:21 +01003069 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
Mark Brownc74184e2012-04-04 22:12:09 +01003070 config->rate_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003071 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
Mark Brownc74184e2012-04-04 22:12:09 +01003072 config->rate_max;
3073
Mark Brown9747cec2012-04-26 19:12:21 +01003074 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
Mark Brownc74184e2012-04-04 22:12:09 +01003075 = config->channels_min;
Mark Brown9747cec2012-04-26 19:12:21 +01003076 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
Mark Brownc74184e2012-04-04 22:12:09 +01003077 = config->channels_max;
3078
3079 memset(&substream, 0, sizeof(substream));
3080
3081 switch (event) {
3082 case SND_SOC_DAPM_PRE_PMU:
3083 if (source->driver->ops && source->driver->ops->hw_params) {
3084 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3085 ret = source->driver->ops->hw_params(&substream,
Mark Brown9747cec2012-04-26 19:12:21 +01003086 params, source);
Mark Brownc74184e2012-04-04 22:12:09 +01003087 if (ret != 0) {
3088 dev_err(source->dev,
3089 "hw_params() failed: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003090 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003091 }
3092 }
3093
3094 if (sink->driver->ops && sink->driver->ops->hw_params) {
3095 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
Mark Brown9747cec2012-04-26 19:12:21 +01003096 ret = sink->driver->ops->hw_params(&substream, params,
Mark Brownc74184e2012-04-04 22:12:09 +01003097 sink);
3098 if (ret != 0) {
3099 dev_err(sink->dev,
3100 "hw_params() failed: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003101 goto out;
Mark Brownc74184e2012-04-04 22:12:09 +01003102 }
3103 }
3104 break;
3105
3106 case SND_SOC_DAPM_POST_PMU:
3107 ret = snd_soc_dai_digital_mute(sink, 0);
3108 if (ret != 0 && ret != -ENOTSUPP)
3109 dev_warn(sink->dev, "Failed to unmute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003110 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003111 break;
3112
3113 case SND_SOC_DAPM_PRE_PMD:
3114 ret = snd_soc_dai_digital_mute(sink, 1);
3115 if (ret != 0 && ret != -ENOTSUPP)
3116 dev_warn(sink->dev, "Failed to mute: %d\n", ret);
Mark Brown9747cec2012-04-26 19:12:21 +01003117 ret = 0;
Mark Brownc74184e2012-04-04 22:12:09 +01003118 break;
3119
3120 default:
3121 BUG();
3122 return -EINVAL;
3123 }
3124
Mark Brown9747cec2012-04-26 19:12:21 +01003125out:
3126 kfree(params);
3127 return ret;
Mark Brownc74184e2012-04-04 22:12:09 +01003128}
3129
3130int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
3131 const struct snd_soc_pcm_stream *params,
3132 struct snd_soc_dapm_widget *source,
3133 struct snd_soc_dapm_widget *sink)
3134{
3135 struct snd_soc_dapm_route routes[2];
3136 struct snd_soc_dapm_widget template;
3137 struct snd_soc_dapm_widget *w;
3138 size_t len;
3139 char *link_name;
3140
3141 len = strlen(source->name) + strlen(sink->name) + 2;
3142 link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
3143 if (!link_name)
3144 return -ENOMEM;
3145 snprintf(link_name, len, "%s-%s", source->name, sink->name);
3146
3147 memset(&template, 0, sizeof(template));
3148 template.reg = SND_SOC_NOPM;
3149 template.id = snd_soc_dapm_dai_link;
3150 template.name = link_name;
3151 template.event = snd_soc_dai_link_event;
3152 template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3153 SND_SOC_DAPM_PRE_PMD;
3154
3155 dev_dbg(card->dev, "adding %s widget\n", link_name);
3156
3157 w = snd_soc_dapm_new_control(&card->dapm, &template);
3158 if (!w) {
3159 dev_err(card->dev, "Failed to create %s widget\n",
3160 link_name);
3161 return -ENOMEM;
3162 }
3163
3164 w->params = params;
3165
3166 memset(&routes, 0, sizeof(routes));
3167
3168 routes[0].source = source->name;
3169 routes[0].sink = link_name;
3170 routes[1].source = link_name;
3171 routes[1].sink = sink->name;
3172
3173 return snd_soc_dapm_add_routes(&card->dapm, routes,
3174 ARRAY_SIZE(routes));
3175}
3176
Mark Brown888df392012-02-16 19:37:51 -08003177int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
3178 struct snd_soc_dai *dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003179{
Mark Brown888df392012-02-16 19:37:51 -08003180 struct snd_soc_dapm_widget template;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003181 struct snd_soc_dapm_widget *w;
3182
Mark Brown888df392012-02-16 19:37:51 -08003183 WARN_ON(dapm->dev != dai->dev);
3184
3185 memset(&template, 0, sizeof(template));
3186 template.reg = SND_SOC_NOPM;
3187
3188 if (dai->driver->playback.stream_name) {
3189 template.id = snd_soc_dapm_dai;
3190 template.name = dai->driver->playback.stream_name;
3191 template.sname = dai->driver->playback.stream_name;
3192
3193 dev_dbg(dai->dev, "adding %s widget\n",
3194 template.name);
3195
3196 w = snd_soc_dapm_new_control(dapm, &template);
3197 if (!w) {
3198 dev_err(dapm->dev, "Failed to create %s widget\n",
3199 dai->driver->playback.stream_name);
3200 }
3201
3202 w->priv = dai;
3203 dai->playback_widget = w;
3204 }
3205
3206 if (dai->driver->capture.stream_name) {
3207 template.id = snd_soc_dapm_dai;
3208 template.name = dai->driver->capture.stream_name;
3209 template.sname = dai->driver->capture.stream_name;
3210
3211 dev_dbg(dai->dev, "adding %s widget\n",
3212 template.name);
3213
3214 w = snd_soc_dapm_new_control(dapm, &template);
3215 if (!w) {
3216 dev_err(dapm->dev, "Failed to create %s widget\n",
3217 dai->driver->capture.stream_name);
3218 }
3219
3220 w->priv = dai;
3221 dai->capture_widget = w;
3222 }
3223
3224 return 0;
3225}
3226
3227int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
3228{
3229 struct snd_soc_dapm_widget *dai_w, *w;
3230 struct snd_soc_dai *dai;
3231 struct snd_soc_dapm_route r;
3232
3233 memset(&r, 0, sizeof(r));
3234
3235 /* For each DAI widget... */
3236 list_for_each_entry(dai_w, &card->widgets, list) {
3237 if (dai_w->id != snd_soc_dapm_dai)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003238 continue;
Mark Brown888df392012-02-16 19:37:51 -08003239
3240 dai = dai_w->priv;
3241
3242 /* ...find all widgets with the same stream and link them */
3243 list_for_each_entry(w, &card->widgets, list) {
3244 if (w->dapm != dai_w->dapm)
3245 continue;
3246
3247 if (w->id == snd_soc_dapm_dai)
3248 continue;
3249
3250 if (!w->sname)
3251 continue;
3252
3253 if (dai->driver->playback.stream_name &&
3254 strstr(w->sname,
3255 dai->driver->playback.stream_name)) {
3256 r.source = dai->playback_widget->name;
3257 r.sink = w->name;
3258 dev_dbg(dai->dev, "%s -> %s\n",
3259 r.source, r.sink);
3260
3261 snd_soc_dapm_add_route(w->dapm, &r);
3262 }
3263
3264 if (dai->driver->capture.stream_name &&
3265 strstr(w->sname,
3266 dai->driver->capture.stream_name)) {
3267 r.source = w->name;
3268 r.sink = dai->capture_widget->name;
3269 dev_dbg(dai->dev, "%s -> %s\n",
3270 r.source, r.sink);
3271
3272 snd_soc_dapm_add_route(w->dapm, &r);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003273 }
3274 }
3275 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02003276
Mark Brown888df392012-02-16 19:37:51 -08003277 return 0;
3278}
Liam Girdwood64a648c222011-07-25 11:15:15 +01003279
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003280static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3281 int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003282{
Mark Brown7bd3a6f2012-02-16 15:03:27 -08003283
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003284 struct snd_soc_dapm_widget *w_cpu, *w_codec;
3285 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
3286 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Mark Brown7bd3a6f2012-02-16 15:03:27 -08003287
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003288 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
3289 w_cpu = cpu_dai->playback_widget;
3290 w_codec = codec_dai->playback_widget;
3291 } else {
3292 w_cpu = cpu_dai->capture_widget;
3293 w_codec = codec_dai->capture_widget;
Richard Purdie2b97eab2006-10-06 18:32:18 +02003294 }
3295
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003296 if (w_cpu) {
3297
3298 dapm_mark_dirty(w_cpu, "stream event");
3299
3300 switch (event) {
3301 case SND_SOC_DAPM_STREAM_START:
3302 w_cpu->active = 1;
3303 break;
3304 case SND_SOC_DAPM_STREAM_STOP:
3305 w_cpu->active = 0;
3306 break;
3307 case SND_SOC_DAPM_STREAM_SUSPEND:
3308 case SND_SOC_DAPM_STREAM_RESUME:
3309 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3310 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3311 break;
3312 }
3313 }
3314
3315 if (w_codec) {
3316
3317 dapm_mark_dirty(w_codec, "stream event");
3318
3319 switch (event) {
3320 case SND_SOC_DAPM_STREAM_START:
3321 w_codec->active = 1;
3322 break;
3323 case SND_SOC_DAPM_STREAM_STOP:
3324 w_codec->active = 0;
3325 break;
3326 case SND_SOC_DAPM_STREAM_SUSPEND:
3327 case SND_SOC_DAPM_STREAM_RESUME:
3328 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
3329 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
3330 break;
3331 }
3332 }
3333
3334 dapm_power_widgets(&rtd->card->dapm, event);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003335}
3336
3337/**
3338 * snd_soc_dapm_stream_event - send a stream event to the dapm core
3339 * @rtd: PCM runtime data
3340 * @stream: stream name
3341 * @event: stream event
3342 *
3343 * Sends a stream event to the dapm core. The core then makes any
3344 * necessary widget power changes.
3345 *
3346 * Returns 0 for success else error.
3347 */
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003348void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
3349 int event)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003350{
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003351 struct snd_soc_card *card = rtd->card;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003352
Liam Girdwood3cd04342012-03-09 12:02:08 +00003353 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
Liam Girdwoodd9b09512012-03-07 16:32:59 +00003354 soc_dapm_stream_event(rtd, stream, event);
Liam Girdwooda73fb2d2012-03-07 10:38:26 +00003355 mutex_unlock(&card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003356}
Richard Purdie2b97eab2006-10-06 18:32:18 +02003357
3358/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003359 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003360 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003361 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02003362 *
Mark Brown74b8f952009-06-06 11:26:15 +01003363 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01003364 * a valid audio route and active audio stream.
3365 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3366 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02003367 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003368int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003369{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003370 return snd_soc_dapm_set_pin(dapm, pin, 1);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003371}
Liam Girdwooda5302182008-07-07 13:35:17 +01003372EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003373
3374/**
Mark Brownda341832010-03-15 19:23:37 +00003375 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003376 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00003377 * @pin: pin name
3378 *
3379 * Enables input/output pin regardless of any other state. This is
3380 * intended for use with microphone bias supplies used in microphone
3381 * jack detection.
3382 *
3383 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3384 * do any widget power switching.
3385 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003386int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
3387 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00003388{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003389 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Mark Brownda341832010-03-15 19:23:37 +00003390
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003391 if (!w) {
3392 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
3393 return -EINVAL;
Mark Brownda341832010-03-15 19:23:37 +00003394 }
3395
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003396 dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
3397 w->connected = 1;
3398 w->force = 1;
Mark Brown75c1f892011-10-04 22:28:08 +01003399 dapm_mark_dirty(w, "force enable");
Mark Brown0d867332011-04-06 11:38:14 +09003400
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003401 return 0;
Mark Brownda341832010-03-15 19:23:37 +00003402}
3403EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
3404
3405/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003406 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003407 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003408 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003409 *
Mark Brown74b8f952009-06-06 11:26:15 +01003410 * Disables input/output pin and its parents or children widgets.
Liam Girdwooda5302182008-07-07 13:35:17 +01003411 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3412 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003413 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003414int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
3415 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01003416{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003417 return snd_soc_dapm_set_pin(dapm, pin, 0);
Liam Girdwooda5302182008-07-07 13:35:17 +01003418}
3419EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
3420
3421/**
Mark Brown5817b522008-09-24 11:23:11 +01003422 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003423 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01003424 * @pin: pin name
3425 *
3426 * Marks the specified pin as being not connected, disabling it along
3427 * any parent or child widgets. At present this is identical to
3428 * snd_soc_dapm_disable_pin() but in future it will be extended to do
3429 * additional things such as disabling controls which only affect
3430 * paths through the pin.
3431 *
3432 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
3433 * do any widget power switching.
3434 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003435int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01003436{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003437 return snd_soc_dapm_set_pin(dapm, pin, 0);
Mark Brown5817b522008-09-24 11:23:11 +01003438}
3439EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
3440
3441/**
Liam Girdwooda5302182008-07-07 13:35:17 +01003442 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003443 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01003444 * @pin: audio signal pin endpoint (or start point)
3445 *
3446 * Get audio pin status - connected or disconnected.
3447 *
3448 * Returns 1 for connected otherwise 0.
3449 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003450int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
3451 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003452{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003453 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003454
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003455 if (w)
3456 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06003457
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003458 return 0;
3459}
Liam Girdwooda5302182008-07-07 13:35:17 +01003460EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02003461
3462/**
Mark Brown1547aba2010-05-07 21:11:40 +01003463 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003464 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01003465 * @pin: audio signal pin endpoint (or start point)
3466 *
3467 * Mark the given endpoint or pin as ignoring suspend. When the
3468 * system is disabled a path between two endpoints flagged as ignoring
3469 * suspend will not be disabled. The path must already be enabled via
3470 * normal means at suspend time, it will not be turned on if it was not
3471 * already enabled.
3472 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003473int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
3474 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01003475{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003476 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01003477
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003478 if (!w) {
3479 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
3480 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01003481 }
3482
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02003483 w->ignore_suspend = 1;
3484
3485 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01003486}
3487EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
3488
Stephen Warren16332812011-11-23 12:42:04 -07003489static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
3490 struct snd_soc_dapm_widget *w)
3491{
3492 struct snd_soc_dapm_path *p;
3493
3494 list_for_each_entry(p, &card->paths, list) {
3495 if ((p->source == w) || (p->sink == w)) {
3496 dev_dbg(card->dev,
3497 "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
3498 p->source->name, p->source->id, p->source->dapm,
3499 p->sink->name, p->sink->id, p->sink->dapm);
3500
3501 /* Connected to something other than the codec */
3502 if (p->source->dapm != p->sink->dapm)
3503 return true;
3504 /*
3505 * Loopback connection from codec external pin to
3506 * codec external pin
3507 */
3508 if (p->sink->id == snd_soc_dapm_input) {
3509 switch (p->source->id) {
3510 case snd_soc_dapm_output:
3511 case snd_soc_dapm_micbias:
3512 return true;
3513 default:
3514 break;
3515 }
3516 }
3517 }
3518 }
3519
3520 return false;
3521}
3522
3523/**
3524 * snd_soc_dapm_auto_nc_codec_pins - call snd_soc_dapm_nc_pin for unused pins
3525 * @codec: The codec whose pins should be processed
3526 *
3527 * Automatically call snd_soc_dapm_nc_pin() for any external pins in the codec
3528 * which are unused. Pins are used if they are connected externally to the
3529 * codec, whether that be to some other device, or a loop-back connection to
3530 * the codec itself.
3531 */
3532void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec)
3533{
3534 struct snd_soc_card *card = codec->card;
3535 struct snd_soc_dapm_context *dapm = &codec->dapm;
3536 struct snd_soc_dapm_widget *w;
3537
Mark Browna094b802011-11-27 19:42:20 +00003538 dev_dbg(codec->dev, "Auto NC: DAPMs: card:%p codec:%p\n",
Stephen Warren16332812011-11-23 12:42:04 -07003539 &card->dapm, &codec->dapm);
3540
3541 list_for_each_entry(w, &card->widgets, list) {
3542 if (w->dapm != dapm)
3543 continue;
3544 switch (w->id) {
3545 case snd_soc_dapm_input:
3546 case snd_soc_dapm_output:
3547 case snd_soc_dapm_micbias:
Mark Browna094b802011-11-27 19:42:20 +00003548 dev_dbg(codec->dev, "Auto NC: Checking widget %s\n",
Stephen Warren16332812011-11-23 12:42:04 -07003549 w->name);
3550 if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
Mark Browna094b802011-11-27 19:42:20 +00003551 dev_dbg(codec->dev,
Stephen Warren16332812011-11-23 12:42:04 -07003552 "... Not in map; disabling\n");
3553 snd_soc_dapm_nc_pin(dapm, w->name);
3554 }
3555 break;
3556 default:
3557 break;
3558 }
3559 }
3560}
3561
Mark Brown1547aba2010-05-07 21:11:40 +01003562/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02003563 * snd_soc_dapm_free - free dapm resources
Peter Ujfalusi728a5222011-08-26 16:33:52 +03003564 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02003565 *
3566 * Free all dapm widgets and resources.
3567 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003568void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02003569{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003570 snd_soc_dapm_sys_remove(dapm->dev);
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02003571 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003572 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02003573 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02003574}
3575EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
3576
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003577static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01003578{
Mark Brown51737472009-06-22 13:16:51 +01003579 struct snd_soc_dapm_widget *w;
3580 LIST_HEAD(down_list);
3581 int powerdown = 0;
3582
Jarkko Nikula97c866d2010-12-14 12:18:31 +02003583 list_for_each_entry(w, &dapm->card->widgets, list) {
3584 if (w->dapm != dapm)
3585 continue;
Mark Brown51737472009-06-22 13:16:51 +01003586 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00003587 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01003588 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01003589 powerdown = 1;
3590 }
3591 }
3592
3593 /* If there were no widgets to power down we're already in
3594 * standby.
3595 */
3596 if (powerdown) {
Mark Brown7679e422012-02-22 15:52:56 +00003597 if (dapm->bias_level == SND_SOC_BIAS_ON)
3598 snd_soc_dapm_set_bias_level(dapm,
3599 SND_SOC_BIAS_PREPARE);
Mark Brown828a8422011-01-15 13:14:30 +00003600 dapm_seq_run(dapm, &down_list, 0, false);
Mark Brown7679e422012-02-22 15:52:56 +00003601 if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
3602 snd_soc_dapm_set_bias_level(dapm,
3603 SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01003604 }
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00003605}
Mark Brown51737472009-06-22 13:16:51 +01003606
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00003607/*
3608 * snd_soc_dapm_shutdown - callback for system shutdown
3609 */
3610void snd_soc_dapm_shutdown(struct snd_soc_card *card)
3611{
3612 struct snd_soc_codec *codec;
3613
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003614 list_for_each_entry(codec, &card->codec_dev_list, list) {
3615 soc_dapm_shutdown_codec(&codec->dapm);
Mark Brown7679e422012-02-22 15:52:56 +00003616 if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
3617 snd_soc_dapm_set_bias_level(&codec->dapm,
3618 SND_SOC_BIAS_OFF);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02003619 }
Mark Brown51737472009-06-22 13:16:51 +01003620}
3621
Richard Purdie2b97eab2006-10-06 18:32:18 +02003622/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01003623MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02003624MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
3625MODULE_LICENSE("GPL");