blob: 6ba168c603b6778d9e895157092d0b4bad2bce6f [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
17 * mic/meadphone insertion events.
18 * o Automatic Mic Bias support
19 * o Jack insertion power event initiation - e.g. hp insertion will enable
20 * sinks, dacs, etc
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +020021 * o Delayed powerdown of audio susbsystem to reduce pops between a quick
Richard Purdie2b97eab2006-10-06 18:32:18 +020022 * device reopen.
23 *
24 * Todo:
25 * o DAPM power change sequencing - allow for configurable per
26 * codec sequences.
27 * o Support for analogue bias optimisation.
28 * o Support for reduced codec oversampling rates.
29 * o Support for reduced codec bias currents.
30 */
31
Liam Girdwood7987a112011-01-31 19:52:42 +000032#define DEBUG
33
Richard Purdie2b97eab2006-10-06 18:32:18 +020034#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/init.h>
Mark Brown9d0624a2011-02-18 11:49:43 -080037#include <linux/async.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020038#include <linux/delay.h>
39#include <linux/pm.h>
40#include <linux/bitops.h>
41#include <linux/platform_device.h>
42#include <linux/jiffies.h>
Takashi Iwai20496ff2009-08-24 09:40:34 +020043#include <linux/debugfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090044#include <linux/slab.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020045#include <sound/core.h>
46#include <sound/pcm.h>
47#include <sound/pcm_params.h>
Liam Girdwoodce6120c2010-11-05 15:53:46 +020048#include <sound/soc.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020049#include <sound/initval.h>
50
Mark Brown84e90932010-11-04 00:07:02 -040051#include <trace/events/asoc.h>
52
Liam Girdwoodab1058a2011-01-31 20:33:07 +000053#define PATH_MAX_HOPS 16
54
Richard Purdie2b97eab2006-10-06 18:32:18 +020055/* dapm power sequences - make this per codec in the future */
56static int dapm_up_seq[] = {
Mark Brown38357ab2009-06-06 19:03:23 +010057 [snd_soc_dapm_pre] = 0,
58 [snd_soc_dapm_supply] = 1,
59 [snd_soc_dapm_micbias] = 2,
Mark Brown010ff262009-08-17 17:39:22 +010060 [snd_soc_dapm_aif_in] = 3,
61 [snd_soc_dapm_aif_out] = 3,
62 [snd_soc_dapm_mic] = 4,
63 [snd_soc_dapm_mux] = 5,
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +000064 [snd_soc_dapm_virt_mux] = 5,
Mark Brown010ff262009-08-17 17:39:22 +010065 [snd_soc_dapm_value_mux] = 5,
66 [snd_soc_dapm_dac] = 6,
67 [snd_soc_dapm_mixer] = 7,
68 [snd_soc_dapm_mixer_named_ctl] = 7,
69 [snd_soc_dapm_pga] = 8,
70 [snd_soc_dapm_adc] = 9,
Olaya, Margaritad88429a2010-12-10 21:11:44 -060071 [snd_soc_dapm_out_drv] = 10,
Mark Brown010ff262009-08-17 17:39:22 +010072 [snd_soc_dapm_hp] = 10,
73 [snd_soc_dapm_spk] = 10,
74 [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,
Olaya, Margaritad88429a2010-12-10 21:11:44 -060082 [snd_soc_dapm_out_drv] = 2,
Mark Brown38357ab2009-06-06 19:03:23 +010083 [snd_soc_dapm_pga] = 4,
84 [snd_soc_dapm_mixer_named_ctl] = 5,
Mark Browne3d4dab2009-06-07 13:08:45 +010085 [snd_soc_dapm_mixer] = 5,
86 [snd_soc_dapm_dac] = 6,
87 [snd_soc_dapm_mic] = 7,
88 [snd_soc_dapm_micbias] = 8,
89 [snd_soc_dapm_mux] = 9,
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +000090 [snd_soc_dapm_virt_mux] = 9,
Mark Browne3d4dab2009-06-07 13:08:45 +010091 [snd_soc_dapm_value_mux] = 9,
Mark Brown010ff262009-08-17 17:39:22 +010092 [snd_soc_dapm_aif_in] = 10,
93 [snd_soc_dapm_aif_out] = 10,
94 [snd_soc_dapm_supply] = 11,
95 [snd_soc_dapm_post] = 12,
Richard Purdie2b97eab2006-10-06 18:32:18 +020096};
97
Troy Kisky12ef1932008-10-13 17:42:14 -070098static void pop_wait(u32 pop_time)
Mark Brown15e4c722008-07-02 11:51:20 +010099{
100 if (pop_time)
101 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
102}
103
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200104static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
Mark Brown15e4c722008-07-02 11:51:20 +0100105{
106 va_list args;
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200107 char *buf;
108
109 if (!pop_time)
110 return;
111
112 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
113 if (buf == NULL)
114 return;
Mark Brown15e4c722008-07-02 11:51:20 +0100115
116 va_start(args, fmt);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200117 vsnprintf(buf, PAGE_SIZE, fmt, args);
Takashi Iwai9d01df02010-12-22 14:08:40 +0100118 dev_info(dev, "%s", buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100119 va_end(args);
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +0200120
121 kfree(buf);
Mark Brown15e4c722008-07-02 11:51:20 +0100122}
123
Richard Purdie2b97eab2006-10-06 18:32:18 +0200124/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +0100125static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +0200126 const struct snd_soc_dapm_widget *_widget)
127{
Takashi Iwai88cb4292007-02-05 14:56:20 +0100128 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200129}
130
Liam Girdwood7987a112011-01-31 19:52:42 +0000131static inline struct snd_card *dapm_get_card(struct snd_soc_dapm_context *dapm)
132{
133 if (dapm->codec)
134 return dapm->codec->card->snd_card;
135 else if (dapm->platform)
136 return dapm->platform->card->snd_card;
137 else
138 BUG();
139}
140
141static inline struct snd_soc_card *dapm_get_soc_card(
142 struct snd_soc_dapm_context *dapm)
143{
144 if (dapm->codec)
145 return dapm->codec->card;
146 else if (dapm->platform)
147 return dapm->platform->card;
148 else
149 BUG();
150}
151
Liam Girdwood35ca6602011-01-28 17:45:35 +0000152static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
153{
154 if (w->codec)
155 return snd_soc_read(w->codec, reg);
Liam Girdwood7987a112011-01-31 19:52:42 +0000156 else if (w->platform)
157 return snd_soc_platform_read(w->platform, reg);
Liam Girdwood35ca6602011-01-28 17:45:35 +0000158 return 0;
159}
160
161static int soc_widget_write(struct snd_soc_dapm_widget *w,int reg, int val)
162{
163 if (w->codec)
164 return snd_soc_write(w->codec, reg, val);
Liam Girdwood7987a112011-01-31 19:52:42 +0000165 else if (w->platform)
166 return snd_soc_platform_write(w->platform, reg, val);
Liam Girdwood35ca6602011-01-28 17:45:35 +0000167 return 0;
168}
169
170int soc_widget_update_bits(struct snd_soc_dapm_widget *w, unsigned short reg,
171 unsigned int mask, unsigned int value)
172{
173 int change;
174 unsigned int old, new;
175
176 old = soc_widget_read(w, reg);
177 new = (old & ~mask) | value;
178 change = old != new;
179 if (change)
180 soc_widget_write(w, reg, new);
181
182 return change;
183}
184
185int soc_widget_test_bits(struct snd_soc_dapm_widget *w, unsigned short reg,
186 unsigned int mask, unsigned int value)
187{
188 int change;
189 unsigned int old, new;
190
191 old = soc_widget_read(w, reg);
192 new = (old & ~mask) | value;
193 change = old != new;
194
195 return change;
196}
197
Liam Girdwoodab1058a2011-01-31 20:33:07 +0000198/* reset 'walked' bit for each dapm path */
199static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
200{
201 struct snd_soc_dapm_path *p;
202
203 list_for_each_entry(p, &dapm->card->paths, list)
204 p->walked = 0;
205}
206
207static void dapm_clear_paths(struct snd_soc_dapm_context *dapm)
208{
209 struct snd_soc_dapm_path *p;
210 struct snd_soc_dapm_widget *w;
211 struct list_head *l;
212
213 list_for_each(l, &dapm->paths) {
214 p = list_entry(l, struct snd_soc_dapm_path, list);
215 p->length = 0;
216 }
217 list_for_each(l, &dapm->card->widgets) {
218 w = list_entry(l, struct snd_soc_dapm_widget, list);
219 w->hops = 0;
220 }
221 dapm_clear_walk(dapm);
222}
223
224/*
225 * find all the paths between source and sink
226 */
227static int dapm_find_playback_paths (struct snd_soc_dapm_context *dapm,
228 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
229 int hops)
230{
231 struct list_head *lp;
232 struct snd_soc_dapm_path *path;
233 int dist = 0;
234
235 if (hops > PATH_MAX_HOPS)
236 return 0;
237
238 if (source == sink) {
239 dev_dbg(dapm->dev," ! %d: valid route found\n", hops);
240 dapm->num_valid_paths++;
241 return 1;
242 }
243
244 if (source->hops && source->hops <= hops)
245 return 0;
246 source->hops = hops;
247
248 /* check all the output paths on this source widget by walking
249 * from source to sink */
250 list_for_each(lp, &source->sinks) {
251 path = list_entry(lp, struct snd_soc_dapm_path, list_source);
252
253 dev_dbg(dapm->dev," %c %d: %s -> %s -> %s\n",
254 path->connect ? '*' : ' ', hops,
255 source->name, path->name, path->sink->name);
256
257 /* been here before ? */
258 if (path->length && path->length <= hops)
259 continue;
260
261 /* check down the next path if connected */
262 if (path->sink && path->connect &&
263 dapm_find_playback_paths(dapm, path->sink, sink, hops + 1)) {
264 path->length = hops;
265 if (!dist || dist > path->length)
266 dist = path->length;
267 }
268 }
269
270 return dist;
271}
272
273static int dapm_find_capture_paths (struct snd_soc_dapm_context *dapm,
274 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
275 int hops)
276{
277 struct list_head *lp;
278 struct snd_soc_dapm_path *path;
279 int dist = 0;
280
281 if (hops > PATH_MAX_HOPS)
282 return 0;
283
284 if (source == sink) {
285 dev_dbg(dapm->dev," ! %d: valid route found\n", hops);
286 dapm->num_valid_paths++;
287 return 1;
288 }
289
290 if (sink->hops && sink->hops <= hops)
291 return 0;
292 sink->hops = hops;
293
294 /* check all the output paths on this source widget by walking from
295 * sink to source */
296 list_for_each(lp, &sink->sources) {
297 path = list_entry(lp, struct snd_soc_dapm_path, list_sink);
298
299 dev_dbg(dapm->dev," %c %d: %s <- %s <- %s\n",
300 path->connect ? '*' : ' ', hops,
301 sink->name, path->name, path->source->name);
302
303 /* been here before ? */
304 if (path->length && path->length <= hops)
305 continue;
306
307 /* check down the next path if connected */
308 if (path->source && path->connect &&
309 dapm_find_capture_paths(dapm, source, path->source, hops + 1)) {
310 path->length = hops;
311 if (!dist || dist > path->length)
312 dist = path->length;
313 }
314 }
315
316 return dist;
317}
318
319/*
320 * traverse the tree from sink to source via the shortest path
321 */
322static int dapm_get_playback_paths(struct snd_soc_dapm_context *dapm,
323 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)
324{
325 dev_dbg(dapm->dev, "Playback: checking path from %s to %s\n",
326 source->name, sink->name);
327
328 dapm->num_valid_paths = 0;
329 dapm_find_playback_paths(dapm, source, sink, 1);
330 return dapm->num_valid_paths;
331}
332
333static int dapm_get_capture_paths(struct snd_soc_dapm_context *dapm,
334 struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink)
335{
336 dev_dbg(dapm->dev, "check capture path to %s from %s\n",
337 source->name, sink->name);
338
339 dapm->num_valid_paths = 0;
340 dapm_find_capture_paths(dapm, sink, source, 1);
341 return dapm->num_valid_paths;
342}
343
344/**
345 * snd_soc_dapm_query_path - query audio path
346 * @dapm: the dapm context
347 * @source_name: source widget name
348 * @sink_name: sink widget name
349 * @stream: stream direction
350 *
351 * Queries DAPM graph as to whether an valid audio stream path exists between
352 * the source and sink widgets specified. This takes into account current
353 * mixer and mux kcontrol settings.
354 *
355 * Returns the number of valid paths or negative error.
356 */
357int snd_soc_dapm_query_path(struct snd_soc_dapm_context *dapm,
358 const char *source_name, const char *sink_name, int stream)
359{
360 struct snd_soc_dapm_widget *sink = NULL, *source = NULL;
361 struct list_head *l = NULL;
362 int routes;
363
364 /* find source and sink widgets */
365 list_for_each(l, &dapm->card->widgets) {
366 struct snd_soc_dapm_widget *w =
367 list_entry(l, struct snd_soc_dapm_widget, list);
368
369 if (!source && !strcmp(w->name, source_name)) {
370 source = w;
371 continue;
372 }
373
374 if (!sink && !strcmp(w->name, sink_name))
375 sink = w;
376 }
377
378 if (!source) {
379 dev_err(dapm->dev, "can't find source widget: %s\n", source_name);
380 return -EINVAL;
381 }
382 if (!sink) {
383 dev_err(dapm->dev, "can't find sink widget: %s\n", sink_name);
384 return -EINVAL;
385 }
386
387 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
388 routes = dapm_get_playback_paths(dapm, source, sink);
389 else
390 routes = dapm_get_capture_paths(dapm, source, sink);
391
392 dapm_clear_paths(dapm);
393 return routes;
394}
395EXPORT_SYMBOL_GPL(snd_soc_dapm_query_path);
Liam Girdwood35ca6602011-01-28 17:45:35 +0000396
Mark Brown452c5ea2009-05-17 21:41:23 +0100397/**
398 * snd_soc_dapm_set_bias_level - set the bias level for the system
Mark Browned5a4c42011-02-18 11:12:42 -0800399 * @dapm: DAPM context
Mark Brown452c5ea2009-05-17 21:41:23 +0100400 * @level: level to configure
401 *
402 * Configure the bias (power) levels for the SoC audio device.
403 *
404 * Returns 0 for success else error.
405 */
Mark Browned5a4c42011-02-18 11:12:42 -0800406static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200407 enum snd_soc_bias_level level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100408{
Mark Browned5a4c42011-02-18 11:12:42 -0800409 struct snd_soc_card *card = dapm->card;
Mark Brown452c5ea2009-05-17 21:41:23 +0100410 int ret = 0;
411
Mark Brownf83fba82009-05-18 15:44:43 +0100412 switch (level) {
413 case SND_SOC_BIAS_ON:
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200414 dev_dbg(dapm->dev, "Setting full bias\n");
Mark Brownf83fba82009-05-18 15:44:43 +0100415 break;
416 case SND_SOC_BIAS_PREPARE:
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200417 dev_dbg(dapm->dev, "Setting bias prepare\n");
Mark Brownf83fba82009-05-18 15:44:43 +0100418 break;
419 case SND_SOC_BIAS_STANDBY:
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200420 dev_dbg(dapm->dev, "Setting standby bias\n");
Mark Brownf83fba82009-05-18 15:44:43 +0100421 break;
422 case SND_SOC_BIAS_OFF:
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200423 dev_dbg(dapm->dev, "Setting bias off\n");
Mark Brownf83fba82009-05-18 15:44:43 +0100424 break;
425 default:
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200426 dev_err(dapm->dev, "Setting invalid bias %d\n", level);
Mark Brownf83fba82009-05-18 15:44:43 +0100427 return -EINVAL;
428 }
429
Mark Brown84e90932010-11-04 00:07:02 -0400430 trace_snd_soc_bias_level_start(card, level);
431
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000432 if (card && card->set_bias_level)
Mark Brown452c5ea2009-05-17 21:41:23 +0100433 ret = card->set_bias_level(card, level);
Mark Brown474e09c2009-08-19 14:18:53 +0100434 if (ret == 0) {
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200435 if (dapm->codec && dapm->codec->driver->set_bias_level)
436 ret = dapm->codec->driver->set_bias_level(dapm->codec, level);
Mark Brown474e09c2009-08-19 14:18:53 +0100437 else
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200438 dapm->bias_level = level;
Mark Brown474e09c2009-08-19 14:18:53 +0100439 }
Mark Brown1badabd2010-12-04 12:41:04 +0000440 if (ret == 0) {
441 if (card && card->set_bias_level_post)
442 ret = card->set_bias_level_post(card, level);
443 }
Mark Brown452c5ea2009-05-17 21:41:23 +0100444
Mark Brown84e90932010-11-04 00:07:02 -0400445 trace_snd_soc_bias_level_done(card, level);
446
Mark Brown452c5ea2009-05-17 21:41:23 +0100447 return ret;
448}
449
Richard Purdie2b97eab2006-10-06 18:32:18 +0200450/* set up initial codec paths */
451static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
452 struct snd_soc_dapm_path *p, int i)
453{
454 switch (w->id) {
455 case snd_soc_dapm_switch:
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000456 case snd_soc_dapm_mixer:
457 case snd_soc_dapm_mixer_named_ctl: {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200458 int val;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100459 struct soc_mixer_control *mc = (struct soc_mixer_control *)
Stephen Warren82cfecd2011-04-28 17:37:58 -0600460 w->kcontrol_news[i].private_value;
Jon Smirl815ecf82008-07-29 10:22:24 -0400461 unsigned int reg = mc->reg;
462 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100463 int max = mc->max;
Jon Smirl815ecf82008-07-29 10:22:24 -0400464 unsigned int mask = (1 << fls(max)) - 1;
465 unsigned int invert = mc->invert;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200466
Liam Girdwood35ca6602011-01-28 17:45:35 +0000467 val = soc_widget_read(w, reg);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200468 val = (val >> shift) & mask;
469
470 if ((invert && !val) || (!invert && val))
471 p->connect = 1;
472 else
473 p->connect = 0;
474 }
475 break;
476 case snd_soc_dapm_mux: {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600477 struct soc_enum *e = (struct soc_enum *)
478 w->kcontrol_news[i].private_value;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200479 int val, item, bitmask;
480
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100481 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200482 ;
Liam Girdwood35ca6602011-01-28 17:45:35 +0000483 val = soc_widget_read(w, e->reg);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200484 item = (val >> e->shift_l) & (bitmask - 1);
485
486 p->connect = 0;
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100487 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200488 if (!(strcmp(p->name, e->texts[i])) && item == i)
489 p->connect = 1;
490 }
491 }
492 break;
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +0000493 case snd_soc_dapm_virt_mux: {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600494 struct soc_enum *e = (struct soc_enum *)
495 w->kcontrol_news[i].private_value;
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +0000496
497 p->connect = 0;
498 /* since a virtual mux has no backing registers to
499 * decide which path to connect, it will try to match
500 * with the first enumeration. This is to ensure
501 * that the default mux choice (the first) will be
502 * correctly powered up during initialization.
503 */
504 if (!strcmp(p->name, e->texts[0]))
505 p->connect = 1;
506 }
507 break;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200508 case snd_soc_dapm_value_mux: {
Peter Ujfalusi74155552009-01-08 13:34:29 +0200509 struct soc_enum *e = (struct soc_enum *)
Stephen Warren82cfecd2011-04-28 17:37:58 -0600510 w->kcontrol_news[i].private_value;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200511 int val, item;
512
Liam Girdwood35ca6602011-01-28 17:45:35 +0000513 val = soc_widget_read(w, e->reg);
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200514 val = (val >> e->shift_l) & e->mask;
515 for (item = 0; item < e->max; item++) {
516 if (val == e->values[item])
517 break;
518 }
519
520 p->connect = 0;
521 for (i = 0; i < e->max; i++) {
522 if (!(strcmp(p->name, e->texts[i])) && item == i)
523 p->connect = 1;
524 }
525 }
526 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200527 /* does not effect routing - always connected */
528 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -0600529 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200530 case snd_soc_dapm_output:
531 case snd_soc_dapm_adc:
532 case snd_soc_dapm_input:
533 case snd_soc_dapm_dac:
534 case snd_soc_dapm_micbias:
535 case snd_soc_dapm_vmid:
Mark Brown246d0a12009-04-22 18:24:55 +0100536 case snd_soc_dapm_supply:
Mark Brown010ff262009-08-17 17:39:22 +0100537 case snd_soc_dapm_aif_in:
538 case snd_soc_dapm_aif_out:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200539 p->connect = 1;
540 break;
541 /* does effect routing - dynamically connected */
542 case snd_soc_dapm_hp:
543 case snd_soc_dapm_mic:
544 case snd_soc_dapm_spk:
545 case snd_soc_dapm_line:
546 case snd_soc_dapm_pre:
547 case snd_soc_dapm_post:
548 p->connect = 0;
549 break;
550 }
551}
552
Mark Brown74b8f952009-06-06 11:26:15 +0100553/* connect mux widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200554static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200555 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
556 struct snd_soc_dapm_path *path, const char *control_name,
557 const struct snd_kcontrol_new *kcontrol)
558{
559 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
560 int i;
561
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100562 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200563 if (!(strcmp(control_name, e->texts[i]))) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200564 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200565 list_add(&path->list_sink, &dest->sources);
566 list_add(&path->list_source, &src->sinks);
567 path->name = (char*)e->texts[i];
568 dapm_set_path_status(dest, path, 0);
569 return 0;
570 }
571 }
572
573 return -ENODEV;
574}
575
Mark Brown74b8f952009-06-06 11:26:15 +0100576/* connect mixer widget to its interconnecting audio paths */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200577static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +0200578 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
579 struct snd_soc_dapm_path *path, const char *control_name)
580{
581 int i;
582
583 /* search for mixer kcontrol */
584 for (i = 0; i < dest->num_kcontrols; i++) {
Stephen Warren82cfecd2011-04-28 17:37:58 -0600585 if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +0200586 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200587 list_add(&path->list_sink, &dest->sources);
588 list_add(&path->list_source, &src->sinks);
Stephen Warren82cfecd2011-04-28 17:37:58 -0600589 path->name = dest->kcontrol_news[i].name;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200590 dapm_set_path_status(dest, path, i);
591 return 0;
592 }
593 }
594 return -ENODEV;
595}
596
Stephen Warrenaf468002011-04-28 17:38:01 -0600597static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
Stephen Warren1007da02011-05-26 09:57:33 -0600598 struct snd_soc_dapm_widget *kcontrolw,
Stephen Warrenaf468002011-04-28 17:38:01 -0600599 const struct snd_kcontrol_new *kcontrol_new,
600 struct snd_kcontrol **kcontrol)
601{
602 struct snd_soc_dapm_widget *w;
603 int i;
604
605 *kcontrol = NULL;
606
607 list_for_each_entry(w, &dapm->card->widgets, list) {
Stephen Warren1007da02011-05-26 09:57:33 -0600608 if (w == kcontrolw || w->dapm != kcontrolw->dapm)
609 continue;
Stephen Warrenaf468002011-04-28 17:38:01 -0600610 for (i = 0; i < w->num_kcontrols; i++) {
611 if (&w->kcontrol_news[i] == kcontrol_new) {
612 if (w->kcontrols)
613 *kcontrol = w->kcontrols[i];
614 return 1;
615 }
616 }
617 }
618
619 return 0;
620}
621
Richard Purdie2b97eab2006-10-06 18:32:18 +0200622/* create new dapm mixer control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200623static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200624{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200625 struct snd_soc_dapm_context *dapm = w->dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200626 int i, ret = 0;
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000627 size_t name_len, prefix_len;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200628 struct snd_soc_dapm_path *path;
Mark Brown12ea2c72011-03-02 18:17:32 +0000629 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000630 const char *prefix;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600631 struct snd_soc_dapm_widget_list *wlist;
632 size_t wlistsize;
Mark Brownefb7ac32011-03-08 17:23:24 +0000633
634 if (dapm->codec)
635 prefix = dapm->codec->name_prefix;
636 else
637 prefix = NULL;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200638
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000639 if (prefix)
640 prefix_len = strlen(prefix) + 1;
641 else
642 prefix_len = 0;
643
Richard Purdie2b97eab2006-10-06 18:32:18 +0200644 /* add kcontrol */
645 for (i = 0; i < w->num_kcontrols; i++) {
646
647 /* match name */
648 list_for_each_entry(path, &w->sources, list_sink) {
649
650 /* mixer/mux paths name must match control name */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600651 if (path->name != (char *)w->kcontrol_news[i].name)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200652 continue;
653
Stephen Warrenfafd2172011-04-28 17:38:00 -0600654 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
655 sizeof(struct snd_soc_dapm_widget *),
656 wlist = kzalloc(wlistsize, GFP_KERNEL);
657 if (wlist == NULL) {
658 dev_err(dapm->dev,
659 "asoc: can't allocate widget list for %s\n",
660 w->name);
661 return -ENOMEM;
662 }
663 wlist->num_widgets = 1;
664 wlist->widgets[0] = w;
665
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000666 /* add dapm control with long name.
667 * for dapm_mixer this is the concatenation of the
668 * mixer and kcontrol name.
669 * for dapm_mixer_named_ctl this is simply the
670 * kcontrol name.
671 */
Stephen Warren82cfecd2011-04-28 17:37:58 -0600672 name_len = strlen(w->kcontrol_news[i].name) + 1;
Mark Brown07495f32009-03-05 17:06:23 +0000673 if (w->id != snd_soc_dapm_mixer_named_ctl)
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000674 name_len += 1 + strlen(w->name);
675
Mark Brown219b93f2008-10-28 13:02:31 +0000676 path->long_name = kmalloc(name_len, GFP_KERNEL);
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000677
Stephen Warrenfafd2172011-04-28 17:38:00 -0600678 if (path->long_name == NULL) {
679 kfree(wlist);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200680 return -ENOMEM;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600681 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200682
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000683 switch (w->id) {
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000684 default:
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000685 /* The control will get a prefix from
686 * the control creation process but
687 * we're also using the same prefix
688 * for widgets so cut the prefix off
689 * the front of the widget name.
690 */
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000691 snprintf(path->long_name, name_len, "%s %s",
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000692 w->name + prefix_len,
Stephen Warren82cfecd2011-04-28 17:37:58 -0600693 w->kcontrol_news[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000694 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000695 case snd_soc_dapm_mixer_named_ctl:
696 snprintf(path->long_name, name_len, "%s",
Stephen Warren82cfecd2011-04-28 17:37:58 -0600697 w->kcontrol_news[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000698 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000699 }
700
Mark Brown219b93f2008-10-28 13:02:31 +0000701 path->long_name[name_len - 1] = '\0';
702
Stephen Warrenfafd2172011-04-28 17:38:00 -0600703 path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
704 wlist, path->long_name,
705 prefix);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200706 ret = snd_ctl_add(card, path->kcontrol);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200707 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200708 dev_err(dapm->dev,
709 "asoc: failed to add dapm kcontrol %s: %d\n",
710 path->long_name, ret);
Stephen Warrenfafd2172011-04-28 17:38:00 -0600711 kfree(wlist);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200712 kfree(path->long_name);
713 path->long_name = NULL;
714 return ret;
715 }
Stephen Warrenfad59882011-04-28 17:37:59 -0600716 w->kcontrols[i] = path->kcontrol;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200717 }
718 }
719 return ret;
720}
721
722/* create new dapm mux control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200723static int dapm_new_mux(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200724{
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200725 struct snd_soc_dapm_context *dapm = w->dapm;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200726 struct snd_soc_dapm_path *path = NULL;
727 struct snd_kcontrol *kcontrol;
Mark Brown12ea2c72011-03-02 18:17:32 +0000728 struct snd_card *card = dapm->card->snd_card;
Mark Brownefb7ac32011-03-08 17:23:24 +0000729 const char *prefix;
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000730 size_t prefix_len;
Stephen Warrenaf468002011-04-28 17:38:01 -0600731 int ret;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600732 struct snd_soc_dapm_widget_list *wlist;
Stephen Warrenaf468002011-04-28 17:38:01 -0600733 int shared, wlistentries;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600734 size_t wlistsize;
Stephen Warrenaf468002011-04-28 17:38:01 -0600735 char *name;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200736
Stephen Warrenaf468002011-04-28 17:38:01 -0600737 if (w->num_kcontrols != 1) {
738 dev_err(dapm->dev,
739 "asoc: mux %s has incorrect number of controls\n",
740 w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200741 return -EINVAL;
742 }
743
Stephen Warren1007da02011-05-26 09:57:33 -0600744 shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
Stephen Warrenaf468002011-04-28 17:38:01 -0600745 &kcontrol);
746 if (kcontrol) {
747 wlist = kcontrol->private_data;
748 wlistentries = wlist->num_widgets + 1;
749 } else {
750 wlist = NULL;
751 wlistentries = 1;
752 }
Stephen Warrenfafd2172011-04-28 17:38:00 -0600753 wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
Stephen Warrenaf468002011-04-28 17:38:01 -0600754 wlistentries * sizeof(struct snd_soc_dapm_widget *),
755 wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
Stephen Warrenfafd2172011-04-28 17:38:00 -0600756 if (wlist == NULL) {
757 dev_err(dapm->dev,
758 "asoc: can't allocate widget list for %s\n", w->name);
759 return -ENOMEM;
760 }
Stephen Warrenaf468002011-04-28 17:38:01 -0600761 wlist->num_widgets = wlistentries;
762 wlist->widgets[wlistentries - 1] = w;
Stephen Warrenfafd2172011-04-28 17:38:00 -0600763
Stephen Warrenaf468002011-04-28 17:38:01 -0600764 if (!kcontrol) {
Liam Girdwood4d74b362011-05-18 17:50:07 +0100765 if (dapm->codec && dapm->codec->name_prefix)
Stephen Warrenaf468002011-04-28 17:38:01 -0600766 prefix = dapm->codec->name_prefix;
767 else
Liam Girdwood4d74b362011-05-18 17:50:07 +0100768 prefix = w->name;
Mark Brownefb7ac32011-03-08 17:23:24 +0000769
Stephen Warrenaf468002011-04-28 17:38:01 -0600770 if (shared) {
771 name = w->kcontrol_news[0].name;
772 prefix_len = 0;
773 } else {
774 name = w->name;
775 if (prefix)
776 prefix_len = strlen(prefix) + 1;
777 else
778 prefix_len = 0;
779 }
Mark Brown3e5ff4d2011-03-09 11:33:09 +0000780
Stephen Warrenaf468002011-04-28 17:38:01 -0600781 /*
782 * The control will get a prefix from the control creation
783 * process but we're also using the same prefix for widgets so
784 * cut the prefix off the front of the widget name.
785 */
786 kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
787 name + prefix_len, prefix);
788 ret = snd_ctl_add(card, kcontrol);
789 if (ret < 0) {
790 dev_err(dapm->dev,
791 "asoc: failed to add kcontrol %s\n", w->name);
792 kfree(wlist);
793 return ret;
794 }
795 }
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200796
Stephen Warrenaf468002011-04-28 17:38:01 -0600797 kcontrol->private_data = wlist;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200798
Stephen Warrenfad59882011-04-28 17:37:59 -0600799 w->kcontrols[0] = kcontrol;
800
Richard Purdie2b97eab2006-10-06 18:32:18 +0200801 list_for_each_entry(path, &w->sources, list_sink)
802 path->kcontrol = kcontrol;
803
Stephen Warrenaf468002011-04-28 17:38:01 -0600804 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200805}
806
807/* create new dapm volume control */
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +0200808static int dapm_new_pga(struct snd_soc_dapm_widget *w)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200809{
Mark Browna6c65732010-03-03 17:45:21 +0000810 if (w->num_kcontrols)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200811 dev_err(w->dapm->dev,
812 "asoc: PGA controls not supported: '%s'\n", w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200813
Mark Browna6c65732010-03-03 17:45:21 +0000814 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200815}
816
Mark Brown99497882010-05-07 20:24:05 +0100817/* We implement power down on suspend by checking the power state of
818 * the ALSA card - when we are suspending the ALSA state for the card
819 * is set to D3.
820 */
821static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
822{
Mark Brown12ea2c72011-03-02 18:17:32 +0000823 int level = snd_power_get_state(widget->dapm->card->snd_card);
Mark Brown99497882010-05-07 20:24:05 +0100824
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000825 switch (level) {
Mark Brown99497882010-05-07 20:24:05 +0100826 case SNDRV_CTL_POWER_D3hot:
827 case SNDRV_CTL_POWER_D3cold:
Mark Brown1547aba2010-05-07 21:11:40 +0100828 if (widget->ignore_suspend)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +0200829 dev_dbg(widget->dapm->dev, "%s ignoring suspend\n",
830 widget->name);
Mark Brown1547aba2010-05-07 21:11:40 +0100831 return widget->ignore_suspend;
Mark Brown99497882010-05-07 20:24:05 +0100832 default:
833 return 1;
834 }
835}
836
Richard Purdie2b97eab2006-10-06 18:32:18 +0200837/*
838 * Recursively check for a completed path to an active or physically connected
839 * output widget. Returns number of complete paths.
840 */
841static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
842{
843 struct snd_soc_dapm_path *path;
844 int con = 0;
845
Mark Brown246d0a12009-04-22 18:24:55 +0100846 if (widget->id == snd_soc_dapm_supply)
847 return 0;
848
Mark Brown010ff262009-08-17 17:39:22 +0100849 switch (widget->id) {
850 case snd_soc_dapm_adc:
851 case snd_soc_dapm_aif_out:
852 if (widget->active)
Mark Brown99497882010-05-07 20:24:05 +0100853 return snd_soc_dapm_suspend_check(widget);
Mark Brown010ff262009-08-17 17:39:22 +0100854 default:
855 break;
856 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200857
858 if (widget->connected) {
859 /* connected pin ? */
860 if (widget->id == snd_soc_dapm_output && !widget->ext)
Mark Brown99497882010-05-07 20:24:05 +0100861 return snd_soc_dapm_suspend_check(widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200862
863 /* connected jack or spk ? */
864 if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
Peter Ujfalusieaeae5d2009-09-30 09:27:24 +0300865 (widget->id == snd_soc_dapm_line && !list_empty(&widget->sources)))
Mark Brown99497882010-05-07 20:24:05 +0100866 return snd_soc_dapm_suspend_check(widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200867 }
868
869 list_for_each_entry(path, &widget->sinks, list_source) {
870 if (path->walked)
871 continue;
872
873 if (path->sink && path->connect) {
874 path->walked = 1;
875 con += is_connected_output_ep(path->sink);
876 }
877 }
878
879 return con;
880}
881
882/*
883 * Recursively check for a completed path to an active or physically connected
884 * input widget. Returns number of complete paths.
885 */
886static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
887{
888 struct snd_soc_dapm_path *path;
889 int con = 0;
890
Mark Brown246d0a12009-04-22 18:24:55 +0100891 if (widget->id == snd_soc_dapm_supply)
892 return 0;
893
Richard Purdie2b97eab2006-10-06 18:32:18 +0200894 /* active stream ? */
Mark Brown010ff262009-08-17 17:39:22 +0100895 switch (widget->id) {
896 case snd_soc_dapm_dac:
897 case snd_soc_dapm_aif_in:
898 if (widget->active)
Mark Brown99497882010-05-07 20:24:05 +0100899 return snd_soc_dapm_suspend_check(widget);
Mark Brown010ff262009-08-17 17:39:22 +0100900 default:
901 break;
902 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200903
904 if (widget->connected) {
905 /* connected pin ? */
906 if (widget->id == snd_soc_dapm_input && !widget->ext)
Mark Brown99497882010-05-07 20:24:05 +0100907 return snd_soc_dapm_suspend_check(widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200908
909 /* connected VMID/Bias for lower pops */
910 if (widget->id == snd_soc_dapm_vmid)
Mark Brown99497882010-05-07 20:24:05 +0100911 return snd_soc_dapm_suspend_check(widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200912
913 /* connected jack ? */
Peter Ujfalusieaeae5d2009-09-30 09:27:24 +0300914 if (widget->id == snd_soc_dapm_mic ||
915 (widget->id == snd_soc_dapm_line && !list_empty(&widget->sinks)))
Mark Brown99497882010-05-07 20:24:05 +0100916 return snd_soc_dapm_suspend_check(widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200917 }
918
919 list_for_each_entry(path, &widget->sources, list_sink) {
920 if (path->walked)
921 continue;
922
923 if (path->source && path->connect) {
924 path->walked = 1;
925 con += is_connected_input_ep(path->source);
926 }
927 }
928
929 return con;
930}
931
932/*
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300933 * Handler for generic register modifier widget.
934 */
935int dapm_reg_event(struct snd_soc_dapm_widget *w,
936 struct snd_kcontrol *kcontrol, int event)
937{
938 unsigned int val;
939
940 if (SND_SOC_DAPM_EVENT_ON(event))
941 val = w->on_val;
942 else
943 val = w->off_val;
944
Liam Girdwood35ca6602011-01-28 17:45:35 +0000945 soc_widget_update_bits(w, -(w->reg + 1),
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300946 w->mask << w->shift, val << w->shift);
947
948 return 0;
949}
Mark Brown11589412008-07-29 11:42:23 +0100950EXPORT_SYMBOL_GPL(dapm_reg_event);
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300951
Mark Browncd0f2d42009-04-20 16:56:59 +0100952/* Generic check to see if a widget should be powered.
953 */
954static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
955{
956 int in, out;
957
958 in = is_connected_input_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200959 dapm_clear_walk(w->dapm);
Mark Browncd0f2d42009-04-20 16:56:59 +0100960 out = is_connected_output_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200961 dapm_clear_walk(w->dapm);
Mark Browncd0f2d42009-04-20 16:56:59 +0100962 return out != 0 && in != 0;
963}
964
Mark Brown6ea31b92009-04-20 17:15:41 +0100965/* Check to see if an ADC has power */
966static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
967{
968 int in;
969
970 if (w->active) {
971 in = is_connected_input_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200972 dapm_clear_walk(w->dapm);
Mark Brown6ea31b92009-04-20 17:15:41 +0100973 return in != 0;
974 } else {
975 return dapm_generic_check_power(w);
976 }
977}
978
979/* Check to see if a DAC has power */
980static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
981{
982 int out;
983
984 if (w->active) {
985 out = is_connected_output_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200986 dapm_clear_walk(w->dapm);
Mark Brown6ea31b92009-04-20 17:15:41 +0100987 return out != 0;
988 } else {
989 return dapm_generic_check_power(w);
990 }
991}
992
Mark Brown246d0a12009-04-22 18:24:55 +0100993/* Check to see if a power supply is needed */
994static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
995{
996 struct snd_soc_dapm_path *path;
997 int power = 0;
998
999 /* Check if one of our outputs is connected */
1000 list_for_each_entry(path, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001001 if (path->connected &&
1002 !path->connected(path->source, path->sink))
1003 continue;
1004
Mark Brown30173582011-02-11 11:42:19 +00001005 if (!path->sink)
1006 continue;
1007
1008 if (path->sink->force) {
1009 power = 1;
1010 break;
1011 }
1012
1013 if (path->sink->power_check &&
Mark Brown246d0a12009-04-22 18:24:55 +01001014 path->sink->power_check(path->sink)) {
1015 power = 1;
1016 break;
1017 }
1018 }
1019
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001020 dapm_clear_walk(w->dapm);
Mark Brown246d0a12009-04-22 18:24:55 +01001021
1022 return power;
1023}
1024
Mark Brown38357ab2009-06-06 19:03:23 +01001025static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
1026 struct snd_soc_dapm_widget *b,
Mark Brown828a8422011-01-15 13:14:30 +00001027 bool power_up)
Mark Brown42aa3412009-03-01 19:21:10 +00001028{
Mark Brown828a8422011-01-15 13:14:30 +00001029 int *sort;
1030
1031 if (power_up)
1032 sort = dapm_up_seq;
1033 else
1034 sort = dapm_down_seq;
1035
Mark Brown38357ab2009-06-06 19:03:23 +01001036 if (sort[a->id] != sort[b->id])
1037 return sort[a->id] - sort[b->id];
Mark Brown20e48592011-01-15 13:40:50 +00001038 if (a->subseq != b->subseq) {
1039 if (power_up)
1040 return a->subseq - b->subseq;
1041 else
1042 return b->subseq - a->subseq;
1043 }
Mark Brownb22ead22009-06-07 12:51:26 +01001044 if (a->reg != b->reg)
1045 return a->reg - b->reg;
Mark Brown84dab562010-11-12 15:28:42 +00001046 if (a->dapm != b->dapm)
1047 return (unsigned long)a->dapm - (unsigned long)b->dapm;
Mark Brown42aa3412009-03-01 19:21:10 +00001048
Mark Brown38357ab2009-06-06 19:03:23 +01001049 return 0;
1050}
Mark Brown42aa3412009-03-01 19:21:10 +00001051
Mark Brown38357ab2009-06-06 19:03:23 +01001052/* Insert a widget in order into a DAPM power sequence. */
1053static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
1054 struct list_head *list,
Mark Brown828a8422011-01-15 13:14:30 +00001055 bool power_up)
Mark Brown38357ab2009-06-06 19:03:23 +01001056{
1057 struct snd_soc_dapm_widget *w;
1058
1059 list_for_each_entry(w, list, power_list)
Mark Brown828a8422011-01-15 13:14:30 +00001060 if (dapm_seq_compare(new_widget, w, power_up) < 0) {
Mark Brown38357ab2009-06-06 19:03:23 +01001061 list_add_tail(&new_widget->power_list, &w->power_list);
1062 return;
Mark Brown42aa3412009-03-01 19:21:10 +00001063 }
Mark Brown6ea31b92009-04-20 17:15:41 +01001064
Mark Brown38357ab2009-06-06 19:03:23 +01001065 list_add_tail(&new_widget->power_list, list);
1066}
Mark Brown42aa3412009-03-01 19:21:10 +00001067
Mark Brown68f89ad2010-11-03 23:51:49 -04001068static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
1069 struct snd_soc_dapm_widget *w, int event)
1070{
1071 struct snd_soc_card *card = dapm->card;
1072 const char *ev_name;
1073 int power, ret;
1074
1075 switch (event) {
1076 case SND_SOC_DAPM_PRE_PMU:
1077 ev_name = "PRE_PMU";
1078 power = 1;
1079 break;
1080 case SND_SOC_DAPM_POST_PMU:
1081 ev_name = "POST_PMU";
1082 power = 1;
1083 break;
1084 case SND_SOC_DAPM_PRE_PMD:
1085 ev_name = "PRE_PMD";
1086 power = 0;
1087 break;
1088 case SND_SOC_DAPM_POST_PMD:
1089 ev_name = "POST_PMD";
1090 power = 0;
1091 break;
1092 default:
1093 BUG();
1094 return;
1095 }
1096
1097 if (w->power != power)
1098 return;
1099
1100 if (w->event && (w->event_flags & event)) {
1101 pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
1102 w->name, ev_name);
Mark Brown84e90932010-11-04 00:07:02 -04001103 trace_snd_soc_dapm_widget_event_start(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001104 ret = w->event(w, NULL, event);
Mark Brown84e90932010-11-04 00:07:02 -04001105 trace_snd_soc_dapm_widget_event_done(w, event);
Mark Brown68f89ad2010-11-03 23:51:49 -04001106 if (ret < 0)
1107 pr_err("%s: %s event failed: %d\n",
1108 ev_name, w->name, ret);
1109 }
1110}
1111
Mark Brownb22ead22009-06-07 12:51:26 +01001112/* Apply the coalesced changes from a DAPM sequence */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001113static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
Mark Brownb22ead22009-06-07 12:51:26 +01001114 struct list_head *pending)
Mark Brown163cac02009-06-07 10:12:52 +01001115{
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001116 struct snd_soc_card *card = dapm->card;
Liam Girdwoodecc1a0d2011-02-16 16:24:17 +00001117 struct snd_soc_dapm_widget *w, *_w;
Mark Brown68f89ad2010-11-03 23:51:49 -04001118 int reg, power;
Mark Brownb22ead22009-06-07 12:51:26 +01001119 unsigned int value = 0;
1120 unsigned int mask = 0;
1121 unsigned int cur_mask;
1122
Liam Girdwoodecc1a0d2011-02-16 16:24:17 +00001123 _w = list_first_entry(pending, struct snd_soc_dapm_widget,
1124 power_list);
1125 reg = _w->reg;
Mark Brownb22ead22009-06-07 12:51:26 +01001126
1127 list_for_each_entry(w, pending, power_list) {
1128 cur_mask = 1 << w->shift;
1129 BUG_ON(reg != w->reg);
1130
1131 if (w->invert)
1132 power = !w->power;
1133 else
1134 power = w->power;
1135
1136 mask |= cur_mask;
1137 if (power)
1138 value |= cur_mask;
1139
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001140 pop_dbg(dapm->dev, card->pop_time,
Mark Brownb22ead22009-06-07 12:51:26 +01001141 "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
1142 w->name, reg, value, mask);
Mark Brown81628102009-06-07 13:21:24 +01001143
Mark Brown68f89ad2010-11-03 23:51:49 -04001144 /* Check for events */
1145 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
1146 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001147 }
1148
Mark Brown81628102009-06-07 13:21:24 +01001149 if (reg >= 0) {
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001150 pop_dbg(dapm->dev, card->pop_time,
Mark Brown81628102009-06-07 13:21:24 +01001151 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001152 value, mask, reg, card->pop_time);
1153 pop_wait(card->pop_time);
Liam Girdwoodecc1a0d2011-02-16 16:24:17 +00001154 soc_widget_update_bits(_w, reg, mask, value);
Mark Brown81628102009-06-07 13:21:24 +01001155 }
1156
1157 list_for_each_entry(w, pending, power_list) {
Mark Brown68f89ad2010-11-03 23:51:49 -04001158 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
1159 dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
Mark Brown42aa3412009-03-01 19:21:10 +00001160 }
Mark Brown42aa3412009-03-01 19:21:10 +00001161}
1162
Mark Brownb22ead22009-06-07 12:51:26 +01001163/* Apply a DAPM power sequence.
1164 *
1165 * We walk over a pre-sorted list of widgets to apply power to. In
1166 * order to minimise the number of writes to the device required
1167 * multiple widgets will be updated in a single write where possible.
1168 * Currently anything that requires more than a single write is not
1169 * handled.
1170 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001171static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
Mark Brown828a8422011-01-15 13:14:30 +00001172 struct list_head *list, int event, bool power_up)
Mark Brownb22ead22009-06-07 12:51:26 +01001173{
1174 struct snd_soc_dapm_widget *w, *n;
1175 LIST_HEAD(pending);
1176 int cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001177 int cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001178 int cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001179 struct snd_soc_dapm_context *cur_dapm = NULL;
Mark Brown474b62d2011-01-18 16:14:44 +00001180 int ret, i;
Mark Brown828a8422011-01-15 13:14:30 +00001181 int *sort;
1182
1183 if (power_up)
1184 sort = dapm_up_seq;
1185 else
1186 sort = dapm_down_seq;
Mark Brown163cac02009-06-07 10:12:52 +01001187
Mark Brownb22ead22009-06-07 12:51:26 +01001188 list_for_each_entry_safe(w, n, list, power_list) {
1189 ret = 0;
1190
1191 /* Do we need to apply any queued changes? */
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001192 if (sort[w->id] != cur_sort || w->reg != cur_reg ||
Mark Brown20e48592011-01-15 13:40:50 +00001193 w->dapm != cur_dapm || w->subseq != cur_subseq) {
Mark Brownb22ead22009-06-07 12:51:26 +01001194 if (!list_empty(&pending))
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001195 dapm_seq_run_coalesced(cur_dapm, &pending);
Mark Brownb22ead22009-06-07 12:51:26 +01001196
Mark Brown474b62d2011-01-18 16:14:44 +00001197 if (cur_dapm && cur_dapm->seq_notifier) {
1198 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1199 if (sort[i] == cur_sort)
1200 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001201 i,
1202 cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001203 }
1204
Mark Brownb22ead22009-06-07 12:51:26 +01001205 INIT_LIST_HEAD(&pending);
1206 cur_sort = -1;
Mark Brown20e48592011-01-15 13:40:50 +00001207 cur_subseq = -1;
Mark Brownb22ead22009-06-07 12:51:26 +01001208 cur_reg = SND_SOC_NOPM;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001209 cur_dapm = NULL;
Mark Brownb22ead22009-06-07 12:51:26 +01001210 }
1211
Mark Brown163cac02009-06-07 10:12:52 +01001212 switch (w->id) {
1213 case snd_soc_dapm_pre:
1214 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001215 list_for_each_entry_safe_continue(w, n, list,
1216 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001217
Mark Brownb22ead22009-06-07 12:51:26 +01001218 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001219 ret = w->event(w,
1220 NULL, SND_SOC_DAPM_PRE_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001221 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001222 ret = w->event(w,
1223 NULL, SND_SOC_DAPM_PRE_PMD);
Mark Brown163cac02009-06-07 10:12:52 +01001224 break;
1225
1226 case snd_soc_dapm_post:
1227 if (!w->event)
Mark Brownb22ead22009-06-07 12:51:26 +01001228 list_for_each_entry_safe_continue(w, n, list,
1229 power_list);
Mark Brown163cac02009-06-07 10:12:52 +01001230
Mark Brownb22ead22009-06-07 12:51:26 +01001231 if (event == SND_SOC_DAPM_STREAM_START)
Mark Brown163cac02009-06-07 10:12:52 +01001232 ret = w->event(w,
1233 NULL, SND_SOC_DAPM_POST_PMU);
Mark Brownb22ead22009-06-07 12:51:26 +01001234 else if (event == SND_SOC_DAPM_STREAM_STOP)
Mark Brown163cac02009-06-07 10:12:52 +01001235 ret = w->event(w,
1236 NULL, SND_SOC_DAPM_POST_PMD);
Mark Brownb22ead22009-06-07 12:51:26 +01001237 break;
1238
Mark Brown163cac02009-06-07 10:12:52 +01001239 default:
Mark Brown81628102009-06-07 13:21:24 +01001240 /* Queue it up for application */
1241 cur_sort = sort[w->id];
Mark Brown20e48592011-01-15 13:40:50 +00001242 cur_subseq = w->subseq;
Mark Brown81628102009-06-07 13:21:24 +01001243 cur_reg = w->reg;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001244 cur_dapm = w->dapm;
Mark Brown81628102009-06-07 13:21:24 +01001245 list_move(&w->power_list, &pending);
1246 break;
Mark Brown163cac02009-06-07 10:12:52 +01001247 }
Mark Brownb22ead22009-06-07 12:51:26 +01001248
1249 if (ret < 0)
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02001250 dev_err(w->dapm->dev,
1251 "Failed to apply widget power: %d\n", ret);
Mark Brown163cac02009-06-07 10:12:52 +01001252 }
Mark Brownb22ead22009-06-07 12:51:26 +01001253
1254 if (!list_empty(&pending))
Mark Brown28e86802011-03-08 19:29:53 +00001255 dapm_seq_run_coalesced(cur_dapm, &pending);
Mark Brown474b62d2011-01-18 16:14:44 +00001256
1257 if (cur_dapm && cur_dapm->seq_notifier) {
1258 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
1259 if (sort[i] == cur_sort)
1260 cur_dapm->seq_notifier(cur_dapm,
Mark Brownf85a9e02011-01-26 21:41:28 +00001261 i, cur_subseq);
Mark Brown474b62d2011-01-18 16:14:44 +00001262 }
Mark Brown163cac02009-06-07 10:12:52 +01001263}
1264
Mark Brown97404f22010-12-14 16:13:57 +00001265static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
1266{
1267 struct snd_soc_dapm_update *update = dapm->update;
1268 struct snd_soc_dapm_widget *w;
1269 int ret;
1270
1271 if (!update)
1272 return;
1273
1274 w = update->widget;
1275
1276 if (w->event &&
1277 (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1278 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1279 if (ret != 0)
1280 pr_err("%s DAPM pre-event failed: %d\n",
1281 w->name, ret);
1282 }
1283
1284 ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
1285 update->val);
1286 if (ret < 0)
1287 pr_err("%s DAPM update failed: %d\n", w->name, ret);
1288
1289 if (w->event &&
1290 (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1291 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1292 if (ret != 0)
1293 pr_err("%s DAPM post-event failed: %d\n",
1294 w->name, ret);
1295 }
1296}
1297
Mark Brown9d0624a2011-02-18 11:49:43 -08001298/* Async callback run prior to DAPM sequences - brings to _PREPARE if
1299 * they're changing state.
1300 */
1301static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1302{
1303 struct snd_soc_dapm_context *d = data;
1304 int ret;
Mark Brown97404f22010-12-14 16:13:57 +00001305
Mark Brown9d0624a2011-02-18 11:49:43 -08001306 if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) {
1307 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1308 if (ret != 0)
1309 dev_err(d->dev,
1310 "Failed to turn on bias: %d\n", ret);
1311 }
1312
1313 /* If we're changing to all on or all off then prepare */
1314 if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) ||
1315 (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
1316 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1317 if (ret != 0)
1318 dev_err(d->dev,
1319 "Failed to prepare bias: %d\n", ret);
1320 }
1321}
1322
1323/* Async callback run prior to DAPM sequences - brings to their final
1324 * state.
1325 */
1326static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1327{
1328 struct snd_soc_dapm_context *d = data;
1329 int ret;
1330
1331 /* If we just powered the last thing off drop to standby bias */
1332 if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) {
1333 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1334 if (ret != 0)
1335 dev_err(d->dev, "Failed to apply standby bias: %d\n",
1336 ret);
1337 }
1338
1339 /* If we're in standby and can support bias off then do that */
1340 if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) {
1341 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1342 if (ret != 0)
1343 dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
1344 }
1345
1346 /* If we just powered up then move to active bias */
1347 if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) {
1348 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1349 if (ret != 0)
1350 dev_err(d->dev, "Failed to apply active bias: %d\n",
1351 ret);
1352 }
1353}
Mark Brown97404f22010-12-14 16:13:57 +00001354
Mark Brown42aa3412009-03-01 19:21:10 +00001355/*
Richard Purdie2b97eab2006-10-06 18:32:18 +02001356 * Scan each dapm widget for complete audio path.
1357 * A complete path is a route that has valid endpoints i.e.:-
1358 *
1359 * o DAC to output pin.
1360 * o Input Pin to ADC.
1361 * o Input pin to Output pin (bypass, sidetone)
1362 * o DAC to ADC (loopback).
1363 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001364static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001365{
Mark Brown12ea2c72011-03-02 18:17:32 +00001366 struct snd_soc_card *card = dapm->card;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001367 struct snd_soc_dapm_widget *w;
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001368 struct snd_soc_dapm_context *d;
Mark Brown291f3bb2009-06-07 13:57:17 +01001369 LIST_HEAD(up_list);
1370 LIST_HEAD(down_list);
Mark Brown9d0624a2011-02-18 11:49:43 -08001371 LIST_HEAD(async_domain);
Mark Brown38357ab2009-06-06 19:03:23 +01001372 int power;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001373
Mark Brown84e90932010-11-04 00:07:02 -04001374 trace_snd_soc_dapm_start(card);
1375
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001376 list_for_each_entry(d, &card->dapm_list, list)
Jarkko Nikulaea77b942011-05-26 16:32:18 +03001377 if (d->n_widgets || d->codec == NULL)
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001378 d->dev_power = 0;
1379
Mark Brown6d3ddc82009-05-16 17:47:29 +01001380 /* Check which widgets we need to power and store them in
1381 * lists indicating if they should be powered up or down.
1382 */
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001383 list_for_each_entry(w, &card->widgets, list) {
Mark Brown6d3ddc82009-05-16 17:47:29 +01001384 switch (w->id) {
1385 case snd_soc_dapm_pre:
Mark Brown828a8422011-01-15 13:14:30 +00001386 dapm_seq_insert(w, &down_list, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001387 break;
1388 case snd_soc_dapm_post:
Mark Brown828a8422011-01-15 13:14:30 +00001389 dapm_seq_insert(w, &up_list, true);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001390 break;
1391
1392 default:
1393 if (!w->power_check)
1394 continue;
1395
Mark Brown99497882010-05-07 20:24:05 +01001396 if (!w->force)
Mark Brown50b6bce2009-11-23 13:11:53 +00001397 power = w->power_check(w);
Mark Brown99497882010-05-07 20:24:05 +01001398 else
1399 power = 1;
1400 if (power)
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001401 w->dapm->dev_power = 1;
Mark Brown452c5ea2009-05-17 21:41:23 +01001402
Mark Brown6d3ddc82009-05-16 17:47:29 +01001403 if (w->power == power)
1404 continue;
1405
Mark Brown84e90932010-11-04 00:07:02 -04001406 trace_snd_soc_dapm_widget_power(w, power);
1407
Mark Brown6d3ddc82009-05-16 17:47:29 +01001408 if (power)
Mark Brown828a8422011-01-15 13:14:30 +00001409 dapm_seq_insert(w, &up_list, true);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001410 else
Mark Brown828a8422011-01-15 13:14:30 +00001411 dapm_seq_insert(w, &down_list, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001412
1413 w->power = power;
1414 break;
1415 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001416 }
1417
Mark Brownb14b76a2009-08-17 11:55:38 +01001418 /* If there are no DAPM widgets then try to figure out power from the
1419 * event type.
1420 */
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001421 if (!dapm->n_widgets) {
Mark Brownb14b76a2009-08-17 11:55:38 +01001422 switch (event) {
1423 case SND_SOC_DAPM_STREAM_START:
1424 case SND_SOC_DAPM_STREAM_RESUME:
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001425 dapm->dev_power = 1;
Mark Brownb14b76a2009-08-17 11:55:38 +01001426 break;
Jarkko Nikula862af8a2010-12-10 20:53:55 +02001427 case SND_SOC_DAPM_STREAM_STOP:
Liam Girdwood7987a112011-01-31 19:52:42 +00001428#warning need re-work
1429 if (dapm->codec)
1430 dapm->dev_power = !!dapm->codec->active;
1431 else
1432 dapm->dev_power = 0;
Jarkko Nikula862af8a2010-12-10 20:53:55 +02001433 break;
Mark Brown50b6bce2009-11-23 13:11:53 +00001434 case SND_SOC_DAPM_STREAM_SUSPEND:
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001435 dapm->dev_power = 0;
Mark Brown50b6bce2009-11-23 13:11:53 +00001436 break;
Mark Brownb14b76a2009-08-17 11:55:38 +01001437 case SND_SOC_DAPM_STREAM_NOP:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001438 switch (dapm->bias_level) {
Mark Browna96ca332010-01-19 22:49:43 +00001439 case SND_SOC_BIAS_STANDBY:
1440 case SND_SOC_BIAS_OFF:
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001441 dapm->dev_power = 0;
Mark Browna96ca332010-01-19 22:49:43 +00001442 break;
1443 default:
Jarkko Nikula7be31be82010-12-14 12:18:32 +02001444 dapm->dev_power = 1;
Mark Browna96ca332010-01-19 22:49:43 +00001445 break;
1446 }
Mark Brown50b6bce2009-11-23 13:11:53 +00001447 break;
Mark Brownb14b76a2009-08-17 11:55:38 +01001448 default:
1449 break;
1450 }
1451 }
1452
Mark Brown52ba67b2011-04-04 21:05:11 +09001453 /* Force all contexts in the card to the same bias state */
1454 power = 0;
1455 list_for_each_entry(d, &card->dapm_list, list)
1456 if (d->dev_power)
1457 power = 1;
1458 list_for_each_entry(d, &card->dapm_list, list)
1459 d->dev_power = power;
1460
1461
Mark Brown9d0624a2011-02-18 11:49:43 -08001462 /* Run all the bias changes in parallel */
1463 list_for_each_entry(d, &dapm->card->dapm_list, list)
1464 async_schedule_domain(dapm_pre_sequence_async, d,
1465 &async_domain);
1466 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001467
Mark Brown6d3ddc82009-05-16 17:47:29 +01001468 /* Power down widgets first; try to avoid amplifying pops. */
Mark Brown828a8422011-01-15 13:14:30 +00001469 dapm_seq_run(dapm, &down_list, event, false);
Mark Brown6d3ddc82009-05-16 17:47:29 +01001470
Mark Brown97404f22010-12-14 16:13:57 +00001471 dapm_widget_update(dapm);
1472
Mark Brown6d3ddc82009-05-16 17:47:29 +01001473 /* Now power up. */
Mark Brown828a8422011-01-15 13:14:30 +00001474 dapm_seq_run(dapm, &up_list, event, true);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001475
Mark Brown9d0624a2011-02-18 11:49:43 -08001476 /* Run all the bias changes in parallel */
1477 list_for_each_entry(d, &dapm->card->dapm_list, list)
1478 async_schedule_domain(dapm_post_sequence_async, d,
1479 &async_domain);
1480 async_synchronize_full_domain(&async_domain);
Mark Brown452c5ea2009-05-17 21:41:23 +01001481
Jarkko Nikulafd8d3bc2010-11-09 14:40:28 +02001482 pop_dbg(dapm->dev, card->pop_time,
1483 "DAPM sequencing finished, waiting %dms\n", card->pop_time);
Jarkko Nikula3a45b862010-11-05 20:35:21 +02001484 pop_wait(card->pop_time);
Mark Browncb507e72009-07-08 18:54:57 +01001485
Mark Brown84e90932010-11-04 00:07:02 -04001486 trace_snd_soc_dapm_done(card);
1487
Mark Brown42aa3412009-03-01 19:21:10 +00001488 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001489}
1490
Mark Brown79fb9382009-08-21 16:38:13 +01001491#ifdef CONFIG_DEBUG_FS
1492static int dapm_widget_power_open_file(struct inode *inode, struct file *file)
1493{
1494 file->private_data = inode->i_private;
1495 return 0;
1496}
1497
1498static ssize_t dapm_widget_power_read_file(struct file *file,
1499 char __user *user_buf,
1500 size_t count, loff_t *ppos)
1501{
1502 struct snd_soc_dapm_widget *w = file->private_data;
1503 char *buf;
1504 int in, out;
1505 ssize_t ret;
1506 struct snd_soc_dapm_path *p = NULL;
1507
1508 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
1509 if (!buf)
1510 return -ENOMEM;
1511
1512 in = is_connected_input_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001513 dapm_clear_walk(w->dapm);
Mark Brown79fb9382009-08-21 16:38:13 +01001514 out = is_connected_output_ep(w);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001515 dapm_clear_walk(w->dapm);
Mark Brown79fb9382009-08-21 16:38:13 +01001516
Mark Brownd033c362009-12-04 15:25:56 +00001517 ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d",
Mark Brown79fb9382009-08-21 16:38:13 +01001518 w->name, w->power ? "On" : "Off", in, out);
1519
Mark Brownd033c362009-12-04 15:25:56 +00001520 if (w->reg >= 0)
1521 ret += snprintf(buf + ret, PAGE_SIZE - ret,
1522 " - R%d(0x%x) bit %d",
1523 w->reg, w->reg, w->shift);
1524
1525 ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
1526
Mark Brown3eef08b2009-09-14 16:49:00 +01001527 if (w->sname)
1528 ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
1529 w->sname,
1530 w->active ? "active" : "inactive");
Mark Brown79fb9382009-08-21 16:38:13 +01001531
1532 list_for_each_entry(p, &w->sources, list_sink) {
Mark Brown215edda2009-09-08 18:59:05 +01001533 if (p->connected && !p->connected(w, p->sink))
1534 continue;
1535
Mark Brown79fb9382009-08-21 16:38:13 +01001536 if (p->connect)
1537 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001538 " in \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001539 p->name ? p->name : "static",
1540 p->source->name);
1541 }
1542 list_for_each_entry(p, &w->sinks, list_source) {
Mark Brown215edda2009-09-08 18:59:05 +01001543 if (p->connected && !p->connected(w, p->sink))
1544 continue;
1545
Mark Brown79fb9382009-08-21 16:38:13 +01001546 if (p->connect)
1547 ret += snprintf(buf + ret, PAGE_SIZE - ret,
Dimitris Papastamos67f5ed62011-02-24 17:09:32 +00001548 " out \"%s\" \"%s\"\n",
Mark Brown79fb9382009-08-21 16:38:13 +01001549 p->name ? p->name : "static",
1550 p->sink->name);
1551 }
1552
1553 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
1554
1555 kfree(buf);
1556 return ret;
1557}
1558
1559static const struct file_operations dapm_widget_power_fops = {
1560 .open = dapm_widget_power_open_file,
1561 .read = dapm_widget_power_read_file,
Arnd Bergmann6038f372010-08-15 18:52:59 +02001562 .llseek = default_llseek,
Mark Brown79fb9382009-08-21 16:38:13 +01001563};
1564
Mark Brownef49e4f2011-04-04 20:48:13 +09001565static int dapm_bias_open_file(struct inode *inode, struct file *file)
1566{
1567 file->private_data = inode->i_private;
1568 return 0;
1569}
1570
1571static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
1572 size_t count, loff_t *ppos)
1573{
1574 struct snd_soc_dapm_context *dapm = file->private_data;
1575 char *level;
1576
1577 switch (dapm->bias_level) {
1578 case SND_SOC_BIAS_ON:
1579 level = "On\n";
1580 break;
1581 case SND_SOC_BIAS_PREPARE:
1582 level = "Prepare\n";
1583 break;
1584 case SND_SOC_BIAS_STANDBY:
1585 level = "Standby\n";
1586 break;
1587 case SND_SOC_BIAS_OFF:
1588 level = "Off\n";
1589 break;
1590 default:
1591 BUG();
1592 level = "Unknown\n";
1593 break;
1594 }
1595
1596 return simple_read_from_buffer(user_buf, count, ppos, level,
1597 strlen(level));
1598}
1599
1600static const struct file_operations dapm_bias_fops = {
1601 .open = dapm_bias_open_file,
1602 .read = dapm_bias_read_file,
1603 .llseek = default_llseek,
1604};
1605
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001606void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1607 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001608{
Mark Brown79fb9382009-08-21 16:38:13 +01001609 struct dentry *d;
1610
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001611 dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);
1612
1613 if (!dapm->debugfs_dapm) {
1614 printk(KERN_WARNING
1615 "Failed to create DAPM debugfs directory\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001616 return;
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001617 }
Mark Brown79fb9382009-08-21 16:38:13 +01001618
Mark Brownef49e4f2011-04-04 20:48:13 +09001619 d = debugfs_create_file("bias_level", 0444,
1620 dapm->debugfs_dapm, dapm,
1621 &dapm_bias_fops);
1622 if (!d)
1623 dev_warn(dapm->dev,
1624 "ASoC: Failed to create bias level debugfs file\n");
Mark Brown79fb9382009-08-21 16:38:13 +01001625}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001626
1627static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1628{
1629 struct snd_soc_dapm_context *dapm = w->dapm;
1630 struct dentry *d;
1631
1632 if (!dapm->debugfs_dapm || !w->name)
1633 return;
1634
1635 d = debugfs_create_file(w->name, 0444,
1636 dapm->debugfs_dapm, w,
1637 &dapm_widget_power_fops);
1638 if (!d)
1639 dev_warn(w->dapm->dev,
1640 "ASoC: Failed to create %s debugfs file\n",
1641 w->name);
1642}
1643
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001644static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1645{
1646 debugfs_remove_recursive(dapm->debugfs_dapm);
1647}
1648
Mark Brown79fb9382009-08-21 16:38:13 +01001649#else
Lars-Peter Clausen8eecaf62011-04-30 19:45:48 +02001650void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
1651 struct dentry *parent)
Mark Brown79fb9382009-08-21 16:38:13 +01001652{
1653}
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02001654
1655static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
1656{
1657}
1658
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02001659static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1660{
1661}
1662
Mark Brown79fb9382009-08-21 16:38:13 +01001663#endif
1664
Richard Purdie2b97eab2006-10-06 18:32:18 +02001665/* test and update the power status of a mux widget */
Adrian Bunkd9c96cf2006-11-28 12:10:09 +01001666static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
Mark Brown3a655772009-10-05 17:23:30 +01001667 struct snd_kcontrol *kcontrol, int change,
1668 int mux, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001669{
1670 struct snd_soc_dapm_path *path;
1671 int found = 0;
1672
Peter Ujfalusieff317d2009-01-15 14:40:47 +02001673 if (widget->id != snd_soc_dapm_mux &&
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00001674 widget->id != snd_soc_dapm_virt_mux &&
Peter Ujfalusieff317d2009-01-15 14:40:47 +02001675 widget->id != snd_soc_dapm_value_mux)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001676 return -ENODEV;
1677
Mark Brown3a655772009-10-05 17:23:30 +01001678 if (!change)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001679 return 0;
1680
1681 /* find dapm widget path assoc with kcontrol */
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001682 list_for_each_entry(path, &widget->dapm->card->paths, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001683 if (path->kcontrol != kcontrol)
1684 continue;
1685
Richard Zhaocb01e2b2008-10-07 08:05:20 +08001686 if (!path->name || !e->texts[mux])
Richard Purdie2b97eab2006-10-06 18:32:18 +02001687 continue;
1688
1689 found = 1;
1690 /* we now need to match the string in the enum to the path */
Richard Zhaocb01e2b2008-10-07 08:05:20 +08001691 if (!(strcmp(path->name, e->texts[mux])))
Richard Purdie2b97eab2006-10-06 18:32:18 +02001692 path->connect = 1; /* new connection */
1693 else
1694 path->connect = 0; /* old connection must be powered down */
1695 }
1696
Mark Brownb91b8fa2010-01-20 18:18:35 +00001697 if (found)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001698 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001699
1700 return 0;
1701}
Richard Purdie2b97eab2006-10-06 18:32:18 +02001702
Milan plzik1b075e32008-01-10 14:39:46 +01001703/* test and update the power status of a mixer or switch widget */
Adrian Bunkd9c96cf2006-11-28 12:10:09 +01001704static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
Mark Brown283375c2009-12-07 18:09:03 +00001705 struct snd_kcontrol *kcontrol, int connect)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001706{
1707 struct snd_soc_dapm_path *path;
1708 int found = 0;
1709
Milan plzik1b075e32008-01-10 14:39:46 +01001710 if (widget->id != snd_soc_dapm_mixer &&
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001711 widget->id != snd_soc_dapm_mixer_named_ctl &&
Milan plzik1b075e32008-01-10 14:39:46 +01001712 widget->id != snd_soc_dapm_switch)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001713 return -ENODEV;
1714
Richard Purdie2b97eab2006-10-06 18:32:18 +02001715 /* find dapm widget path assoc with kcontrol */
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001716 list_for_each_entry(path, &widget->dapm->card->paths, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001717 if (path->kcontrol != kcontrol)
1718 continue;
1719
1720 /* found, now check type */
1721 found = 1;
Mark Brown283375c2009-12-07 18:09:03 +00001722 path->connect = connect;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001723 break;
1724 }
1725
Mark Brownb91b8fa2010-01-20 18:18:35 +00001726 if (found)
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001727 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001728
1729 return 0;
1730}
Richard Purdie2b97eab2006-10-06 18:32:18 +02001731
1732/* show dapm widget status in sys fs */
Liam Girdwood7987a112011-01-31 19:52:42 +00001733static ssize_t widget_show(struct snd_soc_dapm_context *dapm,
1734 const char *name, char *buf, ssize_t count)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001735{
Richard Purdie2b97eab2006-10-06 18:32:18 +02001736 struct snd_soc_dapm_widget *w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001737 char *state = "not set";
1738
Liam Girdwood7987a112011-01-31 19:52:42 +00001739 count += sprintf(buf + count, "\n%s\n", name);
1740
Liam Girdwoodab1058a2011-01-31 20:33:07 +00001741 list_for_each_entry(w, &dapm->card->widgets, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001742
1743 /* only display widgets that burnm power */
1744 switch (w->id) {
1745 case snd_soc_dapm_hp:
1746 case snd_soc_dapm_mic:
1747 case snd_soc_dapm_spk:
1748 case snd_soc_dapm_line:
1749 case snd_soc_dapm_micbias:
1750 case snd_soc_dapm_dac:
1751 case snd_soc_dapm_adc:
1752 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06001753 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001754 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001755 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +01001756 case snd_soc_dapm_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001757 if (w->name)
1758 count += sprintf(buf + count, "%s: %s\n",
1759 w->name, w->power ? "On":"Off");
1760 break;
1761 default:
1762 break;
1763 }
1764 }
1765
Liam Girdwood7987a112011-01-31 19:52:42 +00001766 switch (dapm->bias_level) {
Mark Brown0be98982008-05-19 12:31:28 +02001767 case SND_SOC_BIAS_ON:
1768 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001769 break;
Mark Brown0be98982008-05-19 12:31:28 +02001770 case SND_SOC_BIAS_PREPARE:
1771 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001772 break;
Mark Brown0be98982008-05-19 12:31:28 +02001773 case SND_SOC_BIAS_STANDBY:
1774 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001775 break;
Mark Brown0be98982008-05-19 12:31:28 +02001776 case SND_SOC_BIAS_OFF:
1777 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +02001778 break;
1779 }
1780 count += sprintf(buf + count, "PM State: %s\n", state);
1781
1782 return count;
1783}
1784
Liam Girdwood7987a112011-01-31 19:52:42 +00001785/* show dapm widget status in sys fs */
1786static ssize_t dapm_widget_show(struct device *dev,
1787 struct device_attribute *attr, char *buf)
1788{
1789 struct snd_soc_pcm_runtime *rtd =
1790 container_of(dev, struct snd_soc_pcm_runtime, dev);
1791 struct snd_soc_codec *codec = rtd->codec;
1792 struct snd_soc_platform *platform = rtd->platform;
1793 ssize_t count = 0;
1794
1795 count += widget_show(&codec->dapm, codec->name, buf, count);
1796 count += widget_show(&platform->dapm, platform->name, buf, count);
1797 return count;
1798}
1799
Richard Purdie2b97eab2006-10-06 18:32:18 +02001800static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
1801
1802int snd_soc_dapm_sys_add(struct device *dev)
1803{
Troy Kisky12ef1932008-10-13 17:42:14 -07001804 return device_create_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001805}
1806
1807static void snd_soc_dapm_sys_remove(struct device *dev)
1808{
Mark Brownaef90842009-05-16 17:53:16 +01001809 device_remove_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001810}
1811
1812/* free all dapm widgets and resources */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001813static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001814{
1815 struct snd_soc_dapm_widget *w, *next_w;
1816 struct snd_soc_dapm_path *p, *next_p;
1817
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001818 list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
1819 if (w->dapm != dapm)
1820 continue;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001821 list_del(&w->list);
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001822 /*
1823 * remove source and sink paths associated to this widget.
1824 * While removing the path, remove reference to it from both
1825 * source and sink widgets so that path is removed only once.
1826 */
1827 list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
1828 list_del(&p->list_sink);
1829 list_del(&p->list_source);
1830 list_del(&p->list);
1831 kfree(p->long_name);
1832 kfree(p);
1833 }
1834 list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
1835 list_del(&p->list_sink);
1836 list_del(&p->list_source);
1837 list_del(&p->list);
1838 kfree(p->long_name);
1839 kfree(p);
1840 }
Stephen Warrenfad59882011-04-28 17:37:59 -06001841 kfree(w->kcontrols);
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001842 kfree(w->name);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001843 kfree(w);
1844 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001845}
1846
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001847static struct snd_soc_dapm_widget *dapm_find_widget(
1848 struct snd_soc_dapm_context *dapm, const char *pin,
1849 bool search_other_contexts)
1850{
1851 struct snd_soc_dapm_widget *w;
1852 struct snd_soc_dapm_widget *fallback = NULL;
1853
1854 list_for_each_entry(w, &dapm->card->widgets, list) {
1855 if (!strcmp(w->name, pin)) {
1856 if (w->dapm == dapm)
1857 return w;
1858 else
1859 fallback = w;
1860 }
1861 }
1862
1863 if (search_other_contexts)
1864 return fallback;
1865
1866 return NULL;
1867}
1868
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001869static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
Mark Brown16499232009-01-07 18:25:13 +00001870 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01001871{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001872 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Liam Girdwooda5302182008-07-07 13:35:17 +01001873
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001874 if (!w) {
1875 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
1876 return -EINVAL;
Liam Girdwooda5302182008-07-07 13:35:17 +01001877 }
1878
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001879 w->connected = status;
1880 if (status == 0)
1881 w->force = 0;
Mark Brown0d867332011-04-06 11:38:14 +09001882
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02001883 return 0;
Liam Girdwooda5302182008-07-07 13:35:17 +01001884}
1885
Richard Purdie2b97eab2006-10-06 18:32:18 +02001886/**
Liam Girdwooda5302182008-07-07 13:35:17 +01001887 * snd_soc_dapm_sync - scan and power dapm paths
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001888 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02001889 *
1890 * Walks all dapm audio paths and powers widgets according to their
1891 * stream or path usage.
1892 *
1893 * Returns 0 for success.
1894 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001895int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001896{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001897 return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001898}
Liam Girdwooda5302182008-07-07 13:35:17 +01001899EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001900
Liam Girdwoodce6120c2010-11-05 15:53:46 +02001901static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
Mark Brown215edda2009-09-08 18:59:05 +01001902 const struct snd_soc_dapm_route *route)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001903{
1904 struct snd_soc_dapm_path *path;
1905 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001906 struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001907 const char *sink;
Mark Brown215edda2009-09-08 18:59:05 +01001908 const char *control = route->control;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001909 const char *source;
1910 char prefixed_sink[80];
1911 char prefixed_source[80];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001912 int ret = 0;
1913
Mark Brown88e8b9a2011-03-02 18:18:24 +00001914 if (dapm->codec && dapm->codec->name_prefix) {
Jarkko Nikulaead9b912010-11-13 20:40:44 +02001915 snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
1916 dapm->codec->name_prefix, route->sink);
1917 sink = prefixed_sink;
1918 snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
1919 dapm->codec->name_prefix, route->source);
1920 source = prefixed_source;
1921 } else {
1922 sink = route->sink;
1923 source = route->source;
1924 }
1925
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001926 /*
1927 * find src and dest widgets over all widgets but favor a widget from
1928 * current DAPM context
1929 */
1930 list_for_each_entry(w, &dapm->card->widgets, list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001931 if (!wsink && !(strcmp(w->name, sink))) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001932 wtsink = w;
1933 if (w->dapm == dapm)
1934 wsink = w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001935 continue;
1936 }
1937 if (!wsource && !(strcmp(w->name, source))) {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001938 wtsource = w;
1939 if (w->dapm == dapm)
1940 wsource = w;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001941 }
1942 }
Jarkko Nikula97c866d2010-12-14 12:18:31 +02001943 /* use widget from another DAPM context if not found from this */
1944 if (!wsink)
1945 wsink = wtsink;
1946 if (!wsource)
1947 wsource = wtsource;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001948
1949 if (wsource == NULL || wsink == NULL)
1950 return -ENODEV;
1951
1952 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
1953 if (!path)
1954 return -ENOMEM;
1955
1956 path->source = wsource;
1957 path->sink = wsink;
Mark Brown215edda2009-09-08 18:59:05 +01001958 path->connected = route->connected;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001959 INIT_LIST_HEAD(&path->list);
1960 INIT_LIST_HEAD(&path->list_source);
1961 INIT_LIST_HEAD(&path->list_sink);
1962
1963 /* check for external widgets */
1964 if (wsink->id == snd_soc_dapm_input) {
1965 if (wsource->id == snd_soc_dapm_micbias ||
1966 wsource->id == snd_soc_dapm_mic ||
Rongrong Cao087d53a2009-07-10 20:13:30 +01001967 wsource->id == snd_soc_dapm_line ||
1968 wsource->id == snd_soc_dapm_output)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001969 wsink->ext = 1;
1970 }
1971 if (wsource->id == snd_soc_dapm_output) {
1972 if (wsink->id == snd_soc_dapm_spk ||
1973 wsink->id == snd_soc_dapm_hp ||
Seth Forshee1e392212007-04-16 15:36:42 +02001974 wsink->id == snd_soc_dapm_line ||
1975 wsink->id == snd_soc_dapm_input)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001976 wsource->ext = 1;
1977 }
1978
1979 /* connect static paths */
1980 if (control == NULL) {
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02001981 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001982 list_add(&path->list_sink, &wsink->sources);
1983 list_add(&path->list_source, &wsource->sinks);
1984 path->connect = 1;
1985 return 0;
1986 }
1987
1988 /* connect dynamic paths */
Lu Guanqundc2bea62011-04-20 16:00:36 +08001989 switch (wsink->id) {
Richard Purdie2b97eab2006-10-06 18:32:18 +02001990 case snd_soc_dapm_adc:
1991 case snd_soc_dapm_dac:
1992 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06001993 case snd_soc_dapm_out_drv:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001994 case snd_soc_dapm_input:
1995 case snd_soc_dapm_output:
1996 case snd_soc_dapm_micbias:
1997 case snd_soc_dapm_vmid:
1998 case snd_soc_dapm_pre:
1999 case snd_soc_dapm_post:
Mark Brown246d0a12009-04-22 18:24:55 +01002000 case snd_soc_dapm_supply:
Mark Brown010ff262009-08-17 17:39:22 +01002001 case snd_soc_dapm_aif_in:
2002 case snd_soc_dapm_aif_out:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002003 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002004 list_add(&path->list_sink, &wsink->sources);
2005 list_add(&path->list_source, &wsource->sinks);
2006 path->connect = 1;
2007 return 0;
2008 case snd_soc_dapm_mux:
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00002009 case snd_soc_dapm_virt_mux:
Peter Ujfalusi74155552009-01-08 13:34:29 +02002010 case snd_soc_dapm_value_mux:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002011 ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
Stephen Warren82cfecd2011-04-28 17:37:58 -06002012 &wsink->kcontrol_news[0]);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002013 if (ret != 0)
2014 goto err;
2015 break;
2016 case snd_soc_dapm_switch:
2017 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002018 case snd_soc_dapm_mixer_named_ctl:
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002019 ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002020 if (ret != 0)
2021 goto err;
2022 break;
2023 case snd_soc_dapm_hp:
2024 case snd_soc_dapm_mic:
2025 case snd_soc_dapm_line:
2026 case snd_soc_dapm_spk:
Jarkko Nikula8ddab3f2010-12-14 12:18:30 +02002027 list_add(&path->list, &dapm->card->paths);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002028 list_add(&path->list_sink, &wsink->sources);
2029 list_add(&path->list_source, &wsource->sinks);
2030 path->connect = 0;
2031 return 0;
2032 }
2033 return 0;
2034
2035err:
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002036 dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n",
2037 source, control, sink);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002038 kfree(path);
2039 return ret;
2040}
Mark Brown105f1c22008-05-13 14:52:19 +02002041
2042/**
Mark Brown105f1c22008-05-13 14:52:19 +02002043 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002044 * @dapm: DAPM context
Mark Brown105f1c22008-05-13 14:52:19 +02002045 * @route: audio routes
2046 * @num: number of routes
2047 *
2048 * Connects 2 dapm widgets together via a named audio path. The sink is
2049 * the widget receiving the audio signal, whilst the source is the sender
2050 * of the audio signal.
2051 *
2052 * Returns 0 for success else error. On error all resources can be freed
2053 * with a call to snd_soc_card_free().
2054 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002055int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
Mark Brown105f1c22008-05-13 14:52:19 +02002056 const struct snd_soc_dapm_route *route, int num)
2057{
2058 int i, ret;
2059
2060 for (i = 0; i < num; i++) {
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002061 ret = snd_soc_dapm_add_route(dapm, route);
Mark Brown105f1c22008-05-13 14:52:19 +02002062 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002063 dev_err(dapm->dev, "Failed to add route %s->%s\n",
2064 route->source, route->sink);
Mark Brown105f1c22008-05-13 14:52:19 +02002065 return ret;
2066 }
2067 route++;
2068 }
2069
2070 return 0;
2071}
2072EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
2073
2074/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002075 * snd_soc_dapm_new_widgets - add new dapm widgets
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002076 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002077 *
2078 * Checks the codec for any new dapm widgets and creates them if found.
2079 *
2080 * Returns 0 for success.
2081 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002082int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002083{
2084 struct snd_soc_dapm_widget *w;
Mark Brownb66a70d2011-02-09 18:04:11 +00002085 unsigned int val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002086
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002087 list_for_each_entry(w, &dapm->card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002088 {
2089 if (w->new)
2090 continue;
2091
Stephen Warrenfad59882011-04-28 17:37:59 -06002092 if (w->num_kcontrols) {
2093 w->kcontrols = kzalloc(w->num_kcontrols *
2094 sizeof(struct snd_kcontrol *),
2095 GFP_KERNEL);
2096 if (!w->kcontrols)
2097 return -ENOMEM;
2098 }
2099
Richard Purdie2b97eab2006-10-06 18:32:18 +02002100 switch(w->id) {
2101 case snd_soc_dapm_switch:
2102 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00002103 case snd_soc_dapm_mixer_named_ctl:
Mark Brownb75576d2009-04-20 17:56:13 +01002104 w->power_check = dapm_generic_check_power;
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002105 dapm_new_mixer(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002106 break;
2107 case snd_soc_dapm_mux:
Dimitris Papastamos24ff33a2010-12-16 15:53:39 +00002108 case snd_soc_dapm_virt_mux:
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002109 case snd_soc_dapm_value_mux:
Mark Brownb75576d2009-04-20 17:56:13 +01002110 w->power_check = dapm_generic_check_power;
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002111 dapm_new_mux(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002112 break;
2113 case snd_soc_dapm_adc:
Mark Brown010ff262009-08-17 17:39:22 +01002114 case snd_soc_dapm_aif_out:
Mark Brownb75576d2009-04-20 17:56:13 +01002115 w->power_check = dapm_adc_check_power;
2116 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002117 case snd_soc_dapm_dac:
Mark Brown010ff262009-08-17 17:39:22 +01002118 case snd_soc_dapm_aif_in:
Mark Brownb75576d2009-04-20 17:56:13 +01002119 w->power_check = dapm_dac_check_power;
2120 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002121 case snd_soc_dapm_pga:
Olaya, Margaritad88429a2010-12-10 21:11:44 -06002122 case snd_soc_dapm_out_drv:
Mark Brownb75576d2009-04-20 17:56:13 +01002123 w->power_check = dapm_generic_check_power;
Lars-Peter Clausen4b80b8c2011-06-09 13:22:36 +02002124 dapm_new_pga(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002125 break;
2126 case snd_soc_dapm_input:
2127 case snd_soc_dapm_output:
2128 case snd_soc_dapm_micbias:
2129 case snd_soc_dapm_spk:
2130 case snd_soc_dapm_hp:
2131 case snd_soc_dapm_mic:
2132 case snd_soc_dapm_line:
Mark Brownb75576d2009-04-20 17:56:13 +01002133 w->power_check = dapm_generic_check_power;
2134 break;
Mark Brown246d0a12009-04-22 18:24:55 +01002135 case snd_soc_dapm_supply:
2136 w->power_check = dapm_supply_check_power;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002137 case snd_soc_dapm_vmid:
2138 case snd_soc_dapm_pre:
2139 case snd_soc_dapm_post:
2140 break;
2141 }
Mark Brownb66a70d2011-02-09 18:04:11 +00002142
2143 /* Read the initial power state from the device */
2144 if (w->reg >= 0) {
Liam Girdwood35ca6602011-01-28 17:45:35 +00002145 val = soc_widget_read(w, w->reg);
Mark Brownb66a70d2011-02-09 18:04:11 +00002146 val &= 1 << w->shift;
2147 if (w->invert)
2148 val = !val;
2149
2150 if (val)
2151 w->power = 1;
2152 }
2153
Richard Purdie2b97eab2006-10-06 18:32:18 +02002154 w->new = 1;
Lars-Peter Clausend5d1e0b2011-04-30 19:45:49 +02002155
2156 dapm_debugfs_add_widget(w);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002157 }
2158
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002159 dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002160 return 0;
2161}
2162EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
2163
Liam Girdwood7038dfd92011-02-01 20:58:15 +00002164const char *snd_soc_dapm_get_aif(struct snd_soc_dapm_context *dapm,
2165 const char *stream_name, enum snd_soc_dapm_type type)
2166{
2167 struct snd_soc_dapm_widget *w;
2168
Liam Girdwoodab1058a2011-01-31 20:33:07 +00002169 list_for_each_entry(w, &dapm->card->widgets, list) {
Liam Girdwood7038dfd92011-02-01 20:58:15 +00002170
2171 if (!w->sname)
2172 continue;
2173
2174 if (w->id == type && strstr(w->sname, stream_name))
2175 return w->name;
Liam Girdwoodab1058a2011-01-31 20:33:07 +00002176
Liam Girdwood7038dfd92011-02-01 20:58:15 +00002177 }
2178 return NULL;
2179}
2180EXPORT_SYMBOL_GPL(snd_soc_dapm_get_aif);
2181
Richard Purdie2b97eab2006-10-06 18:32:18 +02002182/**
2183 * snd_soc_dapm_get_volsw - dapm mixer get callback
2184 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002185 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002186 *
2187 * Callback to get the value of a dapm mixer control.
2188 *
2189 * Returns 0 for success.
2190 */
2191int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2192 struct snd_ctl_elem_value *ucontrol)
2193{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002194 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2195 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Jon Smirl4eaa9812008-07-29 11:42:26 +01002196 struct soc_mixer_control *mc =
2197 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf82008-07-29 10:22:24 -04002198 unsigned int reg = mc->reg;
2199 unsigned int shift = mc->shift;
2200 unsigned int rshift = mc->rshift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002201 int max = mc->max;
Jon Smirl815ecf82008-07-29 10:22:24 -04002202 unsigned int invert = mc->invert;
2203 unsigned int mask = (1 << fls(max)) - 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002204
Richard Purdie2b97eab2006-10-06 18:32:18 +02002205 ucontrol->value.integer.value[0] =
2206 (snd_soc_read(widget->codec, reg) >> shift) & mask;
2207 if (shift != rshift)
2208 ucontrol->value.integer.value[1] =
2209 (snd_soc_read(widget->codec, reg) >> rshift) & mask;
2210 if (invert) {
2211 ucontrol->value.integer.value[0] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002212 max - ucontrol->value.integer.value[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002213 if (shift != rshift)
2214 ucontrol->value.integer.value[1] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002215 max - ucontrol->value.integer.value[1];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002216 }
2217
2218 return 0;
2219}
2220EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
2221
2222/**
2223 * snd_soc_dapm_put_volsw - dapm mixer set callback
2224 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002225 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002226 *
2227 * Callback to set the value of a dapm mixer control.
2228 *
2229 * Returns 0 for success.
2230 */
2231int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2232 struct snd_ctl_elem_value *ucontrol)
2233{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002234 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2235 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2236 struct snd_soc_codec *codec = widget->codec;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002237 struct soc_mixer_control *mc =
2238 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf82008-07-29 10:22:24 -04002239 unsigned int reg = mc->reg;
2240 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01002241 int max = mc->max;
Jon Smirl815ecf82008-07-29 10:22:24 -04002242 unsigned int mask = (1 << fls(max)) - 1;
2243 unsigned int invert = mc->invert;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002244 unsigned int val;
Mark Brown97404f22010-12-14 16:13:57 +00002245 int connect, change;
2246 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002247 int wi;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002248
2249 val = (ucontrol->value.integer.value[0] & mask);
2250
2251 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01002252 val = max - val;
Stephen Warrene9cf7042011-01-27 14:54:05 -07002253 mask = mask << shift;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002254 val = val << shift;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002255
Stephen Warrenfafd2172011-04-28 17:38:00 -06002256 if (val)
2257 /* new connection */
2258 connect = invert ? 0 : 1;
2259 else
2260 /* old connection must be powered down */
2261 connect = invert ? 1 : 0;
2262
2263 mutex_lock(&codec->mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002264
Stephen Warrene9cf7042011-01-27 14:54:05 -07002265 change = snd_soc_test_bits(widget->codec, reg, mask, val);
Mark Brown97404f22010-12-14 16:13:57 +00002266 if (change) {
Stephen Warrenfafd2172011-04-28 17:38:00 -06002267 for (wi = 0; wi < wlist->num_widgets; wi++) {
2268 widget = wlist->widgets[wi];
Mark Brown283375c2009-12-07 18:09:03 +00002269
Stephen Warrenfafd2172011-04-28 17:38:00 -06002270 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002271
Stephen Warrenfafd2172011-04-28 17:38:00 -06002272 update.kcontrol = kcontrol;
2273 update.widget = widget;
2274 update.reg = reg;
2275 update.mask = mask;
2276 update.val = val;
2277 widget->dapm->update = &update;
Mark Brown97404f22010-12-14 16:13:57 +00002278
Stephen Warrenfafd2172011-04-28 17:38:00 -06002279 dapm_mixer_update_power(widget, kcontrol, connect);
2280
2281 widget->dapm->update = NULL;
2282 }
Mark Brown283375c2009-12-07 18:09:03 +00002283 }
2284
Stephen Warrenfafd2172011-04-28 17:38:00 -06002285 mutex_unlock(&codec->mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002286 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002287}
2288EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
2289
2290/**
2291 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
2292 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002293 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002294 *
2295 * Callback to get the value of a dapm enumerated double mixer control.
2296 *
2297 * Returns 0 for success.
2298 */
2299int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
2300 struct snd_ctl_elem_value *ucontrol)
2301{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002302 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2303 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +02002304 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002305 unsigned int val, bitmask;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002306
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002307 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002308 ;
2309 val = snd_soc_read(widget->codec, e->reg);
2310 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
2311 if (e->shift_l != e->shift_r)
2312 ucontrol->value.enumerated.item[1] =
2313 (val >> e->shift_r) & (bitmask - 1);
2314
2315 return 0;
2316}
2317EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
2318
2319/**
2320 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
2321 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00002322 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02002323 *
2324 * Callback to set the value of a dapm enumerated double mixer control.
2325 *
2326 * Returns 0 for success.
2327 */
2328int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
2329 struct snd_ctl_elem_value *ucontrol)
2330{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002331 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2332 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2333 struct snd_soc_codec *codec = widget->codec;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002334 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Mark Brown3a655772009-10-05 17:23:30 +01002335 unsigned int val, mux, change;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002336 unsigned int mask, bitmask;
Mark Brown97404f22010-12-14 16:13:57 +00002337 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002338 int wi;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002339
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002340 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002341 ;
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002342 if (ucontrol->value.enumerated.item[0] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002343 return -EINVAL;
2344 mux = ucontrol->value.enumerated.item[0];
2345 val = mux << e->shift_l;
2346 mask = (bitmask - 1) << e->shift_l;
2347 if (e->shift_l != e->shift_r) {
Jon Smirlf8ba0b72008-07-29 11:42:27 +01002348 if (ucontrol->value.enumerated.item[1] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002349 return -EINVAL;
2350 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
2351 mask |= (bitmask - 1) << e->shift_r;
2352 }
2353
Stephen Warrenfafd2172011-04-28 17:38:00 -06002354 mutex_lock(&codec->mutex);
2355
Mark Brown3a655772009-10-05 17:23:30 +01002356 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002357 if (change) {
2358 for (wi = 0; wi < wlist->num_widgets; wi++) {
2359 widget = wlist->widgets[wi];
Mark Brown97404f22010-12-14 16:13:57 +00002360
Stephen Warrenfafd2172011-04-28 17:38:00 -06002361 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002362
Stephen Warrenfafd2172011-04-28 17:38:00 -06002363 update.kcontrol = kcontrol;
2364 update.widget = widget;
2365 update.reg = e->reg;
2366 update.mask = mask;
2367 update.val = val;
2368 widget->dapm->update = &update;
Mark Brown1642e3d2009-10-05 16:24:26 +01002369
Stephen Warrenfafd2172011-04-28 17:38:00 -06002370 dapm_mux_update_power(widget, kcontrol, change, mux, e);
Mark Brown1642e3d2009-10-05 16:24:26 +01002371
Stephen Warrenfafd2172011-04-28 17:38:00 -06002372 widget->dapm->update = NULL;
2373 }
2374 }
2375
2376 mutex_unlock(&codec->mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002377 return change;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002378}
2379EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
2380
2381/**
Mark Brownd2b247a2009-10-06 15:21:04 +01002382 * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
2383 * @kcontrol: mixer control
2384 * @ucontrol: control element information
2385 *
2386 * Returns 0 for success.
2387 */
2388int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
2389 struct snd_ctl_elem_value *ucontrol)
2390{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002391 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2392 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Mark Brownd2b247a2009-10-06 15:21:04 +01002393
2394 ucontrol->value.enumerated.item[0] = widget->value;
2395
2396 return 0;
2397}
2398EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
2399
2400/**
2401 * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
2402 * @kcontrol: mixer control
2403 * @ucontrol: control element information
2404 *
2405 * Returns 0 for success.
2406 */
2407int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
2408 struct snd_ctl_elem_value *ucontrol)
2409{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002410 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2411 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2412 struct snd_soc_codec *codec = widget->codec;
Mark Brownd2b247a2009-10-06 15:21:04 +01002413 struct soc_enum *e =
2414 (struct soc_enum *)kcontrol->private_value;
2415 int change;
2416 int ret = 0;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002417 int wi;
Mark Brownd2b247a2009-10-06 15:21:04 +01002418
2419 if (ucontrol->value.enumerated.item[0] >= e->max)
2420 return -EINVAL;
2421
Stephen Warrenfafd2172011-04-28 17:38:00 -06002422 mutex_lock(&codec->mutex);
Mark Brownd2b247a2009-10-06 15:21:04 +01002423
2424 change = widget->value != ucontrol->value.enumerated.item[0];
Stephen Warrenfafd2172011-04-28 17:38:00 -06002425 if (change) {
2426 for (wi = 0; wi < wlist->num_widgets; wi++) {
2427 widget = wlist->widgets[wi];
Mark Brownd2b247a2009-10-06 15:21:04 +01002428
Stephen Warrenfafd2172011-04-28 17:38:00 -06002429 widget->value = ucontrol->value.enumerated.item[0];
2430
2431 dapm_mux_update_power(widget, kcontrol, change,
2432 widget->value, e);
2433 }
2434 }
2435
2436 mutex_unlock(&codec->mutex);
Mark Brownd2b247a2009-10-06 15:21:04 +01002437 return ret;
2438}
2439EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
2440
2441/**
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002442 * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
2443 * callback
2444 * @kcontrol: mixer control
2445 * @ucontrol: control element information
2446 *
2447 * Callback to get the value of a dapm semi enumerated double mixer control.
2448 *
2449 * Semi enumerated mixer: the enumerated items are referred as values. Can be
2450 * used for handling bitfield coded enumeration for example.
2451 *
2452 * Returns 0 for success.
2453 */
2454int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
2455 struct snd_ctl_elem_value *ucontrol)
2456{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002457 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2458 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
Peter Ujfalusi74155552009-01-08 13:34:29 +02002459 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002460 unsigned int reg_val, val, mux;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002461
2462 reg_val = snd_soc_read(widget->codec, e->reg);
2463 val = (reg_val >> e->shift_l) & e->mask;
2464 for (mux = 0; mux < e->max; mux++) {
2465 if (val == e->values[mux])
2466 break;
2467 }
2468 ucontrol->value.enumerated.item[0] = mux;
2469 if (e->shift_l != e->shift_r) {
2470 val = (reg_val >> e->shift_r) & e->mask;
2471 for (mux = 0; mux < e->max; mux++) {
2472 if (val == e->values[mux])
2473 break;
2474 }
2475 ucontrol->value.enumerated.item[1] = mux;
2476 }
2477
2478 return 0;
2479}
2480EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
2481
2482/**
2483 * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
2484 * callback
2485 * @kcontrol: mixer control
2486 * @ucontrol: control element information
2487 *
2488 * Callback to set the value of a dapm semi enumerated double mixer control.
2489 *
2490 * Semi enumerated mixer: the enumerated items are referred as values. Can be
2491 * used for handling bitfield coded enumeration for example.
2492 *
2493 * Returns 0 for success.
2494 */
2495int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
2496 struct snd_ctl_elem_value *ucontrol)
2497{
Stephen Warrenfafd2172011-04-28 17:38:00 -06002498 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
2499 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2500 struct snd_soc_codec *codec = widget->codec;
Peter Ujfalusi74155552009-01-08 13:34:29 +02002501 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Mark Brown3a655772009-10-05 17:23:30 +01002502 unsigned int val, mux, change;
Daniel Ribeiro46f58222009-06-07 02:49:11 -03002503 unsigned int mask;
Mark Brown97404f22010-12-14 16:13:57 +00002504 struct snd_soc_dapm_update update;
Stephen Warrenfafd2172011-04-28 17:38:00 -06002505 int wi;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002506
2507 if (ucontrol->value.enumerated.item[0] > e->max - 1)
2508 return -EINVAL;
2509 mux = ucontrol->value.enumerated.item[0];
2510 val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
2511 mask = e->mask << e->shift_l;
2512 if (e->shift_l != e->shift_r) {
2513 if (ucontrol->value.enumerated.item[1] > e->max - 1)
2514 return -EINVAL;
2515 val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
2516 mask |= e->mask << e->shift_r;
2517 }
2518
Stephen Warrenfafd2172011-04-28 17:38:00 -06002519 mutex_lock(&codec->mutex);
2520
Mark Brown3a655772009-10-05 17:23:30 +01002521 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
Stephen Warrenfafd2172011-04-28 17:38:00 -06002522 if (change) {
2523 for (wi = 0; wi < wlist->num_widgets; wi++) {
2524 widget = wlist->widgets[wi];
Mark Brown97404f22010-12-14 16:13:57 +00002525
Stephen Warrenfafd2172011-04-28 17:38:00 -06002526 widget->value = val;
Mark Brown97404f22010-12-14 16:13:57 +00002527
Stephen Warrenfafd2172011-04-28 17:38:00 -06002528 update.kcontrol = kcontrol;
2529 update.widget = widget;
2530 update.reg = e->reg;
2531 update.mask = mask;
2532 update.val = val;
2533 widget->dapm->update = &update;
Mark Brown1642e3d2009-10-05 16:24:26 +01002534
Stephen Warrenfafd2172011-04-28 17:38:00 -06002535 dapm_mux_update_power(widget, kcontrol, change, mux, e);
Mark Brown1642e3d2009-10-05 16:24:26 +01002536
Stephen Warrenfafd2172011-04-28 17:38:00 -06002537 widget->dapm->update = NULL;
2538 }
2539 }
2540
2541 mutex_unlock(&codec->mutex);
Mark Brown97404f22010-12-14 16:13:57 +00002542 return change;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02002543}
2544EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
2545
2546/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00002547 * snd_soc_dapm_info_pin_switch - Info for a pin switch
2548 *
2549 * @kcontrol: mixer control
2550 * @uinfo: control element information
2551 *
2552 * Callback to provide information about a pin switch control.
2553 */
2554int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
2555 struct snd_ctl_elem_info *uinfo)
2556{
2557 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2558 uinfo->count = 1;
2559 uinfo->value.integer.min = 0;
2560 uinfo->value.integer.max = 1;
2561
2562 return 0;
2563}
2564EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
2565
2566/**
2567 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
2568 *
2569 * @kcontrol: mixer control
2570 * @ucontrol: Value
2571 */
2572int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
2573 struct snd_ctl_elem_value *ucontrol)
2574{
2575 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2576 const char *pin = (const char *)kcontrol->private_value;
2577
2578 mutex_lock(&codec->mutex);
2579
2580 ucontrol->value.integer.value[0] =
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002581 snd_soc_dapm_get_pin_status(&codec->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002582
2583 mutex_unlock(&codec->mutex);
2584
2585 return 0;
2586}
2587EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
2588
2589/**
2590 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
2591 *
2592 * @kcontrol: mixer control
2593 * @ucontrol: Value
2594 */
2595int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
2596 struct snd_ctl_elem_value *ucontrol)
2597{
2598 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2599 const char *pin = (const char *)kcontrol->private_value;
2600
2601 mutex_lock(&codec->mutex);
2602
2603 if (ucontrol->value.integer.value[0])
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002604 snd_soc_dapm_enable_pin(&codec->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002605 else
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002606 snd_soc_dapm_disable_pin(&codec->dapm, pin);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002607
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002608 snd_soc_dapm_sync(&codec->dapm);
Mark Brown8b37dbd2009-02-28 21:14:20 +00002609
2610 mutex_unlock(&codec->mutex);
2611
2612 return 0;
2613}
2614EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
2615
2616/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002617 * snd_soc_dapm_new_control - create new dapm control
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002618 * @dapm: DAPM context
Richard Purdie2b97eab2006-10-06 18:32:18 +02002619 * @widget: widget template
2620 *
2621 * Creates a new dapm control based upon the template.
2622 *
2623 * Returns 0 for success else error.
2624 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002625int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
Richard Purdie2b97eab2006-10-06 18:32:18 +02002626 const struct snd_soc_dapm_widget *widget)
2627{
2628 struct snd_soc_dapm_widget *w;
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002629 size_t name_len;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002630
2631 if ((w = dapm_cnew_widget(widget)) == NULL)
2632 return -ENOMEM;
2633
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002634 name_len = strlen(widget->name) + 1;
Mark Brown88e8b9a2011-03-02 18:18:24 +00002635 if (dapm->codec && dapm->codec->name_prefix)
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002636 name_len += 1 + strlen(dapm->codec->name_prefix);
2637 w->name = kmalloc(name_len, GFP_KERNEL);
2638 if (w->name == NULL) {
2639 kfree(w);
2640 return -ENOMEM;
2641 }
Mark Brown88e8b9a2011-03-02 18:18:24 +00002642 if (dapm->codec && dapm->codec->name_prefix)
Jarkko Nikulaead9b912010-11-13 20:40:44 +02002643 snprintf(w->name, name_len, "%s %s",
2644 dapm->codec->name_prefix, widget->name);
2645 else
2646 snprintf(w->name, name_len, "%s", widget->name);
2647
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002648 dapm->n_widgets++;
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002649 w->dapm = dapm;
2650 w->codec = dapm->codec;
Liam Girdwood7987a112011-01-31 19:52:42 +00002651 w->platform = dapm->platform;
Richard Purdie2b97eab2006-10-06 18:32:18 +02002652 INIT_LIST_HEAD(&w->sources);
2653 INIT_LIST_HEAD(&w->sinks);
2654 INIT_LIST_HEAD(&w->list);
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002655 list_add(&w->list, &dapm->card->widgets);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002656
2657 /* machine layer set ups unconnected pins and insertions */
2658 w->connected = 1;
2659 return 0;
2660}
2661EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
2662
2663/**
Mark Brown4ba13272008-05-13 14:51:19 +02002664 * snd_soc_dapm_new_controls - create new dapm controls
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002665 * @dapm: DAPM context
Mark Brown4ba13272008-05-13 14:51:19 +02002666 * @widget: widget array
2667 * @num: number of widgets
2668 *
2669 * Creates new DAPM controls based upon the templates.
2670 *
2671 * Returns 0 for success else error.
2672 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002673int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
Mark Brown4ba13272008-05-13 14:51:19 +02002674 const struct snd_soc_dapm_widget *widget,
2675 int num)
2676{
2677 int i, ret;
2678
2679 for (i = 0; i < num; i++) {
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002680 ret = snd_soc_dapm_new_control(dapm, widget);
Mark Brownb8b33cb2008-12-18 11:19:30 +00002681 if (ret < 0) {
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002682 dev_err(dapm->dev,
2683 "ASoC: Failed to create DAPM control %s: %d\n",
2684 widget->name, ret);
Mark Brown4ba13272008-05-13 14:51:19 +02002685 return ret;
Mark Brownb8b33cb2008-12-18 11:19:30 +00002686 }
Mark Brown4ba13272008-05-13 14:51:19 +02002687 widget++;
2688 }
2689 return 0;
2690}
2691EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
2692
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002693static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00002694 const char *stream, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002695{
2696 struct snd_soc_dapm_widget *w;
2697
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002698 list_for_each_entry(w, &dapm->card->widgets, list)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002699 {
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002700 if (!w->sname || w->dapm != dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002701 continue;
Jarkko Nikulaf7d41ae2010-11-09 14:40:27 +02002702 dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
2703 w->name, w->sname, stream, event);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002704 if (strstr(w->sname, stream)) {
2705 switch(event) {
2706 case SND_SOC_DAPM_STREAM_START:
2707 w->active = 1;
2708 break;
2709 case SND_SOC_DAPM_STREAM_STOP:
2710 w->active = 0;
2711 break;
2712 case SND_SOC_DAPM_STREAM_SUSPEND:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002713 case SND_SOC_DAPM_STREAM_RESUME:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002714 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
Richard Purdie2b97eab2006-10-06 18:32:18 +02002715 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
2716 break;
2717 }
2718 }
2719 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02002720
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002721 dapm_power_widgets(dapm, event);
Liam Girdwood670ff442011-03-30 23:27:27 +01002722 /* do we need to notify any clients that DAPM stream is complete */
2723 if (dapm->stream_event)
2724 dapm->stream_event(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002725}
2726
2727/**
2728 * snd_soc_dapm_stream_event - send a stream event to the dapm core
2729 * @rtd: PCM runtime data
2730 * @stream: stream name
2731 * @event: stream event
2732 *
2733 * Sends a stream event to the dapm core. The core then makes any
2734 * necessary widget power changes.
2735 *
2736 * Returns 0 for success else error.
2737 */
2738int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
2739 const char *stream, int event)
2740{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002741 if (stream == NULL)
2742 return 0;
Liam Girdwoodecc1a0d2011-02-16 16:24:17 +00002743
Liam Girdwood670ff442011-03-30 23:27:27 +01002744 mutex_lock(&rtd->card->dapm_mutex);
2745
2746 soc_dapm_stream_event(&rtd->platform->dapm, stream, event);
2747 soc_dapm_stream_event(&rtd->codec->dapm, stream, event);
2748
2749 mutex_unlock(&rtd->card->dapm_mutex);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002750 return 0;
2751}
Richard Purdie2b97eab2006-10-06 18:32:18 +02002752
2753/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002754 * snd_soc_dapm_enable_pin - enable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002755 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01002756 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02002757 *
Mark Brown74b8f952009-06-06 11:26:15 +01002758 * Enables input/output pin and its parents or children widgets iff there is
Liam Girdwooda5302182008-07-07 13:35:17 +01002759 * a valid audio route and active audio stream.
2760 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2761 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02002762 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002763int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002764{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002765 return snd_soc_dapm_set_pin(dapm, pin, 1);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002766}
Liam Girdwooda5302182008-07-07 13:35:17 +01002767EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002768
2769/**
Mark Brownda341832010-03-15 19:23:37 +00002770 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002771 * @dapm: DAPM context
Mark Brownda341832010-03-15 19:23:37 +00002772 * @pin: pin name
2773 *
2774 * Enables input/output pin regardless of any other state. This is
2775 * intended for use with microphone bias supplies used in microphone
2776 * jack detection.
2777 *
2778 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2779 * do any widget power switching.
2780 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002781int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
2782 const char *pin)
Mark Brownda341832010-03-15 19:23:37 +00002783{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002784 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Mark Brownda341832010-03-15 19:23:37 +00002785
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002786 if (!w) {
2787 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
2788 return -EINVAL;
Mark Brownda341832010-03-15 19:23:37 +00002789 }
2790
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002791 dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
2792 w->connected = 1;
2793 w->force = 1;
Mark Brown0d867332011-04-06 11:38:14 +09002794
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002795 return 0;
Mark Brownda341832010-03-15 19:23:37 +00002796}
2797EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
2798
2799/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002800 * snd_soc_dapm_disable_pin - disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002801 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01002802 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002803 *
Mark Brown74b8f952009-06-06 11:26:15 +01002804 * Disables input/output pin and its parents or children widgets.
Liam Girdwooda5302182008-07-07 13:35:17 +01002805 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2806 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002807 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002808int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
2809 const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01002810{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002811 return snd_soc_dapm_set_pin(dapm, pin, 0);
Liam Girdwooda5302182008-07-07 13:35:17 +01002812}
2813EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
2814
2815/**
Mark Brown5817b522008-09-24 11:23:11 +01002816 * snd_soc_dapm_nc_pin - permanently disable pin.
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002817 * @dapm: DAPM context
Mark Brown5817b522008-09-24 11:23:11 +01002818 * @pin: pin name
2819 *
2820 * Marks the specified pin as being not connected, disabling it along
2821 * any parent or child widgets. At present this is identical to
2822 * snd_soc_dapm_disable_pin() but in future it will be extended to do
2823 * additional things such as disabling controls which only affect
2824 * paths through the pin.
2825 *
2826 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2827 * do any widget power switching.
2828 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002829int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01002830{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002831 return snd_soc_dapm_set_pin(dapm, pin, 0);
Mark Brown5817b522008-09-24 11:23:11 +01002832}
2833EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
2834
2835/**
Liam Girdwooda5302182008-07-07 13:35:17 +01002836 * snd_soc_dapm_get_pin_status - get audio pin status
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002837 * @dapm: DAPM context
Liam Girdwooda5302182008-07-07 13:35:17 +01002838 * @pin: audio signal pin endpoint (or start point)
2839 *
2840 * Get audio pin status - connected or disconnected.
2841 *
2842 * Returns 1 for connected otherwise 0.
2843 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002844int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
2845 const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002846{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002847 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002848
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002849 if (w)
2850 return w->connected;
Stephen Warrena68b38a2011-04-19 15:25:11 -06002851
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002852 return 0;
2853}
Liam Girdwooda5302182008-07-07 13:35:17 +01002854EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02002855
2856/**
Mark Brown1547aba2010-05-07 21:11:40 +01002857 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002858 * @dapm: DAPM context
Mark Brown1547aba2010-05-07 21:11:40 +01002859 * @pin: audio signal pin endpoint (or start point)
2860 *
2861 * Mark the given endpoint or pin as ignoring suspend. When the
2862 * system is disabled a path between two endpoints flagged as ignoring
2863 * suspend will not be disabled. The path must already be enabled via
2864 * normal means at suspend time, it will not be turned on if it was not
2865 * already enabled.
2866 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002867int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
2868 const char *pin)
Mark Brown1547aba2010-05-07 21:11:40 +01002869{
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002870 struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
Mark Brown1547aba2010-05-07 21:11:40 +01002871
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002872 if (!w) {
2873 dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
2874 return -EINVAL;
Mark Brown1547aba2010-05-07 21:11:40 +01002875 }
2876
Lars-Peter Clausen91a5fca2011-04-27 18:34:31 +02002877 w->ignore_suspend = 1;
2878
2879 return 0;
Mark Brown1547aba2010-05-07 21:11:40 +01002880}
2881EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
2882
2883/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02002884 * snd_soc_dapm_free - free dapm resources
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00002885 * @card: SoC device
Richard Purdie2b97eab2006-10-06 18:32:18 +02002886 *
2887 * Free all dapm widgets and resources.
2888 */
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002889void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
Richard Purdie2b97eab2006-10-06 18:32:18 +02002890{
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002891 snd_soc_dapm_sys_remove(dapm->dev);
Lars-Peter Clausen6c45e122011-04-30 19:45:50 +02002892 dapm_debugfs_cleanup(dapm);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002893 dapm_free_widgets(dapm);
Jarkko Nikula7be31be82010-12-14 12:18:32 +02002894 list_del(&dapm->list);
Richard Purdie2b97eab2006-10-06 18:32:18 +02002895}
2896EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
2897
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002898static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
Mark Brown51737472009-06-22 13:16:51 +01002899{
Mark Brown51737472009-06-22 13:16:51 +01002900 struct snd_soc_dapm_widget *w;
2901 LIST_HEAD(down_list);
2902 int powerdown = 0;
2903
Jarkko Nikula97c866d2010-12-14 12:18:31 +02002904 list_for_each_entry(w, &dapm->card->widgets, list) {
2905 if (w->dapm != dapm)
2906 continue;
Mark Brown51737472009-06-22 13:16:51 +01002907 if (w->power) {
Mark Brown828a8422011-01-15 13:14:30 +00002908 dapm_seq_insert(w, &down_list, false);
Mark Brownc2caa4d2009-06-26 15:36:56 +01002909 w->power = 0;
Mark Brown51737472009-06-22 13:16:51 +01002910 powerdown = 1;
2911 }
2912 }
2913
2914 /* If there were no widgets to power down we're already in
2915 * standby.
2916 */
2917 if (powerdown) {
Mark Browned5a4c42011-02-18 11:12:42 -08002918 snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE);
Mark Brown828a8422011-01-15 13:14:30 +00002919 dapm_seq_run(dapm, &down_list, 0, false);
Mark Browned5a4c42011-02-18 11:12:42 -08002920 snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
Mark Brown51737472009-06-22 13:16:51 +01002921 }
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00002922}
Mark Brown51737472009-06-22 13:16:51 +01002923
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00002924/*
2925 * snd_soc_dapm_shutdown - callback for system shutdown
2926 */
2927void snd_soc_dapm_shutdown(struct snd_soc_card *card)
2928{
2929 struct snd_soc_codec *codec;
Liam Girdwood7987a112011-01-31 19:52:42 +00002930 struct snd_soc_platform *platform;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +00002931
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002932 list_for_each_entry(codec, &card->codec_dev_list, list) {
2933 soc_dapm_shutdown_codec(&codec->dapm);
Mark Browned5a4c42011-02-18 11:12:42 -08002934 snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF);
Liam Girdwoodce6120c2010-11-05 15:53:46 +02002935 }
Liam Girdwood7987a112011-01-31 19:52:42 +00002936
2937 list_for_each_entry(platform, &card->platform_dev_list, list) {
2938 soc_dapm_shutdown_codec(&platform->dapm);
2939 snd_soc_dapm_set_bias_level(&platform->dapm, SND_SOC_BIAS_OFF);
2940 }
Mark Brown51737472009-06-22 13:16:51 +01002941}
2942
Richard Purdie2b97eab2006-10-06 18:32:18 +02002943/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01002944MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02002945MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
2946MODULE_LICENSE("GPL");