aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-05-20 06:00:43 -0400
committerTakashi Iwai <tiwai@suse.de>2010-05-20 06:00:43 -0400
commitd71f4cece4bd97d05592836202fc04ff2e7817e3 (patch)
tree6c877c7a938758b1323d9c97d46b9c536e618c69 /sound/soc/soc-dapm.c
parent19008bdacb9f7841166ebafe0aef361ee582ffbf (diff)
parentad8332c1302bcb4f80d593fd3eb477be9d7f5604 (diff)
Merge branch 'topic/asoc' into for-linus
Conflicts: sound/soc/codecs/ad1938.c
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c217
1 files changed, 96 insertions, 121 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7c28f401f436..03cb7c05ebec 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -98,7 +98,6 @@ static void pop_dbg(u32 pop_time, const char *fmt, ...)
98 98
99 if (pop_time) { 99 if (pop_time) {
100 vprintk(fmt, args); 100 vprintk(fmt, args);
101 pop_wait(pop_time);
102 } 101 }
103 102
104 va_end(args); 103 va_end(args);
@@ -315,62 +314,14 @@ static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
315 pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n", 314 pop_dbg(codec->pop_time, "pop test %s : %s in %d ms\n",
316 widget->name, widget->power ? "on" : "off", 315 widget->name, widget->power ? "on" : "off",
317 codec->pop_time); 316 codec->pop_time);
318 snd_soc_write(codec, widget->reg, new);
319 pop_wait(codec->pop_time); 317 pop_wait(codec->pop_time);
318 snd_soc_write(codec, widget->reg, new);
320 } 319 }
321 pr_debug("reg %x old %x new %x change %d\n", widget->reg, 320 pr_debug("reg %x old %x new %x change %d\n", widget->reg,
322 old, new, change); 321 old, new, change);
323 return change; 322 return change;
324} 323}
325 324
326/* ramps the volume up or down to minimise pops before or after a
327 * DAPM power event */
328static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
329{
330 const struct snd_kcontrol_new *k = widget->kcontrols;
331
332 if (widget->muted && !power)
333 return 0;
334 if (!widget->muted && power)
335 return 0;
336
337 if (widget->num_kcontrols && k) {
338 struct soc_mixer_control *mc =
339 (struct soc_mixer_control *)k->private_value;
340 unsigned int reg = mc->reg;
341 unsigned int shift = mc->shift;
342 int max = mc->max;
343 unsigned int mask = (1 << fls(max)) - 1;
344 unsigned int invert = mc->invert;
345
346 if (power) {
347 int i;
348 /* power up has happended, increase volume to last level */
349 if (invert) {
350 for (i = max; i > widget->saved_value; i--)
351 snd_soc_update_bits(widget->codec, reg, mask, i);
352 } else {
353 for (i = 0; i < widget->saved_value; i++)
354 snd_soc_update_bits(widget->codec, reg, mask, i);
355 }
356 widget->muted = 0;
357 } else {
358 /* power down is about to occur, decrease volume to mute */
359 int val = snd_soc_read(widget->codec, reg);
360 int i = widget->saved_value = (val >> shift) & mask;
361 if (invert) {
362 for (; i < mask; i++)
363 snd_soc_update_bits(widget->codec, reg, mask, i);
364 } else {
365 for (; i > 0; i--)
366 snd_soc_update_bits(widget->codec, reg, mask, i);
367 }
368 widget->muted = 1;
369 }
370 }
371 return 0;
372}
373
374/* create new dapm mixer control */ 325/* create new dapm mixer control */
375static int dapm_new_mixer(struct snd_soc_codec *codec, 326static int dapm_new_mixer(struct snd_soc_codec *codec,
376 struct snd_soc_dapm_widget *w) 327 struct snd_soc_dapm_widget *w)
@@ -465,20 +416,10 @@ err:
465static int dapm_new_pga(struct snd_soc_codec *codec, 416static int dapm_new_pga(struct snd_soc_codec *codec,
466 struct snd_soc_dapm_widget *w) 417 struct snd_soc_dapm_widget *w)
467{ 418{
468 struct snd_kcontrol *kcontrol; 419 if (w->num_kcontrols)
469 int ret = 0; 420 pr_err("asoc: PGA controls not supported: '%s'\n", w->name);
470
471 if (!w->num_kcontrols)
472 return -EINVAL;
473 421
474 kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); 422 return 0;
475 ret = snd_ctl_add(codec->card, kcontrol);
476 if (ret < 0) {
477 printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
478 return ret;
479 }
480
481 return ret;
482} 423}
483 424
484/* reset 'walked' bit for each dapm path */ 425/* reset 'walked' bit for each dapm path */
@@ -490,6 +431,25 @@ static inline void dapm_clear_walk(struct snd_soc_codec *codec)
490 p->walked = 0; 431 p->walked = 0;
491} 432}
492 433
434/* We implement power down on suspend by checking the power state of
435 * the ALSA card - when we are suspending the ALSA state for the card
436 * is set to D3.
437 */
438static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
439{
440 struct snd_soc_codec *codec = widget->codec;
441
442 switch (snd_power_get_state(codec->card)) {
443 case SNDRV_CTL_POWER_D3hot:
444 case SNDRV_CTL_POWER_D3cold:
445 if (widget->ignore_suspend)
446 pr_debug("%s ignoring suspend\n", widget->name);
447 return widget->ignore_suspend;
448 default:
449 return 1;
450 }
451}
452
493/* 453/*
494 * Recursively check for a completed path to an active or physically connected 454 * Recursively check for a completed path to an active or physically connected
495 * output widget. Returns number of complete paths. 455 * output widget. Returns number of complete paths.
@@ -506,7 +466,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
506 case snd_soc_dapm_adc: 466 case snd_soc_dapm_adc:
507 case snd_soc_dapm_aif_out: 467 case snd_soc_dapm_aif_out:
508 if (widget->active) 468 if (widget->active)
509 return 1; 469 return snd_soc_dapm_suspend_check(widget);
510 default: 470 default:
511 break; 471 break;
512 } 472 }
@@ -514,12 +474,12 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
514 if (widget->connected) { 474 if (widget->connected) {
515 /* connected pin ? */ 475 /* connected pin ? */
516 if (widget->id == snd_soc_dapm_output && !widget->ext) 476 if (widget->id == snd_soc_dapm_output && !widget->ext)
517 return 1; 477 return snd_soc_dapm_suspend_check(widget);
518 478
519 /* connected jack or spk ? */ 479 /* connected jack or spk ? */
520 if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk || 480 if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
521 (widget->id == snd_soc_dapm_line && !list_empty(&widget->sources))) 481 (widget->id == snd_soc_dapm_line && !list_empty(&widget->sources)))
522 return 1; 482 return snd_soc_dapm_suspend_check(widget);
523 } 483 }
524 484
525 list_for_each_entry(path, &widget->sinks, list_source) { 485 list_for_each_entry(path, &widget->sinks, list_source) {
@@ -552,7 +512,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
552 case snd_soc_dapm_dac: 512 case snd_soc_dapm_dac:
553 case snd_soc_dapm_aif_in: 513 case snd_soc_dapm_aif_in:
554 if (widget->active) 514 if (widget->active)
555 return 1; 515 return snd_soc_dapm_suspend_check(widget);
556 default: 516 default:
557 break; 517 break;
558 } 518 }
@@ -560,16 +520,16 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
560 if (widget->connected) { 520 if (widget->connected) {
561 /* connected pin ? */ 521 /* connected pin ? */
562 if (widget->id == snd_soc_dapm_input && !widget->ext) 522 if (widget->id == snd_soc_dapm_input && !widget->ext)
563 return 1; 523 return snd_soc_dapm_suspend_check(widget);
564 524
565 /* connected VMID/Bias for lower pops */ 525 /* connected VMID/Bias for lower pops */
566 if (widget->id == snd_soc_dapm_vmid) 526 if (widget->id == snd_soc_dapm_vmid)
567 return 1; 527 return snd_soc_dapm_suspend_check(widget);
568 528
569 /* connected jack ? */ 529 /* connected jack ? */
570 if (widget->id == snd_soc_dapm_mic || 530 if (widget->id == snd_soc_dapm_mic ||
571 (widget->id == snd_soc_dapm_line && !list_empty(&widget->sinks))) 531 (widget->id == snd_soc_dapm_line && !list_empty(&widget->sinks)))
572 return 1; 532 return snd_soc_dapm_suspend_check(widget);
573 } 533 }
574 534
575 list_for_each_entry(path, &widget->sources, list_sink) { 535 list_for_each_entry(path, &widget->sources, list_sink) {
@@ -634,16 +594,8 @@ static int dapm_generic_apply_power(struct snd_soc_dapm_widget *w)
634 return ret; 594 return ret;
635 } 595 }
636 596
637 /* Lower PGA volume to reduce pops */
638 if (w->id == snd_soc_dapm_pga && !w->power)
639 dapm_set_pga(w, w->power);
640
641 dapm_update_bits(w); 597 dapm_update_bits(w);
642 598
643 /* Raise PGA volume to reduce pops */
644 if (w->id == snd_soc_dapm_pga && w->power)
645 dapm_set_pga(w, w->power);
646
647 /* power up post event */ 599 /* power up post event */
648 if (w->power && w->event && 600 if (w->power && w->event &&
649 (w->event_flags & SND_SOC_DAPM_POST_PMU)) { 601 (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
@@ -810,10 +762,6 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
810 pr_err("%s: pre event failed: %d\n", 762 pr_err("%s: pre event failed: %d\n",
811 w->name, ret); 763 w->name, ret);
812 } 764 }
813
814 /* Lower PGA volume to reduce pops */
815 if (w->id == snd_soc_dapm_pga && !w->power)
816 dapm_set_pga(w, w->power);
817 } 765 }
818 766
819 if (reg >= 0) { 767 if (reg >= 0) {
@@ -825,10 +773,6 @@ static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
825 } 773 }
826 774
827 list_for_each_entry(w, pending, power_list) { 775 list_for_each_entry(w, pending, power_list) {
828 /* Raise PGA volume to reduce pops */
829 if (w->id == snd_soc_dapm_pga && w->power)
830 dapm_set_pga(w, w->power);
831
832 /* power up post event */ 776 /* power up post event */
833 if (w->power && w->event && 777 if (w->power && w->event &&
834 (w->event_flags & SND_SOC_DAPM_POST_PMU)) { 778 (w->event_flags & SND_SOC_DAPM_POST_PMU)) {
@@ -973,19 +917,12 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
973 if (!w->power_check) 917 if (!w->power_check)
974 continue; 918 continue;
975 919
976 /* If we're suspending then pull down all the 920 if (!w->force)
977 * power. */
978 switch (event) {
979 case SND_SOC_DAPM_STREAM_SUSPEND:
980 power = 0;
981 break;
982
983 default:
984 power = w->power_check(w); 921 power = w->power_check(w);
985 if (power) 922 else
986 sys_power = 1; 923 power = 1;
987 break; 924 if (power)
988 } 925 sys_power = 1;
989 926
990 if (w->power == power) 927 if (w->power == power)
991 continue; 928 continue;
@@ -1076,6 +1013,7 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
1076 1013
1077 pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n", 1014 pop_dbg(codec->pop_time, "DAPM sequencing finished, waiting %dms\n",
1078 codec->pop_time); 1015 codec->pop_time);
1016 pop_wait(codec->pop_time);
1079 1017
1080 return 0; 1018 return 0;
1081} 1019}
@@ -1338,6 +1276,9 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
1338 if (!strcmp(w->name, pin)) { 1276 if (!strcmp(w->name, pin)) {
1339 pr_debug("dapm: %s: pin %s\n", codec->name, pin); 1277 pr_debug("dapm: %s: pin %s\n", codec->name, pin);
1340 w->connected = status; 1278 w->connected = status;
1279 /* Allow disabling of forced pins */
1280 if (status == 0)
1281 w->force = 0;
1341 return 0; 1282 return 0;
1342 } 1283 }
1343 } 1284 }
@@ -1594,12 +1535,6 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
1594 unsigned int invert = mc->invert; 1535 unsigned int invert = mc->invert;
1595 unsigned int mask = (1 << fls(max)) - 1; 1536 unsigned int mask = (1 << fls(max)) - 1;
1596 1537
1597 /* return the saved value if we are powered down */
1598 if (widget->id == snd_soc_dapm_pga && !widget->power) {
1599 ucontrol->value.integer.value[0] = widget->saved_value;
1600 return 0;
1601 }
1602
1603 ucontrol->value.integer.value[0] = 1538 ucontrol->value.integer.value[0] =
1604 (snd_soc_read(widget->codec, reg) >> shift) & mask; 1539 (snd_soc_read(widget->codec, reg) >> shift) & mask;
1605 if (shift != rshift) 1540 if (shift != rshift)
@@ -1659,13 +1594,6 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1659 mutex_lock(&widget->codec->mutex); 1594 mutex_lock(&widget->codec->mutex);
1660 widget->value = val; 1595 widget->value = val;
1661 1596
1662 /* save volume value if the widget is powered down */
1663 if (widget->id == snd_soc_dapm_pga && !widget->power) {
1664 widget->saved_value = val;
1665 mutex_unlock(&widget->codec->mutex);
1666 return 1;
1667 }
1668
1669 if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { 1597 if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
1670 if (val) 1598 if (val)
1671 /* new connection */ 1599 /* new connection */
@@ -2094,18 +2022,8 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
2094 w->active = 0; 2022 w->active = 0;
2095 break; 2023 break;
2096 case SND_SOC_DAPM_STREAM_SUSPEND: 2024 case SND_SOC_DAPM_STREAM_SUSPEND:
2097 if (w->active)
2098 w->suspend = 1;
2099 w->active = 0;
2100 break;
2101 case SND_SOC_DAPM_STREAM_RESUME: 2025 case SND_SOC_DAPM_STREAM_RESUME:
2102 if (w->suspend) {
2103 w->active = 1;
2104 w->suspend = 0;
2105 }
2106 break;
2107 case SND_SOC_DAPM_STREAM_PAUSE_PUSH: 2026 case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
2108 break;
2109 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: 2027 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
2110 break; 2028 break;
2111 } 2029 }
@@ -2135,6 +2053,36 @@ int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin)
2135EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); 2053EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
2136 2054
2137/** 2055/**
2056 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
2057 * @codec: SoC codec
2058 * @pin: pin name
2059 *
2060 * Enables input/output pin regardless of any other state. This is
2061 * intended for use with microphone bias supplies used in microphone
2062 * jack detection.
2063 *
2064 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
2065 * do any widget power switching.
2066 */
2067int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec, const char *pin)
2068{
2069 struct snd_soc_dapm_widget *w;
2070
2071 list_for_each_entry(w, &codec->dapm_widgets, list) {
2072 if (!strcmp(w->name, pin)) {
2073 pr_debug("dapm: %s: pin %s\n", codec->name, pin);
2074 w->connected = 1;
2075 w->force = 1;
2076 return 0;
2077 }
2078 }
2079
2080 pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin);
2081 return -EINVAL;
2082}
2083EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
2084
2085/**
2138 * snd_soc_dapm_disable_pin - disable pin. 2086 * snd_soc_dapm_disable_pin - disable pin.
2139 * @codec: SoC codec 2087 * @codec: SoC codec
2140 * @pin: pin name 2088 * @pin: pin name
@@ -2192,6 +2140,33 @@ int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin)
2192EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); 2140EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
2193 2141
2194/** 2142/**
2143 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
2144 * @codec: audio codec
2145 * @pin: audio signal pin endpoint (or start point)
2146 *
2147 * Mark the given endpoint or pin as ignoring suspend. When the
2148 * system is disabled a path between two endpoints flagged as ignoring
2149 * suspend will not be disabled. The path must already be enabled via
2150 * normal means at suspend time, it will not be turned on if it was not
2151 * already enabled.
2152 */
2153int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin)
2154{
2155 struct snd_soc_dapm_widget *w;
2156
2157 list_for_each_entry(w, &codec->dapm_widgets, list) {
2158 if (!strcmp(w->name, pin)) {
2159 w->ignore_suspend = 1;
2160 return 0;
2161 }
2162 }
2163
2164 pr_err("Unknown DAPM pin: %s\n", pin);
2165 return -EINVAL;
2166}
2167EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
2168
2169/**
2195 * snd_soc_dapm_free - free dapm resources 2170 * snd_soc_dapm_free - free dapm resources
2196 * @socdev: SoC device 2171 * @socdev: SoC device
2197 * 2172 *