[ALSA] sound/soc/soc-dapm.c: make 4 functions static
[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  *  Revision history
14  *    12th Aug 2005   Initial version.
15  *    25th Oct 2005   Implemented path power domain.
16  *    18th Dec 2005   Implemented machine and stream level power domain.
17  *
18  *  Features:
19  *    o Changes power status of internal codec blocks depending on the
20  *      dynamic configuration of codec internal audio paths and active
21  *      DAC's/ADC's.
22  *    o Platform power domain - can support external components i.e. amps and
23  *      mic/meadphone insertion events.
24  *    o Automatic Mic Bias support
25  *    o Jack insertion power event initiation - e.g. hp insertion will enable
26  *      sinks, dacs, etc
27  *    o Delayed powerdown of audio susbsytem to reduce pops between a quick
28  *      device reopen.
29  *
30  *  Todo:
31  *    o DAPM power change sequencing - allow for configurable per
32  *      codec sequences.
33  *    o Support for analogue bias optimisation.
34  *    o Support for reduced codec oversampling rates.
35  *    o Support for reduced codec bias currents.
36  */
37
38 #include <linux/module.h>
39 #include <linux/moduleparam.h>
40 #include <linux/init.h>
41 #include <linux/delay.h>
42 #include <linux/pm.h>
43 #include <linux/bitops.h>
44 #include <linux/platform_device.h>
45 #include <linux/jiffies.h>
46 #include <sound/driver.h>
47 #include <sound/core.h>
48 #include <sound/pcm.h>
49 #include <sound/pcm_params.h>
50 #include <sound/soc-dapm.h>
51 #include <sound/initval.h>
52
53 /* debug */
54 #define DAPM_DEBUG 0
55 #if DAPM_DEBUG
56 #define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
57 #define dbg(format, arg...) printk(format, ## arg)
58 #else
59 #define dump_dapm(codec, action)
60 #define dbg(format, arg...)
61 #endif
62
63 #define POP_DEBUG 0
64 #if POP_DEBUG
65 #define POP_TIME 500 /* 500 msecs - change if pop debug is too fast */
66 #define pop_wait(time) schedule_timeout_interruptible(msecs_to_jiffies(time))
67 #define pop_dbg(format, arg...) printk(format, ## arg); pop_wait(POP_TIME)
68 #else
69 #define pop_dbg(format, arg...)
70 #define pop_wait(time)
71 #endif
72
73 /* dapm power sequences - make this per codec in the future */
74 static int dapm_up_seq[] = {
75         snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
76         snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga,
77         snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
78 };
79 static int dapm_down_seq[] = {
80         snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
81         snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
82         snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post
83 };
84
85 static int dapm_status = 1;
86 module_param(dapm_status, int, 0);
87 MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
88
89 /* create a new dapm widget */
90 static struct snd_soc_dapm_widget *dapm_cnew_widget(
91         const struct snd_soc_dapm_widget *_widget)
92 {
93         struct snd_soc_dapm_widget* widget;
94         widget = kmalloc(sizeof(struct snd_soc_dapm_widget), GFP_KERNEL);
95         if (!widget)
96                 return NULL;
97
98         memcpy(widget, _widget, sizeof(struct snd_soc_dapm_widget));
99         return widget;
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(POP_TIME);
235         }
236         dbg("reg old %x new %x change %d\n", 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  * Scan each dapm widget for complete audio path.
459  * A complete path is a route that has valid endpoints i.e.:-
460  *
461  *  o DAC to output pin.
462  *  o Input Pin to ADC.
463  *  o Input pin to Output pin (bypass, sidetone)
464  *  o DAC to ADC (loopback).
465  */
466 static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
467 {
468         struct snd_soc_dapm_widget *w;
469         int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power;
470
471         /* do we have a sequenced stream event */
472         if (event == SND_SOC_DAPM_STREAM_START) {
473                 c = ARRAY_SIZE(dapm_up_seq);
474                 seq = dapm_up_seq;
475         } else if (event == SND_SOC_DAPM_STREAM_STOP) {
476                 c = ARRAY_SIZE(dapm_down_seq);
477                 seq = dapm_down_seq;
478         }
479
480         for(i = 0; i < c; i++) {
481                 list_for_each_entry(w, &codec->dapm_widgets, list) {
482
483                         /* is widget in stream order */
484                         if (seq && seq[i] && w->id != seq[i])
485                                 continue;
486
487                         /* vmid - no action */
488                         if (w->id == snd_soc_dapm_vmid)
489                                 continue;
490
491                         /* active ADC */
492                         if (w->id == snd_soc_dapm_adc && w->active) {
493                                 in = is_connected_input_ep(w);
494                                 dapm_clear_walk(w->codec);
495                                 w->power = (in != 0) ? 1 : 0;
496                                 dapm_update_bits(w);
497                                 continue;
498                         }
499
500                         /* active DAC */
501                         if (w->id == snd_soc_dapm_dac && w->active) {
502                                 out = is_connected_output_ep(w);
503                                 dapm_clear_walk(w->codec);
504                                 w->power = (out != 0) ? 1 : 0;
505                                 dapm_update_bits(w);
506                                 continue;
507                         }
508
509                         /* programmable gain/attenuation */
510                         if (w->id == snd_soc_dapm_pga) {
511                                 int on;
512                                 in = is_connected_input_ep(w);
513                                 dapm_clear_walk(w->codec);
514                                 out = is_connected_output_ep(w);
515                                 dapm_clear_walk(w->codec);
516                                 w->power = on = (out != 0 && in != 0) ? 1 : 0;
517
518                                 if (!on)
519                                         dapm_set_pga(w, on); /* lower volume to reduce pops */
520                                 dapm_update_bits(w);
521                                 if (on)
522                                         dapm_set_pga(w, on); /* restore volume from zero */
523
524                                 continue;
525                         }
526
527                         /* pre and post event widgets */
528                         if (w->id == snd_soc_dapm_pre) {
529                                 if (!w->event)
530                                         continue;
531
532                                 if (event == SND_SOC_DAPM_STREAM_START) {
533                                         ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
534                                         if (ret < 0)
535                                                 return ret;
536                                 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
537                                         ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
538                                         if (ret < 0)
539                                                 return ret;
540                                 }
541                                 continue;
542                         }
543                         if (w->id == snd_soc_dapm_post) {
544                                 if (!w->event)
545                                         continue;
546
547                                 if (event == SND_SOC_DAPM_STREAM_START) {
548                                         ret = w->event(w, SND_SOC_DAPM_POST_PMU);
549                                         if (ret < 0)
550                                                 return ret;
551                                 } else if (event == SND_SOC_DAPM_STREAM_STOP) {
552                                         ret = w->event(w, SND_SOC_DAPM_POST_PMD);
553                                         if (ret < 0)
554                                                 return ret;
555                                 }
556                                 continue;
557                         }
558
559                         /* all other widgets */
560                         in = is_connected_input_ep(w);
561                         dapm_clear_walk(w->codec);
562                         out = is_connected_output_ep(w);
563                         dapm_clear_walk(w->codec);
564                         power = (out != 0 && in != 0) ? 1 : 0;
565                         power_change = (w->power == power) ? 0: 1;
566                         w->power = power;
567
568                         /* call any power change event handlers */
569                         if (power_change) {
570                                 if (w->event) {
571                                         dbg("power %s event for %s flags %x\n",
572                                                 w->power ? "on" : "off", w->name, w->event_flags);
573                                         if (power) {
574                                                 /* power up event */
575                                                 if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
576                                                         ret = w->event(w, SND_SOC_DAPM_PRE_PMU);
577                                                         if (ret < 0)
578                                                                 return ret;
579                                                 }
580                                                 dapm_update_bits(w);
581                                                 if (w->event_flags & SND_SOC_DAPM_POST_PMU){
582                                                         ret = w->event(w, SND_SOC_DAPM_POST_PMU);
583                                                         if (ret < 0)
584                                                                 return ret;
585                                                 }
586                                         } else {
587                                                 /* power down event */
588                                                 if (w->event_flags & SND_SOC_DAPM_PRE_PMD) {
589                                                         ret = w->event(w, SND_SOC_DAPM_PRE_PMD);
590                                                         if (ret < 0)
591                                                                 return ret;
592                                                 }
593                                                 dapm_update_bits(w);
594                                                 if (w->event_flags & SND_SOC_DAPM_POST_PMD) {
595                                                         ret = w->event(w, SND_SOC_DAPM_POST_PMD);
596                                                         if (ret < 0)
597                                                                 return ret;
598                                                 }
599                                         }
600                                 } else
601                                         /* no event handler */
602                                         dapm_update_bits(w);
603                         }
604                 }
605         }
606
607         return ret;
608 }
609
610 #if DAPM_DEBUG
611 static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
612 {
613         struct snd_soc_dapm_widget *w;
614         struct snd_soc_dapm_path *p = NULL;
615         int in, out;
616
617         printk("DAPM %s %s\n", codec->name, action);
618
619         list_for_each_entry(w, &codec->dapm_widgets, list) {
620
621                 /* only display widgets that effect routing */
622                 switch (w->id) {
623                 case snd_soc_dapm_pre:
624                 case snd_soc_dapm_post:
625                 case snd_soc_dapm_vmid:
626                         continue;
627                 case snd_soc_dapm_mux:
628                 case snd_soc_dapm_output:
629                 case snd_soc_dapm_input:
630                 case snd_soc_dapm_switch:
631                 case snd_soc_dapm_hp:
632                 case snd_soc_dapm_mic:
633                 case snd_soc_dapm_spk:
634                 case snd_soc_dapm_line:
635                 case snd_soc_dapm_micbias:
636                 case snd_soc_dapm_dac:
637                 case snd_soc_dapm_adc:
638                 case snd_soc_dapm_pga:
639                 case snd_soc_dapm_mixer:
640                         if (w->name) {
641                                 in = is_connected_input_ep(w);
642                                 dapm_clear_walk(w->codec);
643                                 out = is_connected_output_ep(w);
644                                 dapm_clear_walk(w->codec);
645                                 printk("%s: %s  in %d out %d\n", w->name,
646                                         w->power ? "On":"Off",in, out);
647
648                                 list_for_each_entry(p, &w->sources, list_sink) {
649                                         if (p->connect)
650                                                 printk(" in  %s %s\n", p->name ? p->name : "static",
651                                                         p->source->name);
652                                 }
653                                 list_for_each_entry(p, &w->sinks, list_source) {
654                                         p = list_entry(lp, struct snd_soc_dapm_path, list_source);
655                                         if (p->connect)
656                                                 printk(" out %s %s\n", p->name ? p->name : "static",
657                                                         p->sink->name);
658                                 }
659                         }
660                 break;
661                 }
662         }
663 }
664 #endif
665
666 /* test and update the power status of a mux widget */
667 static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
668                                  struct snd_kcontrol *kcontrol, int mask,
669                                  int val, struct soc_enum* e)
670 {
671         struct snd_soc_dapm_path *path;
672         int found = 0;
673
674         if (widget->id != snd_soc_dapm_mux)
675                 return -ENODEV;
676
677         if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
678                 return 0;
679
680         /* find dapm widget path assoc with kcontrol */
681         list_for_each_entry(path, &widget->codec->dapm_paths, list) {
682                 if (path->kcontrol != kcontrol)
683                         continue;
684
685                 if (!path->name || ! e->texts[val])
686                         continue;
687
688                 found = 1;
689                 /* we now need to match the string in the enum to the path */
690                 if (!(strcmp(path->name, e->texts[val])))
691                         path->connect = 1; /* new connection */
692                 else
693                         path->connect = 0; /* old connection must be powered down */
694         }
695
696         if (found)
697                 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
698
699         return 0;
700 }
701
702 /* test and update the power status of a mixer widget */
703 static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
704                                    struct snd_kcontrol *kcontrol, int reg,
705                                    int val_mask, int val, int invert)
706 {
707         struct snd_soc_dapm_path *path;
708         int found = 0;
709
710         if (widget->id != snd_soc_dapm_mixer)
711                 return -ENODEV;
712
713         if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
714                 return 0;
715
716         /* find dapm widget path assoc with kcontrol */
717         list_for_each_entry(path, &widget->codec->dapm_paths, list) {
718                 if (path->kcontrol != kcontrol)
719                         continue;
720
721                 /* found, now check type */
722                 found = 1;
723                 if (val)
724                         /* new connection */
725                         path->connect = invert ? 0:1;
726                 else
727                         /* old connection must be powered down */
728                         path->connect = invert ? 1:0;
729                 break;
730         }
731
732         if (found)
733                 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
734
735         return 0;
736 }
737
738 /* show dapm widget status in sys fs */
739 static ssize_t dapm_widget_show(struct device *dev,
740         struct device_attribute *attr, char *buf)
741 {
742         struct snd_soc_device *devdata = dev_get_drvdata(dev);
743         struct snd_soc_codec *codec = devdata->codec;
744         struct snd_soc_dapm_widget *w;
745         int count = 0;
746         char *state = "not set";
747
748         list_for_each_entry(w, &codec->dapm_widgets, list) {
749
750                 /* only display widgets that burnm power */
751                 switch (w->id) {
752                 case snd_soc_dapm_hp:
753                 case snd_soc_dapm_mic:
754                 case snd_soc_dapm_spk:
755                 case snd_soc_dapm_line:
756                 case snd_soc_dapm_micbias:
757                 case snd_soc_dapm_dac:
758                 case snd_soc_dapm_adc:
759                 case snd_soc_dapm_pga:
760                 case snd_soc_dapm_mixer:
761                         if (w->name)
762                                 count += sprintf(buf + count, "%s: %s\n",
763                                         w->name, w->power ? "On":"Off");
764                 break;
765                 default:
766                 break;
767                 }
768         }
769
770         switch(codec->dapm_state){
771         case SNDRV_CTL_POWER_D0:
772                 state = "D0";
773                 break;
774         case SNDRV_CTL_POWER_D1:
775                 state = "D1";
776                 break;
777         case SNDRV_CTL_POWER_D2:
778                 state = "D2";
779                 break;
780         case SNDRV_CTL_POWER_D3hot:
781                 state = "D3hot";
782                 break;
783         case SNDRV_CTL_POWER_D3cold:
784                 state = "D3cold";
785                 break;
786         }
787         count += sprintf(buf + count, "PM State: %s\n", state);
788
789         return count;
790 }
791
792 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
793
794 int snd_soc_dapm_sys_add(struct device *dev)
795 {
796         int ret = 0;
797
798         if (dapm_status)
799                 ret = device_create_file(dev, &dev_attr_dapm_widget);
800
801         return ret;
802 }
803
804 static void snd_soc_dapm_sys_remove(struct device *dev)
805 {
806         if (dapm_status)
807                 device_remove_file(dev, &dev_attr_dapm_widget);
808 }
809
810 /* free all dapm widgets and resources */
811 static void dapm_free_widgets(struct snd_soc_codec *codec)
812 {
813         struct snd_soc_dapm_widget *w, *next_w;
814         struct snd_soc_dapm_path *p, *next_p;
815
816         list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
817                 list_del(&w->list);
818                 kfree(w);
819         }
820
821         list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
822                 list_del(&p->list);
823                 kfree(p->long_name);
824                 kfree(p);
825         }
826 }
827
828 /**
829  * snd_soc_dapm_sync_endpoints - scan and power dapm paths
830  * @codec: audio codec
831  *
832  * Walks all dapm audio paths and powers widgets according to their
833  * stream or path usage.
834  *
835  * Returns 0 for success.
836  */
837 int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec)
838 {
839         return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
840 }
841 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints);
842
843 /**
844  * snd_soc_dapm_connect_input - connect dapm widgets
845  * @codec: audio codec
846  * @sink: name of target widget
847  * @control: mixer control name
848  * @source: name of source name
849  *
850  * Connects 2 dapm widgets together via a named audio path. The sink is
851  * the widget receiving the audio signal, whilst the source is the sender
852  * of the audio signal.
853  *
854  * Returns 0 for success else error.
855  */
856 int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
857         const char * control, const char *source)
858 {
859         struct snd_soc_dapm_path *path;
860         struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
861         int ret = 0;
862
863         /* find src and dest widgets */
864         list_for_each_entry(w, &codec->dapm_widgets, list) {
865
866                 if (!wsink && !(strcmp(w->name, sink))) {
867                         wsink = w;
868                         continue;
869                 }
870                 if (!wsource && !(strcmp(w->name, source))) {
871                         wsource = w;
872                 }
873         }
874
875         if (wsource == NULL || wsink == NULL)
876                 return -ENODEV;
877
878         path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
879         if (!path)
880                 return -ENOMEM;
881
882         path->source = wsource;
883         path->sink = wsink;
884         INIT_LIST_HEAD(&path->list);
885         INIT_LIST_HEAD(&path->list_source);
886         INIT_LIST_HEAD(&path->list_sink);
887
888         /* check for external widgets */
889         if (wsink->id == snd_soc_dapm_input) {
890                 if (wsource->id == snd_soc_dapm_micbias ||
891                         wsource->id == snd_soc_dapm_mic ||
892                         wsink->id == snd_soc_dapm_line)
893                         wsink->ext = 1;
894         }
895         if (wsource->id == snd_soc_dapm_output) {
896                 if (wsink->id == snd_soc_dapm_spk ||
897                         wsink->id == snd_soc_dapm_hp ||
898                         wsink->id == snd_soc_dapm_line)
899                         wsource->ext = 1;
900         }
901
902         /* connect static paths */
903         if (control == NULL) {
904                 list_add(&path->list, &codec->dapm_paths);
905                 list_add(&path->list_sink, &wsink->sources);
906                 list_add(&path->list_source, &wsource->sinks);
907                 path->connect = 1;
908                 return 0;
909         }
910
911         /* connect dynamic paths */
912         switch(wsink->id) {
913         case snd_soc_dapm_adc:
914         case snd_soc_dapm_dac:
915         case snd_soc_dapm_pga:
916         case snd_soc_dapm_input:
917         case snd_soc_dapm_output:
918         case snd_soc_dapm_micbias:
919         case snd_soc_dapm_vmid:
920         case snd_soc_dapm_pre:
921         case snd_soc_dapm_post:
922                 list_add(&path->list, &codec->dapm_paths);
923                 list_add(&path->list_sink, &wsink->sources);
924                 list_add(&path->list_source, &wsource->sinks);
925                 path->connect = 1;
926                 return 0;
927         case snd_soc_dapm_mux:
928                 ret = dapm_connect_mux(codec, wsource, wsink, path, control,
929                         &wsink->kcontrols[0]);
930                 if (ret != 0)
931                         goto err;
932                 break;
933         case snd_soc_dapm_switch:
934         case snd_soc_dapm_mixer:
935                 ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
936                 if (ret != 0)
937                         goto err;
938                 break;
939         case snd_soc_dapm_hp:
940         case snd_soc_dapm_mic:
941         case snd_soc_dapm_line:
942         case snd_soc_dapm_spk:
943                 list_add(&path->list, &codec->dapm_paths);
944                 list_add(&path->list_sink, &wsink->sources);
945                 list_add(&path->list_source, &wsource->sinks);
946                 path->connect = 0;
947                 return 0;
948         }
949         return 0;
950
951 err:
952         printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
953                 control, sink);
954         kfree(path);
955         return ret;
956 }
957 EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
958
959 /**
960  * snd_soc_dapm_new_widgets - add new dapm widgets
961  * @codec: audio codec
962  *
963  * Checks the codec for any new dapm widgets and creates them if found.
964  *
965  * Returns 0 for success.
966  */
967 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
968 {
969         struct snd_soc_dapm_widget *w;
970
971         mutex_lock(&codec->mutex);
972         list_for_each_entry(w, &codec->dapm_widgets, list)
973         {
974                 if (w->new)
975                         continue;
976
977                 switch(w->id) {
978                 case snd_soc_dapm_switch:
979                 case snd_soc_dapm_mixer:
980                         dapm_new_mixer(codec, w);
981                         break;
982                 case snd_soc_dapm_mux:
983                         dapm_new_mux(codec, w);
984                         break;
985                 case snd_soc_dapm_adc:
986                 case snd_soc_dapm_dac:
987                 case snd_soc_dapm_pga:
988                         dapm_new_pga(codec, w);
989                         break;
990                 case snd_soc_dapm_input:
991                 case snd_soc_dapm_output:
992                 case snd_soc_dapm_micbias:
993                 case snd_soc_dapm_spk:
994                 case snd_soc_dapm_hp:
995                 case snd_soc_dapm_mic:
996                 case snd_soc_dapm_line:
997                 case snd_soc_dapm_vmid:
998                 case snd_soc_dapm_pre:
999                 case snd_soc_dapm_post:
1000                         break;
1001                 }
1002                 w->new = 1;
1003         }
1004
1005         dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
1006         mutex_unlock(&codec->mutex);
1007         return 0;
1008 }
1009 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
1010
1011 /**
1012  * snd_soc_dapm_get_volsw - dapm mixer get callback
1013  * @kcontrol: mixer control
1014  * @uinfo: control element information
1015  *
1016  * Callback to get the value of a dapm mixer control.
1017  *
1018  * Returns 0 for success.
1019  */
1020 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1021         struct snd_ctl_elem_value *ucontrol)
1022 {
1023         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1024         int reg = kcontrol->private_value & 0xff;
1025         int shift = (kcontrol->private_value >> 8) & 0x0f;
1026         int rshift = (kcontrol->private_value >> 12) & 0x0f;
1027         int mask = (kcontrol->private_value >> 16) & 0xff;
1028         int invert = (kcontrol->private_value >> 24) & 0x01;
1029
1030         /* return the saved value if we are powered down */
1031         if (widget->id == snd_soc_dapm_pga && !widget->power) {
1032                 ucontrol->value.integer.value[0] = widget->saved_value;
1033                 return 0;
1034         }
1035
1036         ucontrol->value.integer.value[0] =
1037                 (snd_soc_read(widget->codec, reg) >> shift) & mask;
1038         if (shift != rshift)
1039                 ucontrol->value.integer.value[1] =
1040                         (snd_soc_read(widget->codec, reg) >> rshift) & mask;
1041         if (invert) {
1042                 ucontrol->value.integer.value[0] =
1043                         mask - ucontrol->value.integer.value[0];
1044                 if (shift != rshift)
1045                         ucontrol->value.integer.value[1] =
1046                                 mask - ucontrol->value.integer.value[1];
1047         }
1048
1049         return 0;
1050 }
1051 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
1052
1053 /**
1054  * snd_soc_dapm_put_volsw - dapm mixer set callback
1055  * @kcontrol: mixer control
1056  * @uinfo: control element information
1057  *
1058  * Callback to set the value of a dapm mixer control.
1059  *
1060  * Returns 0 for success.
1061  */
1062 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1063         struct snd_ctl_elem_value *ucontrol)
1064 {
1065         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1066         int reg = kcontrol->private_value & 0xff;
1067         int shift = (kcontrol->private_value >> 8) & 0x0f;
1068         int rshift = (kcontrol->private_value >> 12) & 0x0f;
1069         int mask = (kcontrol->private_value >> 16) & 0xff;
1070         int invert = (kcontrol->private_value >> 24) & 0x01;
1071         unsigned short val, val2, val_mask;
1072         int ret;
1073
1074         val = (ucontrol->value.integer.value[0] & mask);
1075
1076         if (invert)
1077                 val = mask - val;
1078         val_mask = mask << shift;
1079         val = val << shift;
1080         if (shift != rshift) {
1081                 val2 = (ucontrol->value.integer.value[1] & mask);
1082                 if (invert)
1083                         val2 = mask - val2;
1084                 val_mask |= mask << rshift;
1085                 val |= val2 << rshift;
1086         }
1087
1088         mutex_lock(&widget->codec->mutex);
1089         widget->value = val;
1090
1091         /* save volume value if the widget is powered down */
1092         if (widget->id == snd_soc_dapm_pga && !widget->power) {
1093                 widget->saved_value = val;
1094                 mutex_unlock(&widget->codec->mutex);
1095                 return 1;
1096         }
1097
1098         dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
1099         if (widget->event) {
1100                 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1101                         ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
1102                         if (ret < 0)
1103                                 goto out;
1104                 }
1105                 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1106                 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1107                         ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
1108         } else
1109                 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1110
1111 out:
1112         mutex_unlock(&widget->codec->mutex);
1113         return ret;
1114 }
1115 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
1116
1117 /**
1118  * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
1119  * @kcontrol: mixer control
1120  * @uinfo: control element information
1121  *
1122  * Callback to get the value of a dapm enumerated double mixer control.
1123  *
1124  * Returns 0 for success.
1125  */
1126 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
1127         struct snd_ctl_elem_value *ucontrol)
1128 {
1129         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1130         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1131         unsigned short val, bitmask;
1132
1133         for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
1134                 ;
1135         val = snd_soc_read(widget->codec, e->reg);
1136         ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
1137         if (e->shift_l != e->shift_r)
1138                 ucontrol->value.enumerated.item[1] =
1139                         (val >> e->shift_r) & (bitmask - 1);
1140
1141         return 0;
1142 }
1143 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
1144
1145 /**
1146  * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
1147  * @kcontrol: mixer control
1148  * @uinfo: control element information
1149  *
1150  * Callback to set the value of a dapm enumerated double mixer control.
1151  *
1152  * Returns 0 for success.
1153  */
1154 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1155         struct snd_ctl_elem_value *ucontrol)
1156 {
1157         struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
1158         struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1159         unsigned short val, mux;
1160         unsigned short mask, bitmask;
1161         int ret = 0;
1162
1163         for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
1164                 ;
1165         if (ucontrol->value.enumerated.item[0] > e->mask - 1)
1166                 return -EINVAL;
1167         mux = ucontrol->value.enumerated.item[0];
1168         val = mux << e->shift_l;
1169         mask = (bitmask - 1) << e->shift_l;
1170         if (e->shift_l != e->shift_r) {
1171                 if (ucontrol->value.enumerated.item[1] > e->mask - 1)
1172                         return -EINVAL;
1173                 val |= ucontrol->value.enumerated.item[1] << e->shift_r;
1174                 mask |= (bitmask - 1) << e->shift_r;
1175         }
1176
1177         mutex_lock(&widget->codec->mutex);
1178         widget->value = val;
1179         dapm_mux_update_power(widget, kcontrol, mask, mux, e);
1180         if (widget->event) {
1181                 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1182                         ret = widget->event(widget, SND_SOC_DAPM_PRE_REG);
1183                         if (ret < 0)
1184                                 goto out;
1185                 }
1186                 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1187                 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1188                         ret = widget->event(widget, SND_SOC_DAPM_POST_REG);
1189         } else
1190                 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
1191
1192 out:
1193         mutex_unlock(&widget->codec->mutex);
1194         return ret;
1195 }
1196 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
1197
1198 /**
1199  * snd_soc_dapm_new_control - create new dapm control
1200  * @codec: audio codec
1201  * @widget: widget template
1202  *
1203  * Creates a new dapm control based upon the template.
1204  *
1205  * Returns 0 for success else error.
1206  */
1207 int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
1208         const struct snd_soc_dapm_widget *widget)
1209 {
1210         struct snd_soc_dapm_widget *w;
1211
1212         if ((w = dapm_cnew_widget(widget)) == NULL)
1213                 return -ENOMEM;
1214
1215         w->codec = codec;
1216         INIT_LIST_HEAD(&w->sources);
1217         INIT_LIST_HEAD(&w->sinks);
1218         INIT_LIST_HEAD(&w->list);
1219         list_add(&w->list, &codec->dapm_widgets);
1220
1221         /* machine layer set ups unconnected pins and insertions */
1222         w->connected = 1;
1223         return 0;
1224 }
1225 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
1226
1227 /**
1228  * snd_soc_dapm_stream_event - send a stream event to the dapm core
1229  * @codec: audio codec
1230  * @stream: stream name
1231  * @event: stream event
1232  *
1233  * Sends a stream event to the dapm core. The core then makes any
1234  * necessary widget power changes.
1235  *
1236  * Returns 0 for success else error.
1237  */
1238 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
1239         char *stream, int event)
1240 {
1241         struct snd_soc_dapm_widget *w;
1242
1243         mutex_lock(&codec->mutex);
1244         list_for_each_entry(w, &codec->dapm_widgets, list)
1245         {
1246                 if (!w->sname)
1247                         continue;
1248                 dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
1249                         stream, event);
1250                 if (strstr(w->sname, stream)) {
1251                         switch(event) {
1252                         case SND_SOC_DAPM_STREAM_START:
1253                                 w->active = 1;
1254                                 break;
1255                         case SND_SOC_DAPM_STREAM_STOP:
1256                                 w->active = 0;
1257                                 break;
1258                         case SND_SOC_DAPM_STREAM_SUSPEND:
1259                                 if (w->active)
1260                                         w->suspend = 1;
1261                                 w->active = 0;
1262                                 break;
1263                         case SND_SOC_DAPM_STREAM_RESUME:
1264                                 if (w->suspend) {
1265                                         w->active = 1;
1266                                         w->suspend = 0;
1267                                 }
1268                                 break;
1269                         case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
1270                                 break;
1271                         case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
1272                                 break;
1273                         }
1274                 }
1275         }
1276         mutex_unlock(&codec->mutex);
1277
1278         dapm_power_widgets(codec, event);
1279         dump_dapm(codec, __FUNCTION__);
1280         return 0;
1281 }
1282 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
1283
1284 /**
1285  * snd_soc_dapm_set_endpoint - set audio endpoint status
1286  * @codec: audio codec
1287  * @endpoint: audio signal endpoint (or start point)
1288  * @status: point status
1289  *
1290  * Set audio endpoint status - connected or disconnected.
1291  *
1292  * Returns 0 for success else error.
1293  */
1294 int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
1295         char *endpoint, int status)
1296 {
1297         struct snd_soc_dapm_widget *w;
1298
1299         list_for_each_entry(w, &codec->dapm_widgets, list) {
1300                 if (!strcmp(w->name, endpoint)) {
1301                         w->connected = status;
1302                 }
1303         }
1304
1305         return 0;
1306 }
1307 EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
1308
1309 /**
1310  * snd_soc_dapm_free - free dapm resources
1311  * @socdev: SoC device
1312  *
1313  * Free all dapm widgets and resources.
1314  */
1315 void snd_soc_dapm_free(struct snd_soc_device *socdev)
1316 {
1317         struct snd_soc_codec *codec = socdev->codec;
1318
1319         snd_soc_dapm_sys_remove(socdev->dev);
1320         dapm_free_widgets(codec);
1321 }
1322 EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
1323
1324 /* Module information */
1325 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
1326 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
1327 MODULE_LICENSE("GPL");