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