OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [sound/] [soc/] [soc-dapm.c] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.