[ALSA] ASoC: Clarify API for bias configuration
[safe/jmp/linux-2.6] / sound / soc / soc-dapm.c
1 /*
2  * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
3  *
4  * Copyright 2005 Wolfson Microelectronics PLC.
5  * Author: Liam Girdwood
6  *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
7  *
8  *  This program is free software; you can redistribute  it and/or modify it
9  *  under  the terms of  the GNU General  Public License as published by the
10  *  Free Software Foundation;  either version 2 of the  License, or (at your
11  *  option) any later version.
12  *
13  *  Features:
14  *    o Changes power status of internal codec blocks depending on the
15  *      dynamic configuration of codec internal audio paths and active
16  *      DAC's/ADC's.
17  *    o Platform power domain - can support external components i.e. amps and
18  *      mic/meadphone insertion events.
19  *    o Automatic Mic Bias support
20  *    o Jack insertion power event initiation - e.g. hp insertion will enable
21  *      sinks, dacs, etc
22  *    o Delayed powerdown of audio susbsystem to reduce pops between a quick
23  *      device reopen.
24  *
25  *  Todo:
26  *    o DAPM power change sequencing - allow for configurable per
27  *      codec sequences.
28  *    o Support for analogue bias optimisation.
29  *    o Support for reduced codec oversampling rates.
30  *    o Support for reduced codec bias currents.
31  */
32
33 #include <linux/module.h>
34 #include <linux/moduleparam.h>
35 #include <linux/init.h>
36 #include <linux/delay.h>
37 #include <linux/pm.h>
38 #include <linux/bitops.h>
39 #include <linux/platform_device.h>
40 #include <linux/jiffies.h>
41 #include <sound/core.h>
42 #include <sound/pcm.h>
43 #include <sound/pcm_params.h>
44 #include <sound/soc-dapm.h>
45 #include <sound/initval.h>
46
47 /* debug */
48 #define DAPM_DEBUG 0
49 #if DAPM_DEBUG
50 #define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
51 #define dbg(format, arg...) printk(format, ## arg)
52 #else
53 #define dump_dapm(codec, action)
54 #define dbg(format, arg...)
55 #endif
56
57 #define POP_DEBUG 0
58 #if POP_DEBUG
59 #define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */
60 #define pop_wait(time) schedule_timeout_uninterruptible(msecs_to_jiffies(time))
61 #define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME)
62 #else
63 #define pop_dbg(format, arg...)
64 #define pop_wait(time)
65 #endif
66
67 /* dapm power sequences - make this per codec in the future */
68 static int dapm_up_seq[] = {
69         snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
70         snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga,
71         snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
72 };
73 static int dapm_down_seq[] = {
74         snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
75         snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
76         snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post
77 };
78
79 static int dapm_status = 1;
80 module_param(dapm_status, int, 0);
81 MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
82
83 /* create a new dapm widget */
84 static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
85         const struct snd_soc_dapm_widget *_widget)
86 {
87         return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
88 }
89
90 /* set up initial codec paths */
91 static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
92         struct snd_soc_dapm_path *p, int i)
93 {
94         switch (w->id) {
95         case snd_soc_dapm_switch:
96         case snd_soc_dapm_mixer: {
97                 int val;
98                 int reg = w->kcontrols[i].private_value & 0xff;
99                 int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
100                 int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
101                 int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
102
103                 val = snd_soc_read(w->codec, reg);
104                 val = (val >> shift) & mask;
105
106                 if ((invert && !val) || (!invert && val))
107                         p->connect = 1;
108                 else
109                         p->connect = 0;
110         }
111         break;
112         case snd_soc_dapm_mux: {
113                 struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
114                 int val, item, bitmask;
115
116                 for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
117                 ;
118                 val = snd_soc_read(w->codec, e->reg);
119                 item = (val >> e->shift_l) & (bitmask - 1);
120
121                 p->connect = 0;
122                 for (i = 0; i < e->mask; i++) {
123                         if (!(strcmp(p->name, e->texts[i])) && item == i)
124                                 p->connect = 1;
125                 }
126         }
127         break;
128         /* does not effect routing - always connected */
129         case snd_soc_dapm_pga:
130         case snd_soc_dapm_output:
131         case snd_soc_dapm_adc:
132         case snd_soc_dapm_input:
133         case snd_soc_dapm_dac:
134         case snd_soc_dapm_micbias:
135         case snd_soc_dapm_vmid:
136                 p->connect = 1;
137         break;
138         /* does effect routing - dynamically connected */
139         case snd_soc_dapm_hp:
140         case snd_soc_dapm_mic:
141         case snd_soc_dapm_spk:
142         case snd_soc_dapm_line:
143         case snd_soc_dapm_pre:
144         case snd_soc_dapm_post:
145                 p->connect = 0;
146         break;
147         }
148 }
149
150 /* connect mux widget to it's interconnecting audio paths */
151 static int dapm_connect_mux(struct snd_soc_codec *codec,
152         struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
153         struct snd_soc_dapm_path *path, const char *control_name,
154         const struct snd_kcontrol_new *kcontrol)
155 {
156         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
157         int i;
158
159         for (i = 0; i < e->mask; i++) {
160                 if (!(strcmp(control_name, e->texts[i]))) {
161                         list_add(&path->list, &codec->dapm_paths);
162                         list_add(&path->list_sink, &dest->sources);
163                         list_add(&path->list_source, &src->sinks);
164                         path->name = (char*)e->texts[i];
165                         dapm_set_path_status(dest, path, 0);
166                         return 0;
167                 }
168         }
169
170         return -ENODEV;
171 }
172
173 /* connect mixer widget to it's interconnecting audio paths */
174 static int dapm_connect_mixer(struct snd_soc_codec *codec,
175         struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
176         struct snd_soc_dapm_path *path, const char *control_name)
177 {
178         int i;
179
180         /* search for mixer kcontrol */
181         for (i = 0; i < dest->num_kcontrols; i++) {
182                 if (!strcmp(control_name, dest->kcontrols[i].name)) {
183                         list_add(&path->list, &codec->dapm_paths);
184                         list_add(&path->list_sink, &dest->sources);
185                         list_add(&path->list_source, &src->sinks);
186                         path->name = dest->kcontrols[i].name;
187                         dapm_set_path_status(dest, path, i);
188                         return 0;
189                 }
190         }
191         return -ENODEV;
192 }
193
194 /* update dapm codec register bits */
195 static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
196 {
197         int change, power;
198         unsigned short old, new;
199         struct snd_soc_codec *codec = widget->codec;
200
201         /* check for valid widgets */
202         if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
203                 widget->id == snd_soc_dapm_output ||
204                 widget->id == snd_soc_dapm_hp ||
205                 widget->id == snd_soc_dapm_mic ||
206                 widget->id == snd_soc_dapm_line ||
207                 widget->id == snd_soc_dapm_spk)
208                 return 0;
209
210         power = widget->power;
211         if (widget->invert)
212                 power = (power ? 0:1);
213
214         old = snd_soc_read(codec, widget->reg);
215         new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
216
217         change = old != new;
218         if (change) {
219                 pop_dbg("pop test %s : %s in %d ms\n", widget->name,
220                         widget->power ? "on" : "off", POP_TIME);
221                 snd_soc_write(codec, widget->reg, new);
222                 pop_wait(POP_TIME);
223         }
224         dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change);
225         return change;
226 }
227
228 /* ramps the volume up or down to minimise pops before or after a
229  * DAPM power event */
230 static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
231 {
232         const struct snd_kcontrol_new *k = widget->kcontrols;
233
234         if (widget->muted && !power)
235                 return 0;
236         if (!widget->muted && power)
237                 return 0;
238
239         if (widget->num_kcontrols && k) {
240                 int reg = k->private_value & 0xff;
241                 int shift = (k->private_value >> 8) & 0x0f;
242                 int mask = (k->private_value >> 16) & 0xff;
243                 int invert = (k->private_value >> 24) & 0x01;
244
245                 if (power) {
246                         int i;
247                         /* power up has happended, increase volume to last level */
248                         if (invert) {
249                                 for (i = mask; i > widget->saved_value; i--)
250                                         snd_soc_update_bits(widget->codec, reg, mask, i);
251                         } else {
252                                 for (i = 0; i < widget->saved_value; i++)
253                                         snd_soc_update_bits(widget->codec, reg, mask, i);
254                         }
255                         widget->muted = 0;
256                 } else {
257                         /* power down is about to occur, decrease volume to mute */
258                         int val = snd_soc_read(widget->codec, reg);
259                         int i = widget->saved_value = (val >> shift) & mask;
260                         if (invert) {
261                                 for (; i < mask; i++)
262                                         snd_soc_update_bits(widget->codec, reg, mask, i);
263                         } else {
264                                 for (; i > 0; i--)
265                                         snd_soc_update_bits(widget->codec, reg, mask, i);
266                         }
267                         widget->muted = 1;
268                 }
269         }
270         return 0;
271 }
272
273 /* create new dapm mixer control */
274 static int dapm_new_mixer(struct snd_soc_codec *codec,
275         struct snd_soc_dapm_widget *w)
276 {
277         int i, ret = 0;
278         char name[32];
279         struct snd_soc_dapm_path *path;
280
281         /* add kcontrol */
282         for (i = 0; i < w->num_kcontrols; i++) {
283
284                 /* match name */
285                 list_for_each_entry(path, &w->sources, list_sink) {
286
287                         /* mixer/mux paths name must match control name */
288                         if (path->name != (char*)w->kcontrols[i].name)
289                                 continue;
290
291                         /* add dapm control with long name */
292                         snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name);
293                         path->long_name = kstrdup (name, GFP_KERNEL);
294                         if (path->long_name == NULL)
295                                 return -ENOMEM;
296
297                         path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
298                                 path->long_name);
299                         ret = snd_ctl_add(codec->card, path->kcontrol);
300                         if (ret < 0) {
301                                 printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n",
302                                                 path->long_name);
303                                 kfree(path->long_name);
304                                 path->long_name = NULL;
305                                 return ret;
306                         }
307                 }
308         }
309         return ret;
310 }
311
312 /* create new dapm mux control */
313 static int dapm_new_mux(struct snd_soc_codec *codec,
314         struct snd_soc_dapm_widget *w)
315 {
316         struct snd_soc_dapm_path *path = NULL;
317         struct snd_kcontrol *kcontrol;
318         int ret = 0;
319
320         if (!w->num_kcontrols) {
321                 printk(KERN_ERR "asoc: mux %s has no controls\n", w->name);
322                 return -EINVAL;
323         }
324
325         kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
326         ret = snd_ctl_add(codec->card, kcontrol);
327         if (ret < 0)
328                 goto err;
329
330         list_for_each_entry(path, &w->sources, list_sink)
331                 path->kcontrol = kcontrol;
332
333         return ret;
334
335 err:
336         printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
337         return ret;
338 }
339
340 /* create new dapm volume control */
341 static int dapm_new_pga(struct snd_soc_codec *codec,
342         struct snd_soc_dapm_widget *w)
343 {
344         struct snd_kcontrol *kcontrol;
345         int ret = 0;
346
347         if (!w->num_kcontrols)
348                 return -EINVAL;
349
350         kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
351         ret = snd_ctl_add(codec->card, kcontrol);
352         if (ret < 0) {
353                 printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
354                 return ret;
355         }
356
357         return ret;
358 }
359
360 /* reset 'walked' bit for each dapm path */
361 static inline void dapm_clear_walk(struct snd_soc_codec *codec)
362 {
363         struct snd_soc_dapm_path *p;
364
365         list_for_each_entry(p, &codec->dapm_paths, list)
366                 p->walked = 0;
367 }
368
369 /*
370  * Recursively check for a completed path to an active or physically connected
371  * output widget. Returns number of complete paths.
372  */
373 static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
374 {
375         struct snd_soc_dapm_path *path;
376         int con = 0;
377
378         if (widget->id == snd_soc_dapm_adc && widget->active)
379                 return 1;
380
381         if (widget->connected) {
382                 /* connected pin ? */
383                 if (widget->id == snd_soc_dapm_output && !widget->ext)
384                         return 1;
385
386                 /* connected jack or spk ? */
387                 if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
388                         widget->id == snd_soc_dapm_line)
389                         return 1;
390         }
391
392         list_for_each_entry(path, &widget->sinks, list_source) {
393                 if (path->walked)
394                         continue;
395
396                 if (path->sink && path->connect) {
397                         path->walked = 1;
398                         con += is_connected_output_ep(path->sink);
399                 }
400         }
401
402         return con;
403 }
404
405 /*
406  * Recursively check for a completed path to an active or physically connected
407  * input widget. Returns number of complete paths.
408  */
409 static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
410 {
411         struct snd_soc_dapm_path *path;
412         int con = 0;
413
414         /* active stream ? */
415         if (widget->id == snd_soc_dapm_dac && widget->active)
416                 return 1;
417
418         if (widget->connected) {
419                 /* connected pin ? */
420                 if (widget->id == snd_soc_dapm_input && !widget->ext)
421                         return 1;
422
423                 /* connected VMID/Bias for lower pops */
424                 if (widget->id == snd_soc_dapm_vmid)
425                         return 1;
426
427                 /* connected jack ? */
428                 if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line)
429                         return 1;
430         }
431
432         list_for_each_entry(path, &widget->sources, list_sink) {
433                 if (path->walked)
434                         continue;
435
436                 if (path->source && path->connect) {
437                         path->walked = 1;
438                         con += is_connected_input_ep(path->source);
439                 }
440         }
441
442         return con;
443 }
444
445 /*
446  * Scan each dapm widget for complete audio path.
447  * A complete path is a route that has valid endpoints i.e.:-
448  *
449  *  o DAC to output pin.
450  *  o Input Pin to ADC.
451  *  o Input pin to Output pin (bypass, sidetone)
452  *  o DAC to ADC (loopback).
453  */
454 static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
455 {
456         struct snd_soc_dapm_widget *w;
457         int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power;
458
459         /* do we have a sequenced stream event */
460         if (event == SND_SOC_DAPM_STREAM_START) {
461                 c = ARRAY_SIZE(dapm_up_seq);
462                 seq = dapm_up_seq;
463         } else if (event == SND_SOC_DAPM_STREAM_STOP) {
464                 c = ARRAY_SIZE(dapm_down_seq);
465                 seq = dapm_down_seq;
466         }
467
468         for(i = 0; i < c; i++) {
469                 list_for_each_entry(w, &codec->dapm_widgets, list) {
470
471                         /* is widget in stream order */
472                         if (seq && seq[i] && w->id != seq[i])
473                                 continue;
474
475                         /* vmid - no action */
476                         if (w->id == snd_soc_dapm_vmid)
477                                 continue;
478
479                         /* active ADC */
480                         if (w->id == snd_soc_dapm_adc && w->active) {
481                                 in = is_connected_input_ep(w);
482                                 dapm_clear_walk(w->codec);
483                                 w->power = (in != 0) ? 1 : 0;
484                                 dapm_update_bits(w);
485                                 continue;
486                         }
487
488                         /* active DAC */
489                         if (w->id == snd_soc_dapm_dac && w->active) {
490                                 out = is_connected_output_ep(w);
491                                 dapm_clear_walk(w->codec);
492                                 w->power = (out != 0) ? 1 : 0;
493                                 dapm_update_bits(w);
494                                 continue;
495                         }
496
497                         /* programmable gain/attenuation */
498                         if (w->id == snd_soc_dapm_pga) {
499                                 int on;
500                                 in = is_connected_input_ep(w);
501                                 dapm_clear_walk(w->codec);
502                                 out = is_connected_output_ep(w);
503                                 dapm_clear_walk(w->codec);
504                                 w->power = on = (out != 0 && in != 0) ? 1 : 0;
505
506                                 if (!on)
507                                         dapm_set_pga(w, on); /* lower volume to reduce pops */
508                                 dapm_update_bits(w);
509                                 if (on)
510                                         dapm_set_pga(w, on); /* restore volume from zero */
511
512                                 continue;
513                         }
514
515                         /* pre and post event widgets */
516                         if (w->id == snd_soc_dapm_pre) {
517                                 if (!w->event)
518                                         continue;
519
520                                 if (event == SND_SOC_DAPM_STREAM_START) {
521                                         ret = w->event(w,
522                                                 NULL, SND_SOC_DAPM_PRE_PMU);
523                                         if (ret < 0)
524                                                 return ret;
525                                 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
526                                         ret = w->event(w,
527                                                 NULL, SND_SOC_DAPM_PRE_PMD);
528                                         if (ret < 0)
529                                                 return ret;
530                                 }
531                                 continue;
532                         }
533                         if (w->id == snd_soc_dapm_post) {
534                                 if (!w->event)
535                                         continue;
536
537                                 if (event == SND_SOC_DAPM_STREAM_START) {
538                                         ret = w->event(w,
539                                                 NULL, SND_SOC_DAPM_POST_PMU);
540                                         if (ret < 0)
541                                                 return ret;
542                                 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
543                                         ret = w->event(w,
544                                                 NULL, SND_SOC_DAPM_POST_PMD);
545                                         if (ret < 0)
546                                                 return ret;
547                                 }
548                                 continue;
549                         }
550
551                         /* all other widgets */
552                         in = is_connected_input_ep(w);
553                         dapm_clear_walk(w->codec);
554                         out = is_connected_output_ep(w);
555                         dapm_clear_walk(w->codec);
556                         power = (out != 0 && in != 0) ? 1 : 0;
557                         power_change = (w->power == power) ? 0: 1;
558                         w->power = power;
559
560                         /* call any power change event handlers */
561                         if (power_change) {
562                                 if (w->event) {
563                                         dbg("power %s event for %s flags %x\n",
564                                                 w->power ? "on" : "off", w->name, w->event_flags);
565                                         if (power) {
566                                                 /* power up event */
567                                                 if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
568                                                         ret = w->event(w,
569                                                                 NULL, SND_SOC_DAPM_PRE_PMU);
570                                                         if (ret < 0)
571                                                                 return ret;
572                                                 }
573                                                 dapm_update_bits(w);
574                                                 if (w->event_flags & SND_SOC_DAPM_POST_PMU){
575                                                         ret = w->event(w,
576                                                                 NULL, SND_SOC_DAPM_POST_PMU);
577                                                         if (ret < 0)
578                                                                 return ret;
579                                                 }
580                                         } else {
581                                                 /* power down event */
582                                                 if (w->event_flags & SND_SOC_DAPM_PRE_PMD) {
583                                                         ret = w->event(w,
584                                                                 NULL, SND_SOC_DAPM_PRE_PMD);
585                                                         if (ret < 0)
586                                                                 return ret;
587                                                 }
588                                                 dapm_update_bits(w);
589                                                 if (w->event_flags & SND_SOC_DAPM_POST_PMD) {
590                                                         ret = w->event(w,
591                                                                 NULL, SND_SOC_DAPM_POST_PMD);
592                                                         if (ret < 0)
593                                                                 return ret;
594                                                 }
595                                         }
596                                 } else
597                                         /* no event handler */
598                                         dapm_update_bits(w);
599                         }
600                 }
601         }
602
603         return ret;
604 }
605
606 #if DAPM_DEBUG
607 static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
608 {
609         struct snd_soc_dapm_widget *w;
610         struct snd_soc_dapm_path *p = NULL;
611         int in, out;
612
613         printk("DAPM %s %s\n", codec->name, action);
614
615         list_for_each_entry(w, &codec->dapm_widgets, list) {
616
617                 /* only display widgets that effect routing */
618                 switch (w->id) {
619                 case snd_soc_dapm_pre:
620                 case snd_soc_dapm_post:
621                 case snd_soc_dapm_vmid:
622                         continue;
623                 case snd_soc_dapm_mux:
624                 case snd_soc_dapm_output:
625                 case snd_soc_dapm_input:
626                 case snd_soc_dapm_switch:
627                 case snd_soc_dapm_hp:
628                 case snd_soc_dapm_mic:
629                 case snd_soc_dapm_spk:
630                 case snd_soc_dapm_line:
631                 case snd_soc_dapm_micbias:
632                 case snd_soc_dapm_dac:
633                 case snd_soc_dapm_adc:
634                 case snd_soc_dapm_pga:
635                 case snd_soc_dapm_mixer:
636                         if (w->name) {
637                                 in = is_connected_input_ep(w);
638                                 dapm_clear_walk(w->codec);
639                                 out = is_connected_output_ep(w);
640                                 dapm_clear_walk(w->codec);
641                                 printk("%s: %s  in %d out %d\n", w->name,
642                                         w->power ? "On":"Off",in, out);
643
644                                 list_for_each_entry(p, &w->sources, list_sink) {
645                                         if (p->connect)
646                                                 printk(" in  %s %s\n", p->name ? p->name : "static",
647                                                         p->source->name);
648                                 }
649                                 list_for_each_entry(p, &w->sinks, list_source) {
650                                         if (p->connect)
651                                                 printk(" out %s %s\n", p->name ? p->name : "static",
652                                                         p->sink->name);
653                                 }
654                         }
655                 break;
656                 }
657         }
658 }
659 #endif
660
661 /* test and update the power status of a mux widget */
662 static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
663                                  struct snd_kcontrol *kcontrol, int mask,
664                                  int val, struct soc_enum* e)
665 {
666         struct snd_soc_dapm_path *path;
667         int found = 0;
668
669         if (widget->id != snd_soc_dapm_mux)
670                 return -ENODEV;
671
672         if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
673                 return 0;
674
675         /* find dapm widget path assoc with kcontrol */
676         list_for_each_entry(path, &widget->codec->dapm_paths, list) {
677                 if (path->kcontrol != kcontrol)
678                         continue;
679
680                 if (!path->name || ! e->texts[val])
681                         continue;
682
683                 found = 1;
684                 /* we now need to match the string in the enum to the path */
685                 if (!(strcmp(path->name, e->texts[val])))
686                         path->connect = 1; /* new connection */
687                 else
688                         path->connect = 0; /* old connection must be powered down */
689         }
690
691         if (found)
692                 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
693
694         return 0;
695 }
696
697 /* test and update the power status of a mixer or switch widget */
698 static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
699                                    struct snd_kcontrol *kcontrol, int reg,
700                                    int val_mask, int val, int invert)
701 {
702         struct snd_soc_dapm_path *path;
703         int found = 0;
704
705         if (widget->id != snd_soc_dapm_mixer &&
706             widget->id != snd_soc_dapm_switch)
707                 return -ENODEV;
708
709         if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
710                 return 0;
711
712         /* find dapm widget path assoc with kcontrol */
713         list_for_each_entry(path, &widget->codec->dapm_paths, list) {
714                 if (path->kcontrol != kcontrol)
715                         continue;
716
717                 /* found, now check type */
718                 found = 1;
719                 if (val)
720                         /* new connection */
721                         path->connect = invert ? 0:1;
722                 else
723                         /* old connection must be powered down */
724                         path->connect = invert ? 1:0;
725                 break;
726         }
727
728         if (found)
729                 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
730
731         return 0;
732 }
733
734 /* show dapm widget status in sys fs */
735 static ssize_t dapm_widget_show(struct device *dev,
736         struct device_attribute *attr, char *buf)
737 {
738         struct snd_soc_device *devdata = dev_get_drvdata(dev);
739         struct snd_soc_codec *codec = devdata->codec;
740         struct snd_soc_dapm_widget *w;
741         int count = 0;
742         char *state = "not set";
743
744         list_for_each_entry(w, &codec->dapm_widgets, list) {
745
746                 /* only display widgets that burnm power */
747                 switch (w->id) {
748                 case snd_soc_dapm_hp:
749                 case snd_soc_dapm_mic:
750                 case snd_soc_dapm_spk:
751                 case snd_soc_dapm_line:
752                 case snd_soc_dapm_micbias:
753                 case snd_soc_dapm_dac:
754                 case snd_soc_dapm_adc:
755                 case snd_soc_dapm_pga:
756                 case snd_soc_dapm_mixer:
757                         if (w->name)
758                                 count += sprintf(buf + count, "%s: %s\n",
759                                         w->name, w->power ? "On":"Off");
760                 break;
761                 default:
762                 break;
763                 }
764         }
765
766         switch (codec->bias_level) {
767         case SND_SOC_BIAS_ON:
768                 state = "On";
769                 break;
770         case SND_SOC_BIAS_PREPARE:
771                 state = "Prepare";
772                 break;
773         case SND_SOC_BIAS_STANDBY:
774                 state = "Standby";
775                 break;
776         case SND_SOC_BIAS_OFF:
777                 state = "Off";
778                 break;
779         }
780         count += sprintf(buf + count, "PM State: %s\n", state);
781
782         return count;
783 }
784
785 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
786
787 int snd_soc_dapm_sys_add(struct device *dev)
788 {
789         int ret = 0;
790
791         if (dapm_status)
792                 ret = device_create_file(dev, &dev_attr_dapm_widget);
793
794         return ret;
795 }
796
797 static void snd_soc_dapm_sys_remove(struct device *dev)
798 {
799         if (dapm_status)
800                 device_remove_file(dev, &dev_attr_dapm_widget);
801 }
802
803 /* free all dapm widgets and resources */
804 static void dapm_free_widgets(struct snd_soc_codec *codec)
805 {
806         struct snd_soc_dapm_widget *w, *next_w;
807         struct snd_soc_dapm_path *p, *next_p;
808
809         list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
810                 list_del(&w->list);
811                 kfree(w);
812         }
813
814         list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
815                 list_del(&p->list);
816                 kfree(p->long_name);
817                 kfree(p);
818         }
819 }
820
821 /**
822  * snd_soc_dapm_sync_endpoints - scan and power dapm paths
823  * @codec: audio codec
824  *
825  * Walks all dapm audio paths and powers widgets according to their
826  * stream or path usage.
827  *
828  * Returns 0 for success.
829  */
830 int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec)
831 {
832         return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
833 }
834 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints);
835
836 static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
837         const char *sink, const char *control, const char *source)
838 {
839         struct snd_soc_dapm_path *path;
840         struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
841         int ret = 0;
842
843         /* find src and dest widgets */
844         list_for_each_entry(w, &codec->dapm_widgets, list) {
845
846                 if (!wsink && !(strcmp(w->name, sink))) {
847                         wsink = w;
848                         continue;
849                 }
850                 if (!wsource && !(strcmp(w->name, source))) {
851                         wsource = w;
852                 }
853         }
854
855         if (wsource == NULL || wsink == NULL)
856                 return -ENODEV;
857
858         path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
859         if (!path)
860                 return -ENOMEM;
861
862         path->source = wsource;
863         path->sink = wsink;
864         INIT_LIST_HEAD(&path->list);
865         INIT_LIST_HEAD(&path->list_source);
866         INIT_LIST_HEAD(&path->list_sink);
867
868         /* check for external widgets */
869         if (wsink->id == snd_soc_dapm_input) {
870                 if (wsource->id == snd_soc_dapm_micbias ||
871                         wsource->id == snd_soc_dapm_mic ||
872                         wsink->id == snd_soc_dapm_line ||
873                         wsink->id == snd_soc_dapm_output)
874                         wsink->ext = 1;
875         }
876         if (wsource->id == snd_soc_dapm_output) {
877                 if (wsink->id == snd_soc_dapm_spk ||
878                         wsink->id == snd_soc_dapm_hp ||
879                         wsink->id == snd_soc_dapm_line ||
880                         wsink->id == snd_soc_dapm_input)
881                         wsource->ext = 1;
882         }
883
884         /* connect static paths */
885         if (control == NULL) {
886                 list_add(&path->list, &codec->dapm_paths);
887                 list_add(&path->list_sink, &wsink->sources);
888                 list_add(&path->list_source, &wsource->sinks);
889                 path->connect = 1;
890                 return 0;
891         }
892
893         /* connect dynamic paths */
894         switch(wsink->id) {
895         case snd_soc_dapm_adc:
896         case snd_soc_dapm_dac:
897         case snd_soc_dapm_pga:
898         case snd_soc_dapm_input:
899         case snd_soc_dapm_output:
900         case snd_soc_dapm_micbias:
901         case snd_soc_dapm_vmid:
902         case snd_soc_dapm_pre:
903         case snd_soc_dapm_post:
904                 list_add(&path->list, &codec->dapm_paths);
905                 list_add(&path->list_sink, &wsink->sources);
906                 list_add(&path->list_source, &wsource->sinks);
907                 path->connect = 1;
908                 return 0;
909         case snd_soc_dapm_mux:
910                 ret = dapm_connect_mux(codec, wsource, wsink, path, control,
911                         &wsink->kcontrols[0]);
912                 if (ret != 0)
913                         goto err;
914                 break;
915         case snd_soc_dapm_switch:
916         case snd_soc_dapm_mixer:
917                 ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
918                 if (ret != 0)
919                         goto err;
920                 break;
921         case snd_soc_dapm_hp:
922         case snd_soc_dapm_mic:
923         case snd_soc_dapm_line:
924         case snd_soc_dapm_spk:
925                 list_add(&path->list, &codec->dapm_paths);
926                 list_add(&path->list_sink, &wsink->sources);
927                 list_add(&path->list_source, &wsource->sinks);
928                 path->connect = 0;
929                 return 0;
930         }
931         return 0;
932
933 err:
934         printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
935                 control, sink);
936         kfree(path);
937         return ret;
938 }
939
940 /**
941  * snd_soc_dapm_connect_input - connect dapm widgets
942  * @codec: audio codec
943  * @sink: name of target widget
944  * @control: mixer control name
945  * @source: name of source name
946  *
947  * Connects 2 dapm widgets together via a named audio path. The sink is
948  * the widget receiving the audio signal, whilst the source is the sender
949  * of the audio signal.
950  *
951  * This function has been deprecated in favour of snd_soc_dapm_add_routes().
952  *
953  * Returns 0 for success else error.
954  */
955 int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
956         const char *control, const char *source)
957 {
958         return snd_soc_dapm_add_route(codec, sink, control, source);
959 }
960 EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
961
962 /**
963  * snd_soc_dapm_add_routes - Add routes between DAPM widgets
964  * @codec: codec
965  * @route: audio routes
966  * @num: number of routes
967  *
968  * Connects 2 dapm widgets together via a named audio path. The sink is
969  * the widget receiving the audio signal, whilst the source is the sender
970  * of the audio signal.
971  *
972  * Returns 0 for success else error. On error all resources can be freed
973  * with a call to snd_soc_card_free().
974  */
975 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
976                             const struct snd_soc_dapm_route *route, int num)
977 {
978         int i, ret;
979
980         for (i = 0; i < num; i++) {
981                 ret = snd_soc_dapm_add_route(codec, route->sink,
982                                              route->control, route->source);
983                 if (ret < 0) {
984                         printk(KERN_ERR "Failed to add route %s->%s\n",
985                                route->source,
986                                route->sink);
987                         return ret;
988                 }
989                 route++;
990         }
991
992         return 0;
993 }
994 EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
995
996 /**
997  * snd_soc_dapm_new_widgets - add new dapm widgets
998  * @codec: audio codec
999  *
1000  * Checks the codec for any new dapm widgets and creates them if found.
1001  *
1002  * Returns 0 for success.
1003  */
1004 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
1005 {
1006         struct snd_soc_dapm_widget *w;
1007
1008         list_for_each_entry(w, &codec->dapm_widgets, list)
1009         {
1010                 if (w->new)
1011                         continue;
1012
1013                 switch(w->id) {
1014                 case snd_soc_dapm_switch:
1015                 case snd_soc_dapm_mixer:
1016                         dapm_new_mixer(codec, w);
1017                         break;
1018                 case snd_soc_dapm_mux:
1019                         dapm_new_mux(codec, w);
1020                         break;
1021                 case snd_soc_dapm_adc:
1022                 case snd_soc_dapm_dac:
1023                 case snd_soc_dapm_pga:
1024                         dapm_new_pga(codec, w);
1025                         break;
1026                 case snd_soc_dapm_input:
1027                 case snd_soc_dapm_output:
1028                 case snd_soc_dapm_micbias:
1029                 case snd_soc_dapm_spk:
1030                 case snd_soc_dapm_hp:
1031                 case snd_soc_dapm_mic:
1032                 case snd_soc_dapm_line:
1033                 case snd_soc_dapm_vmid:
1034                 case snd_soc_dapm_pre:
1035                 case snd_soc_dapm_post:
1036                         break;
1037                 }
1038                 w->new = 1;
1039         }
1040
1041         dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
1042         return 0;
1043 }
1044 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
1045
1046 /**
1047  * snd_soc_dapm_get_volsw - dapm mixer get callback
1048  * @kcontrol: mixer control
1049  * @uinfo: control element information
1050  *
1051  * Callback to get the value of a dapm mixer control.
1052  *
1053  * Returns 0 for success.
1054  */
1055 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1056         struct snd_ctl_elem_value *ucontrol)
1057 {
1058         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1059         int reg = kcontrol->private_value & 0xff;
1060         int shift = (kcontrol->private_value >> 8) & 0x0f;
1061         int rshift = (kcontrol->private_value >> 12) & 0x0f;
1062         int max = (kcontrol->private_value >> 16) & 0xff;
1063         int invert = (kcontrol->private_value >> 24) & 0x01;
1064         int mask = (1 << fls(max)) - 1;
1065
1066         /* return the saved value if we are powered down */
1067         if (widget->id == snd_soc_dapm_pga && !widget->power) {
1068                 ucontrol->value.integer.value[0] = widget->saved_value;
1069                 return 0;
1070         }
1071
1072         ucontrol->value.integer.value[0] =
1073                 (snd_soc_read(widget->codec, reg) >> shift) & mask;
1074         if (shift != rshift)
1075                 ucontrol->value.integer.value[1] =
1076                         (snd_soc_read(widget->codec, reg) >> rshift) & mask;
1077         if (invert) {
1078                 ucontrol->value.integer.value[0] =
1079                         max - ucontrol->value.integer.value[0];
1080                 if (shift != rshift)
1081                         ucontrol->value.integer.value[1] =
1082                                 max - ucontrol->value.integer.value[1];
1083         }
1084
1085         return 0;
1086 }
1087 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
1088
1089 /**
1090  * snd_soc_dapm_put_volsw - dapm mixer set callback
1091  * @kcontrol: mixer control
1092  * @uinfo: control element information
1093  *
1094  * Callback to set the value of a dapm mixer control.
1095  *
1096  * Returns 0 for success.
1097  */
1098 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1099         struct snd_ctl_elem_value *ucontrol)
1100 {
1101         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1102         int reg = kcontrol->private_value & 0xff;
1103         int shift = (kcontrol->private_value >> 8) & 0x0f;
1104         int rshift = (kcontrol->private_value >> 12) & 0x0f;
1105         int max = (kcontrol->private_value >> 16) & 0xff;
1106         int mask = (1 << fls(max)) - 1;
1107         int invert = (kcontrol->private_value >> 24) & 0x01;
1108         unsigned short val, val2, val_mask;
1109         int ret;
1110
1111         val = (ucontrol->value.integer.value[0] & mask);
1112
1113         if (invert)
1114                 val = max - val;
1115         val_mask = mask << shift;
1116         val = val << shift;
1117         if (shift != rshift) {
1118                 val2 = (ucontrol->value.integer.value[1] & mask);
1119                 if (invert)
1120                         val2 = max - val2;
1121                 val_mask |= mask << rshift;
1122                 val |= val2 << rshift;
1123         }
1124
1125         mutex_lock(&widget->codec->mutex);
1126         widget->value = val;
1127
1128         /* save volume value if the widget is powered down */
1129         if (widget->id == snd_soc_dapm_pga && !widget->power) {
1130                 widget->saved_value = val;
1131                 mutex_unlock(&widget->codec->mutex);
1132                 return 1;
1133         }
1134
1135         dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
1136         if (widget->event) {
1137                 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1138                         ret = widget->event(widget, kcontrol,
1139                                                 SND_SOC_DAPM_PRE_REG);
1140                         if (ret < 0) {
1141                                 ret = 1;
1142                                 goto out;
1143                         }
1144                 }
1145                 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1146                 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1147                         ret = widget->event(widget, kcontrol,
1148                                                 SND_SOC_DAPM_POST_REG);
1149         } else
1150                 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1151
1152 out:
1153         mutex_unlock(&widget->codec->mutex);
1154         return ret;
1155 }
1156 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
1157
1158 /**
1159  * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
1160  * @kcontrol: mixer control
1161  * @uinfo: control element information
1162  *
1163  * Callback to get the value of a dapm enumerated double mixer control.
1164  *
1165  * Returns 0 for success.
1166  */
1167 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
1168         struct snd_ctl_elem_value *ucontrol)
1169 {
1170         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1171         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1172         unsigned short val, bitmask;
1173
1174         for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
1175                 ;
1176         val = snd_soc_read(widget->codec, e->reg);
1177         ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
1178         if (e->shift_l != e->shift_r)
1179                 ucontrol->value.enumerated.item[1] =
1180                         (val >> e->shift_r) & (bitmask - 1);
1181
1182         return 0;
1183 }
1184 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
1185
1186 /**
1187  * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
1188  * @kcontrol: mixer control
1189  * @uinfo: control element information
1190  *
1191  * Callback to set the value of a dapm enumerated double mixer control.
1192  *
1193  * Returns 0 for success.
1194  */
1195 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1196         struct snd_ctl_elem_value *ucontrol)
1197 {
1198         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1199         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1200         unsigned short val, mux;
1201         unsigned short mask, bitmask;
1202         int ret = 0;
1203
1204         for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
1205                 ;
1206         if (ucontrol->value.enumerated.item[0] > e->mask - 1)
1207                 return -EINVAL;
1208         mux = ucontrol->value.enumerated.item[0];
1209         val = mux << e->shift_l;
1210         mask = (bitmask - 1) << e->shift_l;
1211         if (e->shift_l != e->shift_r) {
1212                 if (ucontrol->value.enumerated.item[1] > e->mask - 1)
1213                         return -EINVAL;
1214                 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
1215                 mask |= (bitmask - 1) << e->shift_r;
1216         }
1217
1218         mutex_lock(&widget->codec->mutex);
1219         widget->value = val;
1220         dapm_mux_update_power(widget, kcontrol, mask, mux, e);
1221         if (widget->event) {
1222                 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1223                         ret = widget->event(widget,
1224                                 kcontrol, SND_SOC_DAPM_PRE_REG);
1225                         if (ret < 0)
1226                                 goto out;
1227                 }
1228                 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1229                 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1230                         ret = widget->event(widget,
1231                                 kcontrol, SND_SOC_DAPM_POST_REG);
1232         } else
1233                 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1234
1235 out:
1236         mutex_unlock(&widget->codec->mutex);
1237         return ret;
1238 }
1239 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
1240
1241 /**
1242  * snd_soc_dapm_new_control - create new dapm control
1243  * @codec: audio codec
1244  * @widget: widget template
1245  *
1246  * Creates a new dapm control based upon the template.
1247  *
1248  * Returns 0 for success else error.
1249  */
1250 int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
1251         const struct snd_soc_dapm_widget *widget)
1252 {
1253         struct snd_soc_dapm_widget *w;
1254
1255         if ((w = dapm_cnew_widget(widget)) == NULL)
1256                 return -ENOMEM;
1257
1258         w->codec = codec;
1259         INIT_LIST_HEAD(&w->sources);
1260         INIT_LIST_HEAD(&w->sinks);
1261         INIT_LIST_HEAD(&w->list);
1262         list_add(&w->list, &codec->dapm_widgets);
1263
1264         /* machine layer set ups unconnected pins and insertions */
1265         w->connected = 1;
1266         return 0;
1267 }
1268 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
1269
1270 /**
1271  * snd_soc_dapm_new_controls - create new dapm controls
1272  * @codec: audio codec
1273  * @widget: widget array
1274  * @num: number of widgets
1275  *
1276  * Creates new DAPM controls based upon the templates.
1277  *
1278  * Returns 0 for success else error.
1279  */
1280 int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
1281         const struct snd_soc_dapm_widget *widget,
1282         int num)
1283 {
1284         int i, ret;
1285
1286         for (i = 0; i < num; i++) {
1287                 ret = snd_soc_dapm_new_control(codec, widget);
1288                 if (ret < 0)
1289                         return ret;
1290                 widget++;
1291         }
1292         return 0;
1293 }
1294 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
1295
1296
1297 /**
1298  * snd_soc_dapm_stream_event - send a stream event to the dapm core
1299  * @codec: audio codec
1300  * @stream: stream name
1301  * @event: stream event
1302  *
1303  * Sends a stream event to the dapm core. The core then makes any
1304  * necessary widget power changes.
1305  *
1306  * Returns 0 for success else error.
1307  */
1308 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1309         char *stream, int event)
1310 {
1311         struct snd_soc_dapm_widget *w;
1312
1313         if (stream == NULL)
1314                 return 0;
1315
1316         mutex_lock(&codec->mutex);
1317         list_for_each_entry(w, &codec->dapm_widgets, list)
1318         {
1319                 if (!w->sname)
1320                         continue;
1321                 dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
1322                         stream, event);
1323                 if (strstr(w->sname, stream)) {
1324                         switch(event) {
1325                         case SND_SOC_DAPM_STREAM_START:
1326                                 w->active = 1;
1327                                 break;
1328                         case SND_SOC_DAPM_STREAM_STOP:
1329                                 w->active = 0;
1330                                 break;
1331                         case SND_SOC_DAPM_STREAM_SUSPEND:
1332                                 if (w->active)
1333                                         w->suspend = 1;
1334                                 w->active = 0;
1335                                 break;
1336                         case SND_SOC_DAPM_STREAM_RESUME:
1337                                 if (w->suspend) {
1338                                         w->active = 1;
1339                                         w->suspend = 0;
1340                                 }
1341                                 break;
1342                         case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
1343                                 break;
1344                         case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
1345                                 break;
1346                         }
1347                 }
1348         }
1349         mutex_unlock(&codec->mutex);
1350
1351         dapm_power_widgets(codec, event);
1352         dump_dapm(codec, __func__);
1353         return 0;
1354 }
1355 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
1356
1357 /**
1358  * snd_soc_dapm_set_bias_level - set the bias level for the system
1359  * @socdev: audio device
1360  * @level: level to configure
1361  *
1362  * Configure the bias (power) levels for the SoC audio device.
1363  *
1364  * Returns 0 for success else error.
1365  */
1366 int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
1367                                 enum snd_soc_bias_level level)
1368 {
1369         struct snd_soc_codec *codec = socdev->codec;
1370         struct snd_soc_machine *machine = socdev->machine;
1371         int ret = 0;
1372
1373         if (machine->set_bias_level)
1374                 ret = machine->set_bias_level(machine, level);
1375         if (ret == 0 && codec->set_bias_level)
1376                 ret = codec->set_bias_level(codec, level);
1377
1378         return ret;
1379 }
1380
1381 /**
1382  * snd_soc_dapm_set_endpoint - set audio endpoint status
1383  * @codec: audio codec
1384  * @endpoint: audio signal endpoint (or start point)
1385  * @status: point status
1386  *
1387  * Set audio endpoint status - connected or disconnected.
1388  *
1389  * Returns 0 for success else error.
1390  */
1391 int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
1392         char *endpoint, int status)
1393 {
1394         struct snd_soc_dapm_widget *w;
1395
1396         list_for_each_entry(w, &codec->dapm_widgets, list) {
1397                 if (!strcmp(w->name, endpoint)) {
1398                         w->connected = status;
1399                         return 0;
1400                 }
1401         }
1402
1403         return -ENODEV;
1404 }
1405 EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
1406
1407 /**
1408  * snd_soc_dapm_get_endpoint_status - get audio endpoint status
1409  * @codec: audio codec
1410  * @endpoint: audio signal endpoint (or start point)
1411  *
1412  * Get audio endpoint status - connected or disconnected.
1413  *
1414  * Returns status
1415  */
1416 int snd_soc_dapm_get_endpoint_status(struct snd_soc_codec *codec,
1417         char *endpoint)
1418 {
1419         struct snd_soc_dapm_widget *w;
1420
1421         list_for_each_entry(w, &codec->dapm_widgets, list) {
1422                 if (!strcmp(w->name, endpoint))
1423                         return w->connected;
1424         }
1425
1426         return 0;
1427 }
1428 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_endpoint_status);
1429
1430 /**
1431  * snd_soc_dapm_free - free dapm resources
1432  * @socdev: SoC device
1433  *
1434  * Free all dapm widgets and resources.
1435  */
1436 void snd_soc_dapm_free(struct snd_soc_device *socdev)
1437 {
1438         struct snd_soc_codec *codec = socdev->codec;
1439
1440         snd_soc_dapm_sys_remove(socdev->dev);
1441         dapm_free_widgets(codec);
1442 }
1443 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
1444
1445 /* Module information */
1446 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
1447 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
1448 MODULE_LICENSE("GPL");