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