[ALSA] ASoC: Remove in-code changelogs
[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->dapm_state){
767         case SNDRV_CTL_POWER_D0:
768                 state = "D0";
769                 break;
770         case SNDRV_CTL_POWER_D1:
771                 state = "D1";
772                 break;
773         case SNDRV_CTL_POWER_D2:
774                 state = "D2";
775                 break;
776         case SNDRV_CTL_POWER_D3hot:
777                 state = "D3hot";
778                 break;
779         case SNDRV_CTL_POWER_D3cold:
780                 state = "D3cold";
781                 break;
782         }
783         count += sprintf(buf + count, "PM State: %s\n", state);
784
785         return count;
786 }
787
788 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
789
790 int snd_soc_dapm_sys_add(struct device *dev)
791 {
792         int ret = 0;
793
794         if (dapm_status)
795                 ret = device_create_file(dev, &dev_attr_dapm_widget);
796
797         return ret;
798 }
799
800 static void snd_soc_dapm_sys_remove(struct device *dev)
801 {
802         if (dapm_status)
803                 device_remove_file(dev, &dev_attr_dapm_widget);
804 }
805
806 /* free all dapm widgets and resources */
807 static void dapm_free_widgets(struct snd_soc_codec *codec)
808 {
809         struct snd_soc_dapm_widget *w, *next_w;
810         struct snd_soc_dapm_path *p, *next_p;
811
812         list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
813                 list_del(&w->list);
814                 kfree(w);
815         }
816
817         list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
818                 list_del(&p->list);
819                 kfree(p->long_name);
820                 kfree(p);
821         }
822 }
823
824 /**
825  * snd_soc_dapm_sync_endpoints - scan and power dapm paths
826  * @codec: audio codec
827  *
828  * Walks all dapm audio paths and powers widgets according to their
829  * stream or path usage.
830  *
831  * Returns 0 for success.
832  */
833 int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec)
834 {
835         return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
836 }
837 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints);
838
839 static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
840         const char *sink, const char *control, const char *source)
841 {
842         struct snd_soc_dapm_path *path;
843         struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
844         int ret = 0;
845
846         /* find src and dest widgets */
847         list_for_each_entry(w, &codec->dapm_widgets, list) {
848
849                 if (!wsink && !(strcmp(w->name, sink))) {
850                         wsink = w;
851                         continue;
852                 }
853                 if (!wsource && !(strcmp(w->name, source))) {
854                         wsource = w;
855                 }
856         }
857
858         if (wsource == NULL || wsink == NULL)
859                 return -ENODEV;
860
861         path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
862         if (!path)
863                 return -ENOMEM;
864
865         path->source = wsource;
866         path->sink = wsink;
867         INIT_LIST_HEAD(&path->list);
868         INIT_LIST_HEAD(&path->list_source);
869         INIT_LIST_HEAD(&path->list_sink);
870
871         /* check for external widgets */
872         if (wsink->id == snd_soc_dapm_input) {
873                 if (wsource->id == snd_soc_dapm_micbias ||
874                         wsource->id == snd_soc_dapm_mic ||
875                         wsink->id == snd_soc_dapm_line ||
876                         wsink->id == snd_soc_dapm_output)
877                         wsink->ext = 1;
878         }
879         if (wsource->id == snd_soc_dapm_output) {
880                 if (wsink->id == snd_soc_dapm_spk ||
881                         wsink->id == snd_soc_dapm_hp ||
882                         wsink->id == snd_soc_dapm_line ||
883                         wsink->id == snd_soc_dapm_input)
884                         wsource->ext = 1;
885         }
886
887         /* connect static paths */
888         if (control == NULL) {
889                 list_add(&path->list, &codec->dapm_paths);
890                 list_add(&path->list_sink, &wsink->sources);
891                 list_add(&path->list_source, &wsource->sinks);
892                 path->connect = 1;
893                 return 0;
894         }
895
896         /* connect dynamic paths */
897         switch(wsink->id) {
898         case snd_soc_dapm_adc:
899         case snd_soc_dapm_dac:
900         case snd_soc_dapm_pga:
901         case snd_soc_dapm_input:
902         case snd_soc_dapm_output:
903         case snd_soc_dapm_micbias:
904         case snd_soc_dapm_vmid:
905         case snd_soc_dapm_pre:
906         case snd_soc_dapm_post:
907                 list_add(&path->list, &codec->dapm_paths);
908                 list_add(&path->list_sink, &wsink->sources);
909                 list_add(&path->list_source, &wsource->sinks);
910                 path->connect = 1;
911                 return 0;
912         case snd_soc_dapm_mux:
913                 ret = dapm_connect_mux(codec, wsource, wsink, path, control,
914                         &wsink->kcontrols[0]);
915                 if (ret != 0)
916                         goto err;
917                 break;
918         case snd_soc_dapm_switch:
919         case snd_soc_dapm_mixer:
920                 ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
921                 if (ret != 0)
922                         goto err;
923                 break;
924         case snd_soc_dapm_hp:
925         case snd_soc_dapm_mic:
926         case snd_soc_dapm_line:
927         case snd_soc_dapm_spk:
928                 list_add(&path->list, &codec->dapm_paths);
929                 list_add(&path->list_sink, &wsink->sources);
930                 list_add(&path->list_source, &wsource->sinks);
931                 path->connect = 0;
932                 return 0;
933         }
934         return 0;
935
936 err:
937         printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
938                 control, sink);
939         kfree(path);
940         return ret;
941 }
942
943 /**
944  * snd_soc_dapm_connect_input - connect dapm widgets
945  * @codec: audio codec
946  * @sink: name of target widget
947  * @control: mixer control name
948  * @source: name of source name
949  *
950  * Connects 2 dapm widgets together via a named audio path. The sink is
951  * the widget receiving the audio signal, whilst the source is the sender
952  * of the audio signal.
953  *
954  * This function has been deprecated in favour of snd_soc_dapm_add_routes().
955  *
956  * Returns 0 for success else error.
957  */
958 int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
959         const char *control, const char *source)
960 {
961         return snd_soc_dapm_add_route(codec, sink, control, source);
962 }
963 EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
964
965 /**
966  * snd_soc_dapm_add_routes - Add routes between DAPM widgets
967  * @codec: codec
968  * @route: audio routes
969  * @num: number of routes
970  *
971  * Connects 2 dapm widgets together via a named audio path. The sink is
972  * the widget receiving the audio signal, whilst the source is the sender
973  * of the audio signal.
974  *
975  * Returns 0 for success else error. On error all resources can be freed
976  * with a call to snd_soc_card_free().
977  */
978 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
979                             const struct snd_soc_dapm_route *route, int num)
980 {
981         int i, ret;
982
983         for (i = 0; i < num; i++) {
984                 ret = snd_soc_dapm_add_route(codec, route->sink,
985                                              route->control, route->source);
986                 if (ret < 0) {
987                         printk(KERN_ERR "Failed to add route %s->%s\n",
988                                route->source,
989                                route->sink);
990                         return ret;
991                 }
992                 route++;
993         }
994
995         return 0;
996 }
997 EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
998
999 /**
1000  * snd_soc_dapm_new_widgets - add new dapm widgets
1001  * @codec: audio codec
1002  *
1003  * Checks the codec for any new dapm widgets and creates them if found.
1004  *
1005  * Returns 0 for success.
1006  */
1007 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
1008 {
1009         struct snd_soc_dapm_widget *w;
1010
1011         list_for_each_entry(w, &codec->dapm_widgets, list)
1012         {
1013                 if (w->new)
1014                         continue;
1015
1016                 switch(w->id) {
1017                 case snd_soc_dapm_switch:
1018                 case snd_soc_dapm_mixer:
1019                         dapm_new_mixer(codec, w);
1020                         break;
1021                 case snd_soc_dapm_mux:
1022                         dapm_new_mux(codec, w);
1023                         break;
1024                 case snd_soc_dapm_adc:
1025                 case snd_soc_dapm_dac:
1026                 case snd_soc_dapm_pga:
1027                         dapm_new_pga(codec, w);
1028                         break;
1029                 case snd_soc_dapm_input:
1030                 case snd_soc_dapm_output:
1031                 case snd_soc_dapm_micbias:
1032                 case snd_soc_dapm_spk:
1033                 case snd_soc_dapm_hp:
1034                 case snd_soc_dapm_mic:
1035                 case snd_soc_dapm_line:
1036                 case snd_soc_dapm_vmid:
1037                 case snd_soc_dapm_pre:
1038                 case snd_soc_dapm_post:
1039                         break;
1040                 }
1041                 w->new = 1;
1042         }
1043
1044         dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
1045         return 0;
1046 }
1047 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
1048
1049 /**
1050  * snd_soc_dapm_get_volsw - dapm mixer get callback
1051  * @kcontrol: mixer control
1052  * @uinfo: control element information
1053  *
1054  * Callback to get the value of a dapm mixer control.
1055  *
1056  * Returns 0 for success.
1057  */
1058 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1059         struct snd_ctl_elem_value *ucontrol)
1060 {
1061         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1062         int reg = kcontrol->private_value & 0xff;
1063         int shift = (kcontrol->private_value >> 8) & 0x0f;
1064         int rshift = (kcontrol->private_value >> 12) & 0x0f;
1065         int max = (kcontrol->private_value >> 16) & 0xff;
1066         int invert = (kcontrol->private_value >> 24) & 0x01;
1067         int mask = (1 << fls(max)) - 1;
1068
1069         /* return the saved value if we are powered down */
1070         if (widget->id == snd_soc_dapm_pga && !widget->power) {
1071                 ucontrol->value.integer.value[0] = widget->saved_value;
1072                 return 0;
1073         }
1074
1075         ucontrol->value.integer.value[0] =
1076                 (snd_soc_read(widget->codec, reg) >> shift) & mask;
1077         if (shift != rshift)
1078                 ucontrol->value.integer.value[1] =
1079                         (snd_soc_read(widget->codec, reg) >> rshift) & mask;
1080         if (invert) {
1081                 ucontrol->value.integer.value[0] =
1082                         max - ucontrol->value.integer.value[0];
1083                 if (shift != rshift)
1084                         ucontrol->value.integer.value[1] =
1085                                 max - ucontrol->value.integer.value[1];
1086         }
1087
1088         return 0;
1089 }
1090 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
1091
1092 /**
1093  * snd_soc_dapm_put_volsw - dapm mixer set callback
1094  * @kcontrol: mixer control
1095  * @uinfo: control element information
1096  *
1097  * Callback to set the value of a dapm mixer control.
1098  *
1099  * Returns 0 for success.
1100  */
1101 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1102         struct snd_ctl_elem_value *ucontrol)
1103 {
1104         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1105         int reg = kcontrol->private_value & 0xff;
1106         int shift = (kcontrol->private_value >> 8) & 0x0f;
1107         int rshift = (kcontrol->private_value >> 12) & 0x0f;
1108         int max = (kcontrol->private_value >> 16) & 0xff;
1109         int mask = (1 << fls(max)) - 1;
1110         int invert = (kcontrol->private_value >> 24) & 0x01;
1111         unsigned short val, val2, val_mask;
1112         int ret;
1113
1114         val = (ucontrol->value.integer.value[0] & mask);
1115
1116         if (invert)
1117                 val = max - val;
1118         val_mask = mask << shift;
1119         val = val << shift;
1120         if (shift != rshift) {
1121                 val2 = (ucontrol->value.integer.value[1] & mask);
1122                 if (invert)
1123                         val2 = max - val2;
1124                 val_mask |= mask << rshift;
1125                 val |= val2 << rshift;
1126         }
1127
1128         mutex_lock(&widget->codec->mutex);
1129         widget->value = val;
1130
1131         /* save volume value if the widget is powered down */
1132         if (widget->id == snd_soc_dapm_pga && !widget->power) {
1133                 widget->saved_value = val;
1134                 mutex_unlock(&widget->codec->mutex);
1135                 return 1;
1136         }
1137
1138         dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
1139         if (widget->event) {
1140                 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1141                         ret = widget->event(widget, kcontrol,
1142                                                 SND_SOC_DAPM_PRE_REG);
1143                         if (ret < 0) {
1144                                 ret = 1;
1145                                 goto out;
1146                         }
1147                 }
1148                 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1149                 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1150                         ret = widget->event(widget, kcontrol,
1151                                                 SND_SOC_DAPM_POST_REG);
1152         } else
1153                 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1154
1155 out:
1156         mutex_unlock(&widget->codec->mutex);
1157         return ret;
1158 }
1159 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
1160
1161 /**
1162  * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
1163  * @kcontrol: mixer control
1164  * @uinfo: control element information
1165  *
1166  * Callback to get the value of a dapm enumerated double mixer control.
1167  *
1168  * Returns 0 for success.
1169  */
1170 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
1171         struct snd_ctl_elem_value *ucontrol)
1172 {
1173         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1174         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1175         unsigned short val, bitmask;
1176
1177         for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
1178                 ;
1179         val = snd_soc_read(widget->codec, e->reg);
1180         ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
1181         if (e->shift_l != e->shift_r)
1182                 ucontrol->value.enumerated.item[1] =
1183                         (val >> e->shift_r) & (bitmask - 1);
1184
1185         return 0;
1186 }
1187 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
1188
1189 /**
1190  * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
1191  * @kcontrol: mixer control
1192  * @uinfo: control element information
1193  *
1194  * Callback to set the value of a dapm enumerated double mixer control.
1195  *
1196  * Returns 0 for success.
1197  */
1198 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1199         struct snd_ctl_elem_value *ucontrol)
1200 {
1201         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1202         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1203         unsigned short val, mux;
1204         unsigned short mask, bitmask;
1205         int ret = 0;
1206
1207         for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
1208                 ;
1209         if (ucontrol->value.enumerated.item[0] > e->mask - 1)
1210                 return -EINVAL;
1211         mux = ucontrol->value.enumerated.item[0];
1212         val = mux << e->shift_l;
1213         mask = (bitmask - 1) << e->shift_l;
1214         if (e->shift_l != e->shift_r) {
1215                 if (ucontrol->value.enumerated.item[1] > e->mask - 1)
1216                         return -EINVAL;
1217                 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
1218                 mask |= (bitmask - 1) << e->shift_r;
1219         }
1220
1221         mutex_lock(&widget->codec->mutex);
1222         widget->value = val;
1223         dapm_mux_update_power(widget, kcontrol, mask, mux, e);
1224         if (widget->event) {
1225                 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1226                         ret = widget->event(widget,
1227                                 kcontrol, SND_SOC_DAPM_PRE_REG);
1228                         if (ret < 0)
1229                                 goto out;
1230                 }
1231                 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1232                 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1233                         ret = widget->event(widget,
1234                                 kcontrol, SND_SOC_DAPM_POST_REG);
1235         } else
1236                 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1237
1238 out:
1239         mutex_unlock(&widget->codec->mutex);
1240         return ret;
1241 }
1242 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
1243
1244 /**
1245  * snd_soc_dapm_new_control - create new dapm control
1246  * @codec: audio codec
1247  * @widget: widget template
1248  *
1249  * Creates a new dapm control based upon the template.
1250  *
1251  * Returns 0 for success else error.
1252  */
1253 int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
1254         const struct snd_soc_dapm_widget *widget)
1255 {
1256         struct snd_soc_dapm_widget *w;
1257
1258         if ((w = dapm_cnew_widget(widget)) == NULL)
1259                 return -ENOMEM;
1260
1261         w->codec = codec;
1262         INIT_LIST_HEAD(&w->sources);
1263         INIT_LIST_HEAD(&w->sinks);
1264         INIT_LIST_HEAD(&w->list);
1265         list_add(&w->list, &codec->dapm_widgets);
1266
1267         /* machine layer set ups unconnected pins and insertions */
1268         w->connected = 1;
1269         return 0;
1270 }
1271 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
1272
1273 /**
1274  * snd_soc_dapm_new_controls - create new dapm controls
1275  * @codec: audio codec
1276  * @widget: widget array
1277  * @num: number of widgets
1278  *
1279  * Creates new DAPM controls based upon the templates.
1280  *
1281  * Returns 0 for success else error.
1282  */
1283 int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
1284         const struct snd_soc_dapm_widget *widget,
1285         int num)
1286 {
1287         int i, ret;
1288
1289         for (i = 0; i < num; i++) {
1290                 ret = snd_soc_dapm_new_control(codec, widget);
1291                 if (ret < 0)
1292                         return ret;
1293                 widget++;
1294         }
1295         return 0;
1296 }
1297 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
1298
1299
1300 /**
1301  * snd_soc_dapm_stream_event - send a stream event to the dapm core
1302  * @codec: audio codec
1303  * @stream: stream name
1304  * @event: stream event
1305  *
1306  * Sends a stream event to the dapm core. The core then makes any
1307  * necessary widget power changes.
1308  *
1309  * Returns 0 for success else error.
1310  */
1311 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1312         char *stream, int event)
1313 {
1314         struct snd_soc_dapm_widget *w;
1315
1316         if (stream == NULL)
1317                 return 0;
1318
1319         mutex_lock(&codec->mutex);
1320         list_for_each_entry(w, &codec->dapm_widgets, list)
1321         {
1322                 if (!w->sname)
1323                         continue;
1324                 dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
1325                         stream, event);
1326                 if (strstr(w->sname, stream)) {
1327                         switch(event) {
1328                         case SND_SOC_DAPM_STREAM_START:
1329                                 w->active = 1;
1330                                 break;
1331                         case SND_SOC_DAPM_STREAM_STOP:
1332                                 w->active = 0;
1333                                 break;
1334                         case SND_SOC_DAPM_STREAM_SUSPEND:
1335                                 if (w->active)
1336                                         w->suspend = 1;
1337                                 w->active = 0;
1338                                 break;
1339                         case SND_SOC_DAPM_STREAM_RESUME:
1340                                 if (w->suspend) {
1341                                         w->active = 1;
1342                                         w->suspend = 0;
1343                                 }
1344                                 break;
1345                         case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
1346                                 break;
1347                         case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
1348                                 break;
1349                         }
1350                 }
1351         }
1352         mutex_unlock(&codec->mutex);
1353
1354         dapm_power_widgets(codec, event);
1355         dump_dapm(codec, __func__);
1356         return 0;
1357 }
1358 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
1359
1360 /**
1361  * snd_soc_dapm_device_event - send a device event to the dapm core
1362  * @socdev: audio device
1363  * @event: device event
1364  *
1365  * Sends a device event to the dapm core. The core then makes any
1366  * necessary machine or codec power changes..
1367  *
1368  * Returns 0 for success else error.
1369  */
1370 int snd_soc_dapm_device_event(struct snd_soc_device *socdev, int event)
1371 {
1372         struct snd_soc_codec *codec = socdev->codec;
1373         struct snd_soc_machine *machine = socdev->machine;
1374
1375         if (machine->dapm_event)
1376                 machine->dapm_event(machine, event);
1377         if (codec->dapm_event)
1378                 codec->dapm_event(codec, event);
1379         return 0;
1380 }
1381 EXPORT_SYMBOL_GPL(snd_soc_dapm_device_event);
1382
1383 /**
1384  * snd_soc_dapm_set_endpoint - set audio endpoint status
1385  * @codec: audio codec
1386  * @endpoint: audio signal endpoint (or start point)
1387  * @status: point status
1388  *
1389  * Set audio endpoint status - connected or disconnected.
1390  *
1391  * Returns 0 for success else error.
1392  */
1393 int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
1394         char *endpoint, int status)
1395 {
1396         struct snd_soc_dapm_widget *w;
1397
1398         list_for_each_entry(w, &codec->dapm_widgets, list) {
1399                 if (!strcmp(w->name, endpoint)) {
1400                         w->connected = status;
1401                         return 0;
1402                 }
1403         }
1404
1405         return -ENODEV;
1406 }
1407 EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
1408
1409 /**
1410  * snd_soc_dapm_get_endpoint_status - get audio endpoint status
1411  * @codec: audio codec
1412  * @endpoint: audio signal endpoint (or start point)
1413  *
1414  * Get audio endpoint status - connected or disconnected.
1415  *
1416  * Returns status
1417  */
1418 int snd_soc_dapm_get_endpoint_status(struct snd_soc_codec *codec,
1419         char *endpoint)
1420 {
1421         struct snd_soc_dapm_widget *w;
1422
1423         list_for_each_entry(w, &codec->dapm_widgets, list) {
1424                 if (!strcmp(w->name, endpoint))
1425                         return w->connected;
1426         }
1427
1428         return 0;
1429 }
1430 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_endpoint_status);
1431
1432 /**
1433  * snd_soc_dapm_free - free dapm resources
1434  * @socdev: SoC device
1435  *
1436  * Free all dapm widgets and resources.
1437  */
1438 void snd_soc_dapm_free(struct snd_soc_device *socdev)
1439 {
1440         struct snd_soc_codec *codec = socdev->codec;
1441
1442         snd_soc_dapm_sys_remove(socdev->dev);
1443         dapm_free_widgets(codec);
1444 }
1445 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
1446
1447 /* Module information */
1448 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
1449 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
1450 MODULE_LICENSE("GPL");