blob: d130602b3072639dbc97980aeeb576a4a616b406 [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
15 * DAC's/ADC's.
16 * 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
32#include <linux/module.h>
33#include <linux/moduleparam.h>
34#include <linux/init.h>
35#include <linux/delay.h>
36#include <linux/pm.h>
37#include <linux/bitops.h>
38#include <linux/platform_device.h>
39#include <linux/jiffies.h>
Richard Purdie2b97eab2006-10-06 18:32:18 +020040#include <sound/core.h>
41#include <sound/pcm.h>
42#include <sound/pcm_params.h>
43#include <sound/soc-dapm.h>
44#include <sound/initval.h>
45
46/* debug */
Mark Brownc1286b82008-07-07 19:26:03 +010047#ifdef DEBUG
Richard Purdie2b97eab2006-10-06 18:32:18 +020048#define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
Richard Purdie2b97eab2006-10-06 18:32:18 +020049#else
50#define dump_dapm(codec, action)
Richard Purdie2b97eab2006-10-06 18:32:18 +020051#endif
52
Richard Purdie2b97eab2006-10-06 18:32:18 +020053/* dapm power sequences - make this per codec in the future */
54static int dapm_up_seq[] = {
Mark Brown246d0a12009-04-22 18:24:55 +010055 snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias,
56 snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
57 snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl,
58 snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
59 snd_soc_dapm_post
Richard Purdie2b97eab2006-10-06 18:32:18 +020060};
Ian Moltonca9c1aa2009-01-06 20:11:51 +000061
Richard Purdie2b97eab2006-10-06 18:32:18 +020062static int dapm_down_seq[] = {
63 snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
Ian Moltonca9c1aa2009-01-06 20:11:51 +000064 snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
65 snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
Mark Brown246d0a12009-04-22 18:24:55 +010066 snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply,
67 snd_soc_dapm_post
Richard Purdie2b97eab2006-10-06 18:32:18 +020068};
69
Troy Kisky12ef1932008-10-13 17:42:14 -070070static void pop_wait(u32 pop_time)
Mark Brown15e4c72f2008-07-02 11:51:20 +010071{
72 if (pop_time)
73 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
74}
75
Troy Kisky12ef1932008-10-13 17:42:14 -070076static void pop_dbg(u32 pop_time, const char *fmt, ...)
Mark Brown15e4c72f2008-07-02 11:51:20 +010077{
78 va_list args;
79
80 va_start(args, fmt);
81
82 if (pop_time) {
83 vprintk(fmt, args);
Troy Kisky12ef1932008-10-13 17:42:14 -070084 pop_wait(pop_time);
Mark Brown15e4c72f2008-07-02 11:51:20 +010085 }
86
87 va_end(args);
88}
89
Richard Purdie2b97eab2006-10-06 18:32:18 +020090/* create a new dapm widget */
Takashi Iwai88cb4292007-02-05 14:56:20 +010091static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
Richard Purdie2b97eab2006-10-06 18:32:18 +020092 const struct snd_soc_dapm_widget *_widget)
93{
Takashi Iwai88cb4292007-02-05 14:56:20 +010094 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
Richard Purdie2b97eab2006-10-06 18:32:18 +020095}
96
97/* set up initial codec paths */
98static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
99 struct snd_soc_dapm_path *p, int i)
100{
101 switch (w->id) {
102 case snd_soc_dapm_switch:
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000103 case snd_soc_dapm_mixer:
104 case snd_soc_dapm_mixer_named_ctl: {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200105 int val;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100106 struct soc_mixer_control *mc = (struct soc_mixer_control *)
107 w->kcontrols[i].private_value;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400108 unsigned int reg = mc->reg;
109 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100110 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400111 unsigned int mask = (1 << fls(max)) - 1;
112 unsigned int invert = mc->invert;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200113
114 val = snd_soc_read(w->codec, reg);
115 val = (val >> shift) & mask;
116
117 if ((invert && !val) || (!invert && val))
118 p->connect = 1;
119 else
120 p->connect = 0;
121 }
122 break;
123 case snd_soc_dapm_mux: {
124 struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
125 int val, item, bitmask;
126
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100127 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200128 ;
129 val = snd_soc_read(w->codec, e->reg);
130 item = (val >> e->shift_l) & (bitmask - 1);
131
132 p->connect = 0;
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100133 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200134 if (!(strcmp(p->name, e->texts[i])) && item == i)
135 p->connect = 1;
136 }
137 }
138 break;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200139 case snd_soc_dapm_value_mux: {
Peter Ujfalusi74155552009-01-08 13:34:29 +0200140 struct soc_enum *e = (struct soc_enum *)
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200141 w->kcontrols[i].private_value;
142 int val, item;
143
144 val = snd_soc_read(w->codec, e->reg);
145 val = (val >> e->shift_l) & e->mask;
146 for (item = 0; item < e->max; item++) {
147 if (val == e->values[item])
148 break;
149 }
150
151 p->connect = 0;
152 for (i = 0; i < e->max; i++) {
153 if (!(strcmp(p->name, e->texts[i])) && item == i)
154 p->connect = 1;
155 }
156 }
157 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200158 /* does not effect routing - always connected */
159 case snd_soc_dapm_pga:
160 case snd_soc_dapm_output:
161 case snd_soc_dapm_adc:
162 case snd_soc_dapm_input:
163 case snd_soc_dapm_dac:
164 case snd_soc_dapm_micbias:
165 case snd_soc_dapm_vmid:
Mark Brown246d0a12009-04-22 18:24:55 +0100166 case snd_soc_dapm_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200167 p->connect = 1;
168 break;
169 /* does effect routing - dynamically connected */
170 case snd_soc_dapm_hp:
171 case snd_soc_dapm_mic:
172 case snd_soc_dapm_spk:
173 case snd_soc_dapm_line:
174 case snd_soc_dapm_pre:
175 case snd_soc_dapm_post:
176 p->connect = 0;
177 break;
178 }
179}
180
181/* connect mux widget to it's interconnecting audio paths */
182static int dapm_connect_mux(struct snd_soc_codec *codec,
183 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
184 struct snd_soc_dapm_path *path, const char *control_name,
185 const struct snd_kcontrol_new *kcontrol)
186{
187 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
188 int i;
189
Jon Smirlf8ba0b72008-07-29 11:42:27 +0100190 for (i = 0; i < e->max; i++) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200191 if (!(strcmp(control_name, e->texts[i]))) {
192 list_add(&path->list, &codec->dapm_paths);
193 list_add(&path->list_sink, &dest->sources);
194 list_add(&path->list_source, &src->sinks);
195 path->name = (char*)e->texts[i];
196 dapm_set_path_status(dest, path, 0);
197 return 0;
198 }
199 }
200
201 return -ENODEV;
202}
203
204/* connect mixer widget to it's interconnecting audio paths */
205static int dapm_connect_mixer(struct snd_soc_codec *codec,
206 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
207 struct snd_soc_dapm_path *path, const char *control_name)
208{
209 int i;
210
211 /* search for mixer kcontrol */
212 for (i = 0; i < dest->num_kcontrols; i++) {
213 if (!strcmp(control_name, dest->kcontrols[i].name)) {
214 list_add(&path->list, &codec->dapm_paths);
215 list_add(&path->list_sink, &dest->sources);
216 list_add(&path->list_source, &src->sinks);
217 path->name = dest->kcontrols[i].name;
218 dapm_set_path_status(dest, path, i);
219 return 0;
220 }
221 }
222 return -ENODEV;
223}
224
225/* update dapm codec register bits */
226static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
227{
228 int change, power;
229 unsigned short old, new;
230 struct snd_soc_codec *codec = widget->codec;
231
232 /* check for valid widgets */
233 if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
234 widget->id == snd_soc_dapm_output ||
235 widget->id == snd_soc_dapm_hp ||
236 widget->id == snd_soc_dapm_mic ||
237 widget->id == snd_soc_dapm_line ||
238 widget->id == snd_soc_dapm_spk)
239 return 0;
240
241 power = widget->power;
242 if (widget->invert)
243 power = (power ? 0:1);
244
245 old = snd_soc_read(codec, widget->reg);
246 new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
247
248 change = old != new;
249 if (change) {
Troy Kisky12ef1932008-10-13 17:42:14 -0700250 pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n",
251 widget->name, widget->power ? "on" : "off",
252 codec->pop_time);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200253 snd_soc_write(codec, widget->reg, new);
Troy Kisky12ef1932008-10-13 17:42:14 -0700254 pop_wait(codec->pop_time);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200255 }
Mark Brownc1286b82008-07-07 19:26:03 +0100256 pr_debug("reg %x old %x new %x change %d\n", widget->reg,
257 old, new, change);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200258 return change;
259}
260
261/* ramps the volume up or down to minimise pops before or after a
262 * DAPM power event */
263static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
264{
265 const struct snd_kcontrol_new *k = widget->kcontrols;
266
267 if (widget->muted && !power)
268 return 0;
269 if (!widget->muted && power)
270 return 0;
271
272 if (widget->num_kcontrols && k) {
Jon Smirl4eaa9812008-07-29 11:42:26 +0100273 struct soc_mixer_control *mc =
274 (struct soc_mixer_control *)k->private_value;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400275 unsigned int reg = mc->reg;
276 unsigned int shift = mc->shift;
Jon Smirl4eaa9812008-07-29 11:42:26 +0100277 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -0400278 unsigned int mask = (1 << fls(max)) - 1;
279 unsigned int invert = mc->invert;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200280
281 if (power) {
282 int i;
283 /* power up has happended, increase volume to last level */
284 if (invert) {
Jon Smirl4eaa9812008-07-29 11:42:26 +0100285 for (i = max; i > widget->saved_value; i--)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200286 snd_soc_update_bits(widget->codec, reg, mask, i);
287 } else {
288 for (i = 0; i < widget->saved_value; i++)
289 snd_soc_update_bits(widget->codec, reg, mask, i);
290 }
291 widget->muted = 0;
292 } else {
293 /* power down is about to occur, decrease volume to mute */
294 int val = snd_soc_read(widget->codec, reg);
295 int i = widget->saved_value = (val >> shift) & mask;
296 if (invert) {
297 for (; i < mask; i++)
298 snd_soc_update_bits(widget->codec, reg, mask, i);
299 } else {
300 for (; i > 0; i--)
301 snd_soc_update_bits(widget->codec, reg, mask, i);
302 }
303 widget->muted = 1;
304 }
305 }
306 return 0;
307}
308
309/* create new dapm mixer control */
310static int dapm_new_mixer(struct snd_soc_codec *codec,
311 struct snd_soc_dapm_widget *w)
312{
313 int i, ret = 0;
Mark Brown219b93f2008-10-28 13:02:31 +0000314 size_t name_len;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200315 struct snd_soc_dapm_path *path;
316
317 /* add kcontrol */
318 for (i = 0; i < w->num_kcontrols; i++) {
319
320 /* match name */
321 list_for_each_entry(path, &w->sources, list_sink) {
322
323 /* mixer/mux paths name must match control name */
324 if (path->name != (char*)w->kcontrols[i].name)
325 continue;
326
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000327 /* add dapm control with long name.
328 * for dapm_mixer this is the concatenation of the
329 * mixer and kcontrol name.
330 * for dapm_mixer_named_ctl this is simply the
331 * kcontrol name.
332 */
333 name_len = strlen(w->kcontrols[i].name) + 1;
Mark Brown07495f32009-03-05 17:06:23 +0000334 if (w->id != snd_soc_dapm_mixer_named_ctl)
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000335 name_len += 1 + strlen(w->name);
336
Mark Brown219b93f2008-10-28 13:02:31 +0000337 path->long_name = kmalloc(name_len, GFP_KERNEL);
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000338
Richard Purdie2b97eab2006-10-06 18:32:18 +0200339 if (path->long_name == NULL)
340 return -ENOMEM;
341
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000342 switch (w->id) {
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000343 default:
344 snprintf(path->long_name, name_len, "%s %s",
345 w->name, w->kcontrols[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000346 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000347 case snd_soc_dapm_mixer_named_ctl:
348 snprintf(path->long_name, name_len, "%s",
349 w->kcontrols[i].name);
Mark Brown07495f32009-03-05 17:06:23 +0000350 break;
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000351 }
352
Mark Brown219b93f2008-10-28 13:02:31 +0000353 path->long_name[name_len - 1] = '\0';
354
Richard Purdie2b97eab2006-10-06 18:32:18 +0200355 path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
356 path->long_name);
357 ret = snd_ctl_add(codec->card, path->kcontrol);
358 if (ret < 0) {
Mark Brown6553e192009-04-06 16:59:32 +0100359 printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
360 path->long_name,
361 ret);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200362 kfree(path->long_name);
363 path->long_name = NULL;
364 return ret;
365 }
366 }
367 }
368 return ret;
369}
370
371/* create new dapm mux control */
372static int dapm_new_mux(struct snd_soc_codec *codec,
373 struct snd_soc_dapm_widget *w)
374{
375 struct snd_soc_dapm_path *path = NULL;
376 struct snd_kcontrol *kcontrol;
377 int ret = 0;
378
379 if (!w->num_kcontrols) {
380 printk(KERN_ERR "asoc: mux %s has no controls\n", w->name);
381 return -EINVAL;
382 }
383
384 kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
385 ret = snd_ctl_add(codec->card, kcontrol);
386 if (ret < 0)
387 goto err;
388
389 list_for_each_entry(path, &w->sources, list_sink)
390 path->kcontrol = kcontrol;
391
392 return ret;
393
394err:
395 printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
396 return ret;
397}
398
399/* create new dapm volume control */
400static int dapm_new_pga(struct snd_soc_codec *codec,
401 struct snd_soc_dapm_widget *w)
402{
403 struct snd_kcontrol *kcontrol;
404 int ret = 0;
405
406 if (!w->num_kcontrols)
407 return -EINVAL;
408
409 kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
410 ret = snd_ctl_add(codec->card, kcontrol);
411 if (ret < 0) {
412 printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
413 return ret;
414 }
415
416 return ret;
417}
418
419/* reset 'walked' bit for each dapm path */
420static inline void dapm_clear_walk(struct snd_soc_codec *codec)
421{
422 struct snd_soc_dapm_path *p;
423
424 list_for_each_entry(p, &codec->dapm_paths, list)
425 p->walked = 0;
426}
427
428/*
429 * Recursively check for a completed path to an active or physically connected
430 * output widget. Returns number of complete paths.
431 */
432static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
433{
434 struct snd_soc_dapm_path *path;
435 int con = 0;
436
Mark Brown246d0a12009-04-22 18:24:55 +0100437 if (widget->id == snd_soc_dapm_supply)
438 return 0;
439
Richard Purdie2b97eab2006-10-06 18:32:18 +0200440 if (widget->id == snd_soc_dapm_adc && widget->active)
441 return 1;
442
443 if (widget->connected) {
444 /* connected pin ? */
445 if (widget->id == snd_soc_dapm_output && !widget->ext)
446 return 1;
447
448 /* connected jack or spk ? */
449 if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
450 widget->id == snd_soc_dapm_line)
451 return 1;
452 }
453
454 list_for_each_entry(path, &widget->sinks, list_source) {
455 if (path->walked)
456 continue;
457
458 if (path->sink && path->connect) {
459 path->walked = 1;
460 con += is_connected_output_ep(path->sink);
461 }
462 }
463
464 return con;
465}
466
467/*
468 * Recursively check for a completed path to an active or physically connected
469 * input widget. Returns number of complete paths.
470 */
471static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
472{
473 struct snd_soc_dapm_path *path;
474 int con = 0;
475
Mark Brown246d0a12009-04-22 18:24:55 +0100476 if (widget->id == snd_soc_dapm_supply)
477 return 0;
478
Richard Purdie2b97eab2006-10-06 18:32:18 +0200479 /* active stream ? */
480 if (widget->id == snd_soc_dapm_dac && widget->active)
481 return 1;
482
483 if (widget->connected) {
484 /* connected pin ? */
485 if (widget->id == snd_soc_dapm_input && !widget->ext)
486 return 1;
487
488 /* connected VMID/Bias for lower pops */
489 if (widget->id == snd_soc_dapm_vmid)
490 return 1;
491
492 /* connected jack ? */
493 if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line)
494 return 1;
495 }
496
497 list_for_each_entry(path, &widget->sources, list_sink) {
498 if (path->walked)
499 continue;
500
501 if (path->source && path->connect) {
502 path->walked = 1;
503 con += is_connected_input_ep(path->source);
504 }
505 }
506
507 return con;
508}
509
510/*
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300511 * Handler for generic register modifier widget.
512 */
513int dapm_reg_event(struct snd_soc_dapm_widget *w,
514 struct snd_kcontrol *kcontrol, int event)
515{
516 unsigned int val;
517
518 if (SND_SOC_DAPM_EVENT_ON(event))
519 val = w->on_val;
520 else
521 val = w->off_val;
522
523 snd_soc_update_bits(w->codec, -(w->reg + 1),
524 w->mask << w->shift, val << w->shift);
525
526 return 0;
527}
Mark Brown11589412008-07-29 11:42:23 +0100528EXPORT_SYMBOL_GPL(dapm_reg_event);
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300529
Mark Brown025756ec2009-04-13 11:09:18 +0100530/* Standard power change method, used to apply power changes to most
531 * widgets.
532 */
533static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w)
534{
535 int ret;
536
537 /* call any power change event handlers */
538 if (w->event)
539 pr_debug("power %s event for %s flags %x\n",
540 w->power ? "on" : "off",
541 w->name, w->event_flags);
542
543 /* power up pre event */
544 if (w->power && w->event &&
545 (w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
546 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
547 if (ret < 0)
548 return ret;
549 }
550
551 /* power down pre event */
552 if (!w->power && w->event &&
553 (w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
554 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
555 if (ret < 0)
556 return ret;
557 }
558
559 /* Lower PGA volume to reduce pops */
560 if (w->id == snd_soc_dapm_pga && !w->power)
561 dapm_set_pga(w, w->power);
562
563 dapm_update_bits(w);
564
565 /* Raise PGA volume to reduce pops */
566 if (w->id == snd_soc_dapm_pga && w->power)
567 dapm_set_pga(w, w->power);
568
569 /* power up post event */
570 if (w->power && w->event &&
571 (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
572 ret = w->event(w,
573 NULL, SND_SOC_DAPM_POST_PMU);
574 if (ret < 0)
575 return ret;
576 }
577
578 /* power down post event */
579 if (!w->power && w->event &&
580 (w->event_flags & SND_SOC_DAPM_POST_PMD)) {
581 ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
582 if (ret < 0)
583 return ret;
584 }
585
586 return 0;
587}
588
Mark Browncd0f2d42009-04-20 16:56:59 +0100589/* Generic check to see if a widget should be powered.
590 */
591static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
592{
593 int in, out;
594
595 in = is_connected_input_ep(w);
596 dapm_clear_walk(w->codec);
597 out = is_connected_output_ep(w);
598 dapm_clear_walk(w->codec);
599 return out != 0 && in != 0;
600}
601
Mark Brown6ea31b92009-04-20 17:15:41 +0100602/* Check to see if an ADC has power */
603static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
604{
605 int in;
606
607 if (w->active) {
608 in = is_connected_input_ep(w);
609 dapm_clear_walk(w->codec);
610 return in != 0;
611 } else {
612 return dapm_generic_check_power(w);
613 }
614}
615
616/* Check to see if a DAC has power */
617static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
618{
619 int out;
620
621 if (w->active) {
622 out = is_connected_output_ep(w);
623 dapm_clear_walk(w->codec);
624 return out != 0;
625 } else {
626 return dapm_generic_check_power(w);
627 }
628}
629
Mark Brown246d0a12009-04-22 18:24:55 +0100630/* Check to see if a power supply is needed */
631static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
632{
633 struct snd_soc_dapm_path *path;
634 int power = 0;
635
636 /* Check if one of our outputs is connected */
637 list_for_each_entry(path, &w->sinks, list_source) {
638 if (path->sink && path->sink->power_check &&
639 path->sink->power_check(path->sink)) {
640 power = 1;
641 break;
642 }
643 }
644
645 dapm_clear_walk(w->codec);
646
647 return power;
648}
649
Jarkko Nikulae2be2cc2008-06-25 14:42:07 +0300650/*
Mark Brown42aa3412009-03-01 19:21:10 +0000651 * Scan a single DAPM widget for a complete audio path and update the
652 * power status appropriately.
653 */
654static int dapm_power_widget(struct snd_soc_codec *codec, int event,
655 struct snd_soc_dapm_widget *w)
656{
Mark Brown6d3ddc82009-05-16 17:47:29 +0100657 int ret;
Mark Brown42aa3412009-03-01 19:21:10 +0000658
Mark Brown6ea31b92009-04-20 17:15:41 +0100659 switch (w->id) {
Mark Brown6ea31b92009-04-20 17:15:41 +0100660 case snd_soc_dapm_pre:
Mark Brown42aa3412009-03-01 19:21:10 +0000661 if (!w->event)
662 return 0;
663
664 if (event == SND_SOC_DAPM_STREAM_START) {
665 ret = w->event(w,
666 NULL, SND_SOC_DAPM_PRE_PMU);
667 if (ret < 0)
668 return ret;
669 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
670 ret = w->event(w,
671 NULL, SND_SOC_DAPM_PRE_PMD);
672 if (ret < 0)
673 return ret;
674 }
675 return 0;
Mark Brown6ea31b92009-04-20 17:15:41 +0100676
677 case snd_soc_dapm_post:
Mark Brown42aa3412009-03-01 19:21:10 +0000678 if (!w->event)
679 return 0;
680
681 if (event == SND_SOC_DAPM_STREAM_START) {
682 ret = w->event(w,
683 NULL, SND_SOC_DAPM_POST_PMU);
684 if (ret < 0)
685 return ret;
686 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
687 ret = w->event(w,
688 NULL, SND_SOC_DAPM_POST_PMD);
689 if (ret < 0)
690 return ret;
691 }
692 return 0;
Mark Brown6ea31b92009-04-20 17:15:41 +0100693
694 default:
Mark Brown6d3ddc82009-05-16 17:47:29 +0100695 return dapm_generic_apply_power(w);
Mark Brown42aa3412009-03-01 19:21:10 +0000696 }
Mark Brown42aa3412009-03-01 19:21:10 +0000697}
698
699/*
Richard Purdie2b97eab2006-10-06 18:32:18 +0200700 * Scan each dapm widget for complete audio path.
701 * A complete path is a route that has valid endpoints i.e.:-
702 *
703 * o DAC to output pin.
704 * o Input Pin to ADC.
705 * o Input pin to Output pin (bypass, sidetone)
706 * o DAC to ADC (loopback).
707 */
Adrian Bunkd9c96cf2006-11-28 12:10:09 +0100708static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200709{
710 struct snd_soc_dapm_widget *w;
Mark Brown6d3ddc82009-05-16 17:47:29 +0100711 int ret = 0;
712 int i, power;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200713
Mark Brown6d3ddc82009-05-16 17:47:29 +0100714 INIT_LIST_HEAD(&codec->up_list);
715 INIT_LIST_HEAD(&codec->down_list);
716
717 /* Check which widgets we need to power and store them in
718 * lists indicating if they should be powered up or down.
719 */
720 list_for_each_entry(w, &codec->dapm_widgets, list) {
721 switch (w->id) {
722 case snd_soc_dapm_pre:
723 list_add_tail(&codec->down_list, &w->power_list);
724 break;
725 case snd_soc_dapm_post:
726 list_add_tail(&codec->up_list, &w->power_list);
727 break;
728
729 default:
730 if (!w->power_check)
731 continue;
732
733 power = w->power_check(w);
734 if (w->power == power)
735 continue;
736
737 if (power)
738 list_add_tail(&w->power_list, &codec->up_list);
739 else
740 list_add_tail(&w->power_list,
741 &codec->down_list);
742
743 w->power = power;
744 break;
745 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200746 }
747
Mark Brown6d3ddc82009-05-16 17:47:29 +0100748 /* Power down widgets first; try to avoid amplifying pops. */
749 for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) {
750 list_for_each_entry(w, &codec->down_list, power_list) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200751 /* is widget in stream order */
Mark Brown6d3ddc82009-05-16 17:47:29 +0100752 if (w->id != dapm_down_seq[i])
Richard Purdie2b97eab2006-10-06 18:32:18 +0200753 continue;
754
Mark Brown42aa3412009-03-01 19:21:10 +0000755 ret = dapm_power_widget(codec, event, w);
756 if (ret != 0)
Mark Brown6d3ddc82009-05-16 17:47:29 +0100757 pr_err("Failed to power down %s: %d\n",
758 w->name, ret);
759 }
760 }
761
762 /* Now power up. */
763 for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) {
764 list_for_each_entry(w, &codec->up_list, power_list) {
765 /* is widget in stream order */
766 if (w->id != dapm_up_seq[i])
767 continue;
768
769 ret = dapm_power_widget(codec, event, w);
770 if (ret != 0)
771 pr_err("Failed to power up %s: %d\n",
772 w->name, ret);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200773 }
774 }
775
Mark Brown42aa3412009-03-01 19:21:10 +0000776 return 0;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200777}
778
Mark Brownc1286b82008-07-07 19:26:03 +0100779#ifdef DEBUG
Richard Purdie2b97eab2006-10-06 18:32:18 +0200780static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
781{
782 struct snd_soc_dapm_widget *w;
783 struct snd_soc_dapm_path *p = NULL;
784 int in, out;
785
786 printk("DAPM %s %s\n", codec->name, action);
787
788 list_for_each_entry(w, &codec->dapm_widgets, list) {
789
790 /* only display widgets that effect routing */
791 switch (w->id) {
792 case snd_soc_dapm_pre:
793 case snd_soc_dapm_post:
794 case snd_soc_dapm_vmid:
795 continue;
796 case snd_soc_dapm_mux:
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +0200797 case snd_soc_dapm_value_mux:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200798 case snd_soc_dapm_output:
799 case snd_soc_dapm_input:
800 case snd_soc_dapm_switch:
801 case snd_soc_dapm_hp:
802 case snd_soc_dapm_mic:
803 case snd_soc_dapm_spk:
804 case snd_soc_dapm_line:
805 case snd_soc_dapm_micbias:
806 case snd_soc_dapm_dac:
807 case snd_soc_dapm_adc:
808 case snd_soc_dapm_pga:
809 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000810 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +0100811 case snd_soc_dapm_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200812 if (w->name) {
813 in = is_connected_input_ep(w);
814 dapm_clear_walk(w->codec);
815 out = is_connected_output_ep(w);
816 dapm_clear_walk(w->codec);
817 printk("%s: %s in %d out %d\n", w->name,
818 w->power ? "On":"Off",in, out);
819
820 list_for_each_entry(p, &w->sources, list_sink) {
821 if (p->connect)
822 printk(" in %s %s\n", p->name ? p->name : "static",
823 p->source->name);
824 }
825 list_for_each_entry(p, &w->sinks, list_source) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200826 if (p->connect)
827 printk(" out %s %s\n", p->name ? p->name : "static",
828 p->sink->name);
829 }
830 }
831 break;
832 }
833 }
834}
835#endif
836
837/* test and update the power status of a mux widget */
Adrian Bunkd9c96cf2006-11-28 12:10:09 +0100838static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
839 struct snd_kcontrol *kcontrol, int mask,
Richard Zhaocb01e2b2008-10-07 08:05:20 +0800840 int mux, int val, struct soc_enum *e)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200841{
842 struct snd_soc_dapm_path *path;
843 int found = 0;
844
Peter Ujfalusieff317d2009-01-15 14:40:47 +0200845 if (widget->id != snd_soc_dapm_mux &&
846 widget->id != snd_soc_dapm_value_mux)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200847 return -ENODEV;
848
849 if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
850 return 0;
851
852 /* find dapm widget path assoc with kcontrol */
853 list_for_each_entry(path, &widget->codec->dapm_paths, list) {
854 if (path->kcontrol != kcontrol)
855 continue;
856
Richard Zhaocb01e2b2008-10-07 08:05:20 +0800857 if (!path->name || !e->texts[mux])
Richard Purdie2b97eab2006-10-06 18:32:18 +0200858 continue;
859
860 found = 1;
861 /* we now need to match the string in the enum to the path */
Richard Zhaocb01e2b2008-10-07 08:05:20 +0800862 if (!(strcmp(path->name, e->texts[mux])))
Richard Purdie2b97eab2006-10-06 18:32:18 +0200863 path->connect = 1; /* new connection */
864 else
865 path->connect = 0; /* old connection must be powered down */
866 }
867
Mark Brown3fccd8b2008-07-07 19:26:04 +0100868 if (found) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200869 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
Mark Brown3fccd8b2008-07-07 19:26:04 +0100870 dump_dapm(widget->codec, "mux power update");
871 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200872
873 return 0;
874}
Richard Purdie2b97eab2006-10-06 18:32:18 +0200875
Milan plzik1b075e32008-01-10 14:39:46 +0100876/* test and update the power status of a mixer or switch widget */
Adrian Bunkd9c96cf2006-11-28 12:10:09 +0100877static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
878 struct snd_kcontrol *kcontrol, int reg,
879 int val_mask, int val, int invert)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200880{
881 struct snd_soc_dapm_path *path;
882 int found = 0;
883
Milan plzik1b075e32008-01-10 14:39:46 +0100884 if (widget->id != snd_soc_dapm_mixer &&
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000885 widget->id != snd_soc_dapm_mixer_named_ctl &&
Milan plzik1b075e32008-01-10 14:39:46 +0100886 widget->id != snd_soc_dapm_switch)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200887 return -ENODEV;
888
889 if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
890 return 0;
891
892 /* find dapm widget path assoc with kcontrol */
893 list_for_each_entry(path, &widget->codec->dapm_paths, list) {
894 if (path->kcontrol != kcontrol)
895 continue;
896
897 /* found, now check type */
898 found = 1;
899 if (val)
900 /* new connection */
901 path->connect = invert ? 0:1;
902 else
903 /* old connection must be powered down */
904 path->connect = invert ? 1:0;
905 break;
906 }
907
Mark Brown3fccd8b2008-07-07 19:26:04 +0100908 if (found) {
Richard Purdie2b97eab2006-10-06 18:32:18 +0200909 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
Mark Brown3fccd8b2008-07-07 19:26:04 +0100910 dump_dapm(widget->codec, "mixer power update");
911 }
Richard Purdie2b97eab2006-10-06 18:32:18 +0200912
913 return 0;
914}
Richard Purdie2b97eab2006-10-06 18:32:18 +0200915
916/* show dapm widget status in sys fs */
917static ssize_t dapm_widget_show(struct device *dev,
918 struct device_attribute *attr, char *buf)
919{
920 struct snd_soc_device *devdata = dev_get_drvdata(dev);
Mark Brown6627a652009-01-23 22:55:23 +0000921 struct snd_soc_codec *codec = devdata->card->codec;
Richard Purdie2b97eab2006-10-06 18:32:18 +0200922 struct snd_soc_dapm_widget *w;
923 int count = 0;
924 char *state = "not set";
925
926 list_for_each_entry(w, &codec->dapm_widgets, list) {
927
928 /* only display widgets that burnm power */
929 switch (w->id) {
930 case snd_soc_dapm_hp:
931 case snd_soc_dapm_mic:
932 case snd_soc_dapm_spk:
933 case snd_soc_dapm_line:
934 case snd_soc_dapm_micbias:
935 case snd_soc_dapm_dac:
936 case snd_soc_dapm_adc:
937 case snd_soc_dapm_pga:
938 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +0000939 case snd_soc_dapm_mixer_named_ctl:
Mark Brown246d0a12009-04-22 18:24:55 +0100940 case snd_soc_dapm_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +0200941 if (w->name)
942 count += sprintf(buf + count, "%s: %s\n",
943 w->name, w->power ? "On":"Off");
944 break;
945 default:
946 break;
947 }
948 }
949
Mark Brown0be98982008-05-19 12:31:28 +0200950 switch (codec->bias_level) {
951 case SND_SOC_BIAS_ON:
952 state = "On";
Richard Purdie2b97eab2006-10-06 18:32:18 +0200953 break;
Mark Brown0be98982008-05-19 12:31:28 +0200954 case SND_SOC_BIAS_PREPARE:
955 state = "Prepare";
Richard Purdie2b97eab2006-10-06 18:32:18 +0200956 break;
Mark Brown0be98982008-05-19 12:31:28 +0200957 case SND_SOC_BIAS_STANDBY:
958 state = "Standby";
Richard Purdie2b97eab2006-10-06 18:32:18 +0200959 break;
Mark Brown0be98982008-05-19 12:31:28 +0200960 case SND_SOC_BIAS_OFF:
961 state = "Off";
Richard Purdie2b97eab2006-10-06 18:32:18 +0200962 break;
963 }
964 count += sprintf(buf + count, "PM State: %s\n", state);
965
966 return count;
967}
968
969static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
970
971int snd_soc_dapm_sys_add(struct device *dev)
972{
Troy Kisky12ef1932008-10-13 17:42:14 -0700973 return device_create_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200974}
975
976static void snd_soc_dapm_sys_remove(struct device *dev)
977{
Mark Brownaef90842009-05-16 17:53:16 +0100978 device_remove_file(dev, &dev_attr_dapm_widget);
Richard Purdie2b97eab2006-10-06 18:32:18 +0200979}
980
981/* free all dapm widgets and resources */
Adrian Bunkd9c96cf2006-11-28 12:10:09 +0100982static void dapm_free_widgets(struct snd_soc_codec *codec)
Richard Purdie2b97eab2006-10-06 18:32:18 +0200983{
984 struct snd_soc_dapm_widget *w, *next_w;
985 struct snd_soc_dapm_path *p, *next_p;
986
987 list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
988 list_del(&w->list);
989 kfree(w);
990 }
991
992 list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
993 list_del(&p->list);
994 kfree(p->long_name);
995 kfree(p);
996 }
997}
998
Liam Girdwooda5302182008-07-07 13:35:17 +0100999static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
Mark Brown16499232009-01-07 18:25:13 +00001000 const char *pin, int status)
Liam Girdwooda5302182008-07-07 13:35:17 +01001001{
1002 struct snd_soc_dapm_widget *w;
1003
1004 list_for_each_entry(w, &codec->dapm_widgets, list) {
1005 if (!strcmp(w->name, pin)) {
Mark Brownc1286b82008-07-07 19:26:03 +01001006 pr_debug("dapm: %s: pin %s\n", codec->name, pin);
Liam Girdwooda5302182008-07-07 13:35:17 +01001007 w->connected = status;
1008 return 0;
1009 }
1010 }
1011
Mark Brownc1286b82008-07-07 19:26:03 +01001012 pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin);
Liam Girdwooda5302182008-07-07 13:35:17 +01001013 return -EINVAL;
1014}
1015
Richard Purdie2b97eab2006-10-06 18:32:18 +02001016/**
Liam Girdwooda5302182008-07-07 13:35:17 +01001017 * snd_soc_dapm_sync - scan and power dapm paths
Richard Purdie2b97eab2006-10-06 18:32:18 +02001018 * @codec: audio codec
1019 *
1020 * Walks all dapm audio paths and powers widgets according to their
1021 * stream or path usage.
1022 *
1023 * Returns 0 for success.
1024 */
Liam Girdwooda5302182008-07-07 13:35:17 +01001025int snd_soc_dapm_sync(struct snd_soc_codec *codec)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001026{
Mark Brown3fccd8b2008-07-07 19:26:04 +01001027 int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
1028 dump_dapm(codec, "sync");
1029 return ret;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001030}
Liam Girdwooda5302182008-07-07 13:35:17 +01001031EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001032
Mark Brown105f1c22008-05-13 14:52:19 +02001033static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
1034 const char *sink, const char *control, const char *source)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001035{
1036 struct snd_soc_dapm_path *path;
1037 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
1038 int ret = 0;
1039
1040 /* find src and dest widgets */
1041 list_for_each_entry(w, &codec->dapm_widgets, list) {
1042
1043 if (!wsink && !(strcmp(w->name, sink))) {
1044 wsink = w;
1045 continue;
1046 }
1047 if (!wsource && !(strcmp(w->name, source))) {
1048 wsource = w;
1049 }
1050 }
1051
1052 if (wsource == NULL || wsink == NULL)
1053 return -ENODEV;
1054
1055 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
1056 if (!path)
1057 return -ENOMEM;
1058
1059 path->source = wsource;
1060 path->sink = wsink;
1061 INIT_LIST_HEAD(&path->list);
1062 INIT_LIST_HEAD(&path->list_source);
1063 INIT_LIST_HEAD(&path->list_sink);
1064
1065 /* check for external widgets */
1066 if (wsink->id == snd_soc_dapm_input) {
1067 if (wsource->id == snd_soc_dapm_micbias ||
1068 wsource->id == snd_soc_dapm_mic ||
Seth Forshee1e392212007-04-16 15:36:42 +02001069 wsink->id == snd_soc_dapm_line ||
1070 wsink->id == snd_soc_dapm_output)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001071 wsink->ext = 1;
1072 }
1073 if (wsource->id == snd_soc_dapm_output) {
1074 if (wsink->id == snd_soc_dapm_spk ||
1075 wsink->id == snd_soc_dapm_hp ||
Seth Forshee1e392212007-04-16 15:36:42 +02001076 wsink->id == snd_soc_dapm_line ||
1077 wsink->id == snd_soc_dapm_input)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001078 wsource->ext = 1;
1079 }
1080
1081 /* connect static paths */
1082 if (control == NULL) {
1083 list_add(&path->list, &codec->dapm_paths);
1084 list_add(&path->list_sink, &wsink->sources);
1085 list_add(&path->list_source, &wsource->sinks);
1086 path->connect = 1;
1087 return 0;
1088 }
1089
1090 /* connect dynamic paths */
1091 switch(wsink->id) {
1092 case snd_soc_dapm_adc:
1093 case snd_soc_dapm_dac:
1094 case snd_soc_dapm_pga:
1095 case snd_soc_dapm_input:
1096 case snd_soc_dapm_output:
1097 case snd_soc_dapm_micbias:
1098 case snd_soc_dapm_vmid:
1099 case snd_soc_dapm_pre:
1100 case snd_soc_dapm_post:
Mark Brown246d0a12009-04-22 18:24:55 +01001101 case snd_soc_dapm_supply:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001102 list_add(&path->list, &codec->dapm_paths);
1103 list_add(&path->list_sink, &wsink->sources);
1104 list_add(&path->list_source, &wsource->sinks);
1105 path->connect = 1;
1106 return 0;
1107 case snd_soc_dapm_mux:
Peter Ujfalusi74155552009-01-08 13:34:29 +02001108 case snd_soc_dapm_value_mux:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001109 ret = dapm_connect_mux(codec, wsource, wsink, path, control,
1110 &wsink->kcontrols[0]);
1111 if (ret != 0)
1112 goto err;
1113 break;
1114 case snd_soc_dapm_switch:
1115 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001116 case snd_soc_dapm_mixer_named_ctl:
Richard Purdie2b97eab2006-10-06 18:32:18 +02001117 ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
1118 if (ret != 0)
1119 goto err;
1120 break;
1121 case snd_soc_dapm_hp:
1122 case snd_soc_dapm_mic:
1123 case snd_soc_dapm_line:
1124 case snd_soc_dapm_spk:
1125 list_add(&path->list, &codec->dapm_paths);
1126 list_add(&path->list_sink, &wsink->sources);
1127 list_add(&path->list_source, &wsource->sinks);
1128 path->connect = 0;
1129 return 0;
1130 }
1131 return 0;
1132
1133err:
1134 printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
1135 control, sink);
1136 kfree(path);
1137 return ret;
1138}
Mark Brown105f1c22008-05-13 14:52:19 +02001139
1140/**
Mark Brown105f1c22008-05-13 14:52:19 +02001141 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
1142 * @codec: codec
1143 * @route: audio routes
1144 * @num: number of routes
1145 *
1146 * Connects 2 dapm widgets together via a named audio path. The sink is
1147 * the widget receiving the audio signal, whilst the source is the sender
1148 * of the audio signal.
1149 *
1150 * Returns 0 for success else error. On error all resources can be freed
1151 * with a call to snd_soc_card_free().
1152 */
1153int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
1154 const struct snd_soc_dapm_route *route, int num)
1155{
1156 int i, ret;
1157
1158 for (i = 0; i < num; i++) {
1159 ret = snd_soc_dapm_add_route(codec, route->sink,
1160 route->control, route->source);
1161 if (ret < 0) {
1162 printk(KERN_ERR "Failed to add route %s->%s\n",
1163 route->source,
1164 route->sink);
1165 return ret;
1166 }
1167 route++;
1168 }
1169
1170 return 0;
1171}
1172EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
1173
1174/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02001175 * snd_soc_dapm_new_widgets - add new dapm widgets
1176 * @codec: audio codec
1177 *
1178 * Checks the codec for any new dapm widgets and creates them if found.
1179 *
1180 * Returns 0 for success.
1181 */
1182int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
1183{
1184 struct snd_soc_dapm_widget *w;
1185
Richard Purdie2b97eab2006-10-06 18:32:18 +02001186 list_for_each_entry(w, &codec->dapm_widgets, list)
1187 {
1188 if (w->new)
1189 continue;
1190
1191 switch(w->id) {
1192 case snd_soc_dapm_switch:
1193 case snd_soc_dapm_mixer:
Ian Moltonca9c1aa2009-01-06 20:11:51 +00001194 case snd_soc_dapm_mixer_named_ctl:
Mark Brownb75576d2009-04-20 17:56:13 +01001195 w->power_check = dapm_generic_check_power;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001196 dapm_new_mixer(codec, w);
1197 break;
1198 case snd_soc_dapm_mux:
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02001199 case snd_soc_dapm_value_mux:
Mark Brownb75576d2009-04-20 17:56:13 +01001200 w->power_check = dapm_generic_check_power;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001201 dapm_new_mux(codec, w);
1202 break;
1203 case snd_soc_dapm_adc:
Mark Brownb75576d2009-04-20 17:56:13 +01001204 w->power_check = dapm_adc_check_power;
1205 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001206 case snd_soc_dapm_dac:
Mark Brownb75576d2009-04-20 17:56:13 +01001207 w->power_check = dapm_dac_check_power;
1208 break;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001209 case snd_soc_dapm_pga:
Mark Brownb75576d2009-04-20 17:56:13 +01001210 w->power_check = dapm_generic_check_power;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001211 dapm_new_pga(codec, w);
1212 break;
1213 case snd_soc_dapm_input:
1214 case snd_soc_dapm_output:
1215 case snd_soc_dapm_micbias:
1216 case snd_soc_dapm_spk:
1217 case snd_soc_dapm_hp:
1218 case snd_soc_dapm_mic:
1219 case snd_soc_dapm_line:
Mark Brownb75576d2009-04-20 17:56:13 +01001220 w->power_check = dapm_generic_check_power;
1221 break;
Mark Brown246d0a12009-04-22 18:24:55 +01001222 case snd_soc_dapm_supply:
1223 w->power_check = dapm_supply_check_power;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001224 case snd_soc_dapm_vmid:
1225 case snd_soc_dapm_pre:
1226 case snd_soc_dapm_post:
1227 break;
1228 }
1229 w->new = 1;
1230 }
1231
1232 dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001233 return 0;
1234}
1235EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
1236
1237/**
1238 * snd_soc_dapm_get_volsw - dapm mixer get callback
1239 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00001240 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02001241 *
1242 * Callback to get the value of a dapm mixer control.
1243 *
1244 * Returns 0 for success.
1245 */
1246int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1247 struct snd_ctl_elem_value *ucontrol)
1248{
1249 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
Jon Smirl4eaa9812008-07-29 11:42:26 +01001250 struct soc_mixer_control *mc =
1251 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04001252 unsigned int reg = mc->reg;
1253 unsigned int shift = mc->shift;
1254 unsigned int rshift = mc->rshift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01001255 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04001256 unsigned int invert = mc->invert;
1257 unsigned int mask = (1 << fls(max)) - 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001258
1259 /* return the saved value if we are powered down */
1260 if (widget->id == snd_soc_dapm_pga && !widget->power) {
1261 ucontrol->value.integer.value[0] = widget->saved_value;
1262 return 0;
1263 }
1264
1265 ucontrol->value.integer.value[0] =
1266 (snd_soc_read(widget->codec, reg) >> shift) & mask;
1267 if (shift != rshift)
1268 ucontrol->value.integer.value[1] =
1269 (snd_soc_read(widget->codec, reg) >> rshift) & mask;
1270 if (invert) {
1271 ucontrol->value.integer.value[0] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01001272 max - ucontrol->value.integer.value[0];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001273 if (shift != rshift)
1274 ucontrol->value.integer.value[1] =
Philipp Zabela7a4ac82008-01-10 14:37:42 +01001275 max - ucontrol->value.integer.value[1];
Richard Purdie2b97eab2006-10-06 18:32:18 +02001276 }
1277
1278 return 0;
1279}
1280EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
1281
1282/**
1283 * snd_soc_dapm_put_volsw - dapm mixer set callback
1284 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00001285 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02001286 *
1287 * Callback to set the value of a dapm mixer control.
1288 *
1289 * Returns 0 for success.
1290 */
1291int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1292 struct snd_ctl_elem_value *ucontrol)
1293{
1294 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
Jon Smirl4eaa9812008-07-29 11:42:26 +01001295 struct soc_mixer_control *mc =
1296 (struct soc_mixer_control *)kcontrol->private_value;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04001297 unsigned int reg = mc->reg;
1298 unsigned int shift = mc->shift;
1299 unsigned int rshift = mc->rshift;
Jon Smirl4eaa9812008-07-29 11:42:26 +01001300 int max = mc->max;
Jon Smirl815ecf8d2008-07-29 10:22:24 -04001301 unsigned int mask = (1 << fls(max)) - 1;
1302 unsigned int invert = mc->invert;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001303 unsigned short val, val2, val_mask;
1304 int ret;
1305
1306 val = (ucontrol->value.integer.value[0] & mask);
1307
1308 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01001309 val = max - val;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001310 val_mask = mask << shift;
1311 val = val << shift;
1312 if (shift != rshift) {
1313 val2 = (ucontrol->value.integer.value[1] & mask);
1314 if (invert)
Philipp Zabela7a4ac82008-01-10 14:37:42 +01001315 val2 = max - val2;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001316 val_mask |= mask << rshift;
1317 val |= val2 << rshift;
1318 }
1319
1320 mutex_lock(&widget->codec->mutex);
1321 widget->value = val;
1322
1323 /* save volume value if the widget is powered down */
1324 if (widget->id == snd_soc_dapm_pga && !widget->power) {
1325 widget->saved_value = val;
1326 mutex_unlock(&widget->codec->mutex);
1327 return 1;
1328 }
1329
1330 dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
1331 if (widget->event) {
1332 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
Laim Girdwood9af6d952008-01-10 14:41:02 +01001333 ret = widget->event(widget, kcontrol,
1334 SND_SOC_DAPM_PRE_REG);
1335 if (ret < 0) {
1336 ret = 1;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001337 goto out;
Laim Girdwood9af6d952008-01-10 14:41:02 +01001338 }
Richard Purdie2b97eab2006-10-06 18:32:18 +02001339 }
1340 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1341 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
Laim Girdwood9af6d952008-01-10 14:41:02 +01001342 ret = widget->event(widget, kcontrol,
1343 SND_SOC_DAPM_POST_REG);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001344 } else
1345 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1346
1347out:
1348 mutex_unlock(&widget->codec->mutex);
1349 return ret;
1350}
1351EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
1352
1353/**
1354 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
1355 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00001356 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02001357 *
1358 * Callback to get the value of a dapm enumerated double mixer control.
1359 *
1360 * Returns 0 for success.
1361 */
1362int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
1363 struct snd_ctl_elem_value *ucontrol)
1364{
1365 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1366 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1367 unsigned short val, bitmask;
1368
Jon Smirlf8ba0b72008-07-29 11:42:27 +01001369 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001370 ;
1371 val = snd_soc_read(widget->codec, e->reg);
1372 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
1373 if (e->shift_l != e->shift_r)
1374 ucontrol->value.enumerated.item[1] =
1375 (val >> e->shift_r) & (bitmask - 1);
1376
1377 return 0;
1378}
1379EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
1380
1381/**
1382 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
1383 * @kcontrol: mixer control
Mark Brownac11a2b2009-01-01 12:18:17 +00001384 * @ucontrol: control element information
Richard Purdie2b97eab2006-10-06 18:32:18 +02001385 *
1386 * Callback to set the value of a dapm enumerated double mixer control.
1387 *
1388 * Returns 0 for success.
1389 */
1390int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1391 struct snd_ctl_elem_value *ucontrol)
1392{
1393 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1394 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1395 unsigned short val, mux;
1396 unsigned short mask, bitmask;
1397 int ret = 0;
1398
Jon Smirlf8ba0b72008-07-29 11:42:27 +01001399 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001400 ;
Jon Smirlf8ba0b72008-07-29 11:42:27 +01001401 if (ucontrol->value.enumerated.item[0] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001402 return -EINVAL;
1403 mux = ucontrol->value.enumerated.item[0];
1404 val = mux << e->shift_l;
1405 mask = (bitmask - 1) << e->shift_l;
1406 if (e->shift_l != e->shift_r) {
Jon Smirlf8ba0b72008-07-29 11:42:27 +01001407 if (ucontrol->value.enumerated.item[1] > e->max - 1)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001408 return -EINVAL;
1409 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
1410 mask |= (bitmask - 1) << e->shift_r;
1411 }
1412
1413 mutex_lock(&widget->codec->mutex);
1414 widget->value = val;
Richard Zhaocb01e2b2008-10-07 08:05:20 +08001415 dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001416 if (widget->event) {
1417 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
Laim Girdwood9af6d952008-01-10 14:41:02 +01001418 ret = widget->event(widget,
1419 kcontrol, SND_SOC_DAPM_PRE_REG);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001420 if (ret < 0)
1421 goto out;
1422 }
1423 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1424 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
Laim Girdwood9af6d952008-01-10 14:41:02 +01001425 ret = widget->event(widget,
1426 kcontrol, SND_SOC_DAPM_POST_REG);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001427 } else
1428 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1429
1430out:
1431 mutex_unlock(&widget->codec->mutex);
1432 return ret;
1433}
1434EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
1435
1436/**
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02001437 * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
1438 * callback
1439 * @kcontrol: mixer control
1440 * @ucontrol: control element information
1441 *
1442 * Callback to get the value of a dapm semi enumerated double mixer control.
1443 *
1444 * Semi enumerated mixer: the enumerated items are referred as values. Can be
1445 * used for handling bitfield coded enumeration for example.
1446 *
1447 * Returns 0 for success.
1448 */
1449int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
1450 struct snd_ctl_elem_value *ucontrol)
1451{
1452 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
Peter Ujfalusi74155552009-01-08 13:34:29 +02001453 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02001454 unsigned short reg_val, val, mux;
1455
1456 reg_val = snd_soc_read(widget->codec, e->reg);
1457 val = (reg_val >> e->shift_l) & e->mask;
1458 for (mux = 0; mux < e->max; mux++) {
1459 if (val == e->values[mux])
1460 break;
1461 }
1462 ucontrol->value.enumerated.item[0] = mux;
1463 if (e->shift_l != e->shift_r) {
1464 val = (reg_val >> e->shift_r) & e->mask;
1465 for (mux = 0; mux < e->max; mux++) {
1466 if (val == e->values[mux])
1467 break;
1468 }
1469 ucontrol->value.enumerated.item[1] = mux;
1470 }
1471
1472 return 0;
1473}
1474EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
1475
1476/**
1477 * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
1478 * callback
1479 * @kcontrol: mixer control
1480 * @ucontrol: control element information
1481 *
1482 * Callback to set the value of a dapm semi enumerated double mixer control.
1483 *
1484 * Semi enumerated mixer: the enumerated items are referred as values. Can be
1485 * used for handling bitfield coded enumeration for example.
1486 *
1487 * Returns 0 for success.
1488 */
1489int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
1490 struct snd_ctl_elem_value *ucontrol)
1491{
1492 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
Peter Ujfalusi74155552009-01-08 13:34:29 +02001493 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02001494 unsigned short val, mux;
1495 unsigned short mask;
1496 int ret = 0;
1497
1498 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1499 return -EINVAL;
1500 mux = ucontrol->value.enumerated.item[0];
1501 val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
1502 mask = e->mask << e->shift_l;
1503 if (e->shift_l != e->shift_r) {
1504 if (ucontrol->value.enumerated.item[1] > e->max - 1)
1505 return -EINVAL;
1506 val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
1507 mask |= e->mask << e->shift_r;
1508 }
1509
1510 mutex_lock(&widget->codec->mutex);
1511 widget->value = val;
Peter Ujfalusi74155552009-01-08 13:34:29 +02001512 dapm_mux_update_power(widget, kcontrol, mask, mux, val, e);
Peter Ujfalusi2e72f8e2009-01-05 09:54:57 +02001513 if (widget->event) {
1514 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1515 ret = widget->event(widget,
1516 kcontrol, SND_SOC_DAPM_PRE_REG);
1517 if (ret < 0)
1518 goto out;
1519 }
1520 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1521 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1522 ret = widget->event(widget,
1523 kcontrol, SND_SOC_DAPM_POST_REG);
1524 } else
1525 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1526
1527out:
1528 mutex_unlock(&widget->codec->mutex);
1529 return ret;
1530}
1531EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
1532
1533/**
Mark Brown8b37dbd2009-02-28 21:14:20 +00001534 * snd_soc_dapm_info_pin_switch - Info for a pin switch
1535 *
1536 * @kcontrol: mixer control
1537 * @uinfo: control element information
1538 *
1539 * Callback to provide information about a pin switch control.
1540 */
1541int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
1542 struct snd_ctl_elem_info *uinfo)
1543{
1544 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1545 uinfo->count = 1;
1546 uinfo->value.integer.min = 0;
1547 uinfo->value.integer.max = 1;
1548
1549 return 0;
1550}
1551EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);
1552
1553/**
1554 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
1555 *
1556 * @kcontrol: mixer control
1557 * @ucontrol: Value
1558 */
1559int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
1560 struct snd_ctl_elem_value *ucontrol)
1561{
1562 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1563 const char *pin = (const char *)kcontrol->private_value;
1564
1565 mutex_lock(&codec->mutex);
1566
1567 ucontrol->value.integer.value[0] =
1568 snd_soc_dapm_get_pin_status(codec, pin);
1569
1570 mutex_unlock(&codec->mutex);
1571
1572 return 0;
1573}
1574EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);
1575
1576/**
1577 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
1578 *
1579 * @kcontrol: mixer control
1580 * @ucontrol: Value
1581 */
1582int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
1583 struct snd_ctl_elem_value *ucontrol)
1584{
1585 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1586 const char *pin = (const char *)kcontrol->private_value;
1587
1588 mutex_lock(&codec->mutex);
1589
1590 if (ucontrol->value.integer.value[0])
1591 snd_soc_dapm_enable_pin(codec, pin);
1592 else
1593 snd_soc_dapm_disable_pin(codec, pin);
1594
1595 snd_soc_dapm_sync(codec);
1596
1597 mutex_unlock(&codec->mutex);
1598
1599 return 0;
1600}
1601EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
1602
1603/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02001604 * snd_soc_dapm_new_control - create new dapm control
1605 * @codec: audio codec
1606 * @widget: widget template
1607 *
1608 * Creates a new dapm control based upon the template.
1609 *
1610 * Returns 0 for success else error.
1611 */
1612int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
1613 const struct snd_soc_dapm_widget *widget)
1614{
1615 struct snd_soc_dapm_widget *w;
1616
1617 if ((w = dapm_cnew_widget(widget)) == NULL)
1618 return -ENOMEM;
1619
1620 w->codec = codec;
1621 INIT_LIST_HEAD(&w->sources);
1622 INIT_LIST_HEAD(&w->sinks);
1623 INIT_LIST_HEAD(&w->list);
1624 list_add(&w->list, &codec->dapm_widgets);
1625
1626 /* machine layer set ups unconnected pins and insertions */
1627 w->connected = 1;
1628 return 0;
1629}
1630EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
1631
1632/**
Mark Brown4ba13272008-05-13 14:51:19 +02001633 * snd_soc_dapm_new_controls - create new dapm controls
1634 * @codec: audio codec
1635 * @widget: widget array
1636 * @num: number of widgets
1637 *
1638 * Creates new DAPM controls based upon the templates.
1639 *
1640 * Returns 0 for success else error.
1641 */
1642int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
1643 const struct snd_soc_dapm_widget *widget,
1644 int num)
1645{
1646 int i, ret;
1647
1648 for (i = 0; i < num; i++) {
1649 ret = snd_soc_dapm_new_control(codec, widget);
Mark Brownb8b33cb2008-12-18 11:19:30 +00001650 if (ret < 0) {
1651 printk(KERN_ERR
1652 "ASoC: Failed to create DAPM control %s: %d\n",
1653 widget->name, ret);
Mark Brown4ba13272008-05-13 14:51:19 +02001654 return ret;
Mark Brownb8b33cb2008-12-18 11:19:30 +00001655 }
Mark Brown4ba13272008-05-13 14:51:19 +02001656 widget++;
1657 }
1658 return 0;
1659}
1660EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
1661
1662
1663/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02001664 * snd_soc_dapm_stream_event - send a stream event to the dapm core
1665 * @codec: audio codec
1666 * @stream: stream name
1667 * @event: stream event
1668 *
1669 * Sends a stream event to the dapm core. The core then makes any
1670 * necessary widget power changes.
1671 *
1672 * Returns 0 for success else error.
1673 */
1674int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1675 char *stream, int event)
1676{
1677 struct snd_soc_dapm_widget *w;
1678
Seth Forshee11da21a2007-02-02 17:14:19 +01001679 if (stream == NULL)
1680 return 0;
1681
Richard Purdie2b97eab2006-10-06 18:32:18 +02001682 mutex_lock(&codec->mutex);
1683 list_for_each_entry(w, &codec->dapm_widgets, list)
1684 {
1685 if (!w->sname)
1686 continue;
Mark Brownc1286b82008-07-07 19:26:03 +01001687 pr_debug("widget %s\n %s stream %s event %d\n",
1688 w->name, w->sname, stream, event);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001689 if (strstr(w->sname, stream)) {
1690 switch(event) {
1691 case SND_SOC_DAPM_STREAM_START:
1692 w->active = 1;
1693 break;
1694 case SND_SOC_DAPM_STREAM_STOP:
1695 w->active = 0;
1696 break;
1697 case SND_SOC_DAPM_STREAM_SUSPEND:
1698 if (w->active)
1699 w->suspend = 1;
1700 w->active = 0;
1701 break;
1702 case SND_SOC_DAPM_STREAM_RESUME:
1703 if (w->suspend) {
1704 w->active = 1;
1705 w->suspend = 0;
1706 }
1707 break;
1708 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
1709 break;
1710 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
1711 break;
1712 }
1713 }
1714 }
1715 mutex_unlock(&codec->mutex);
1716
1717 dapm_power_widgets(codec, event);
Harvey Harrison9bf8e7d2008-03-03 15:32:18 -08001718 dump_dapm(codec, __func__);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001719 return 0;
1720}
1721EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
1722
1723/**
Mark Brown0be98982008-05-19 12:31:28 +02001724 * snd_soc_dapm_set_bias_level - set the bias level for the system
Liam Girdwood0b4d2212008-01-10 14:36:20 +01001725 * @socdev: audio device
Mark Brown0be98982008-05-19 12:31:28 +02001726 * @level: level to configure
Liam Girdwood0b4d2212008-01-10 14:36:20 +01001727 *
Mark Brown0be98982008-05-19 12:31:28 +02001728 * Configure the bias (power) levels for the SoC audio device.
Liam Girdwood0b4d2212008-01-10 14:36:20 +01001729 *
1730 * Returns 0 for success else error.
1731 */
Mark Brown0be98982008-05-19 12:31:28 +02001732int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
1733 enum snd_soc_bias_level level)
Liam Girdwood0b4d2212008-01-10 14:36:20 +01001734{
Mark Brown87506542008-11-18 20:50:34 +00001735 struct snd_soc_card *card = socdev->card;
Mark Brown6627a652009-01-23 22:55:23 +00001736 struct snd_soc_codec *codec = socdev->card->codec;
Mark Brown0be98982008-05-19 12:31:28 +02001737 int ret = 0;
Liam Girdwood0b4d2212008-01-10 14:36:20 +01001738
Mark Brown87506542008-11-18 20:50:34 +00001739 if (card->set_bias_level)
1740 ret = card->set_bias_level(card, level);
Mark Brown0be98982008-05-19 12:31:28 +02001741 if (ret == 0 && codec->set_bias_level)
1742 ret = codec->set_bias_level(codec, level);
1743
1744 return ret;
Liam Girdwood0b4d2212008-01-10 14:36:20 +01001745}
Liam Girdwood0b4d2212008-01-10 14:36:20 +01001746
1747/**
Liam Girdwooda5302182008-07-07 13:35:17 +01001748 * snd_soc_dapm_enable_pin - enable pin.
Mark Brownac11a2b2009-01-01 12:18:17 +00001749 * @codec: SoC codec
Liam Girdwooda5302182008-07-07 13:35:17 +01001750 * @pin: pin name
Richard Purdie2b97eab2006-10-06 18:32:18 +02001751 *
Liam Girdwooda5302182008-07-07 13:35:17 +01001752 * Enables input/output pin and it's parents or children widgets iff there is
1753 * a valid audio route and active audio stream.
1754 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
1755 * do any widget power switching.
Richard Purdie2b97eab2006-10-06 18:32:18 +02001756 */
Mark Brown16499232009-01-07 18:25:13 +00001757int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin)
Richard Purdie2b97eab2006-10-06 18:32:18 +02001758{
Liam Girdwooda5302182008-07-07 13:35:17 +01001759 return snd_soc_dapm_set_pin(codec, pin, 1);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001760}
Liam Girdwooda5302182008-07-07 13:35:17 +01001761EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
Richard Purdie2b97eab2006-10-06 18:32:18 +02001762
1763/**
Liam Girdwooda5302182008-07-07 13:35:17 +01001764 * snd_soc_dapm_disable_pin - disable pin.
1765 * @codec: SoC codec
1766 * @pin: pin name
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02001767 *
Liam Girdwooda5302182008-07-07 13:35:17 +01001768 * Disables input/output pin and it's parents or children widgets.
1769 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
1770 * do any widget power switching.
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02001771 */
Mark Brown16499232009-01-07 18:25:13 +00001772int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin)
Liam Girdwooda5302182008-07-07 13:35:17 +01001773{
1774 return snd_soc_dapm_set_pin(codec, pin, 0);
1775}
1776EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
1777
1778/**
Mark Brown5817b522008-09-24 11:23:11 +01001779 * snd_soc_dapm_nc_pin - permanently disable pin.
1780 * @codec: SoC codec
1781 * @pin: pin name
1782 *
1783 * Marks the specified pin as being not connected, disabling it along
1784 * any parent or child widgets. At present this is identical to
1785 * snd_soc_dapm_disable_pin() but in future it will be extended to do
1786 * additional things such as disabling controls which only affect
1787 * paths through the pin.
1788 *
1789 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
1790 * do any widget power switching.
1791 */
Mark Brown16499232009-01-07 18:25:13 +00001792int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin)
Mark Brown5817b522008-09-24 11:23:11 +01001793{
1794 return snd_soc_dapm_set_pin(codec, pin, 0);
1795}
1796EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
1797
1798/**
Liam Girdwooda5302182008-07-07 13:35:17 +01001799 * snd_soc_dapm_get_pin_status - get audio pin status
1800 * @codec: audio codec
1801 * @pin: audio signal pin endpoint (or start point)
1802 *
1803 * Get audio pin status - connected or disconnected.
1804 *
1805 * Returns 1 for connected otherwise 0.
1806 */
Mark Brown16499232009-01-07 18:25:13 +00001807int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin)
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02001808{
1809 struct snd_soc_dapm_widget *w;
1810
1811 list_for_each_entry(w, &codec->dapm_widgets, list) {
Liam Girdwooda5302182008-07-07 13:35:17 +01001812 if (!strcmp(w->name, pin))
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02001813 return w->connected;
1814 }
1815
1816 return 0;
1817}
Liam Girdwooda5302182008-07-07 13:35:17 +01001818EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
Graeme Gregoryeeec12b2008-04-30 19:27:40 +02001819
1820/**
Richard Purdie2b97eab2006-10-06 18:32:18 +02001821 * snd_soc_dapm_free - free dapm resources
1822 * @socdev: SoC device
1823 *
1824 * Free all dapm widgets and resources.
1825 */
1826void snd_soc_dapm_free(struct snd_soc_device *socdev)
1827{
Mark Brown6627a652009-01-23 22:55:23 +00001828 struct snd_soc_codec *codec = socdev->card->codec;
Richard Purdie2b97eab2006-10-06 18:32:18 +02001829
1830 snd_soc_dapm_sys_remove(socdev->dev);
1831 dapm_free_widgets(codec);
1832}
1833EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
1834
1835/* Module information */
Liam Girdwoodd3311242008-10-12 13:17:36 +01001836MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
Richard Purdie2b97eab2006-10-06 18:32:18 +02001837MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
1838MODULE_LICENSE("GPL");