aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-07-24 09:27:37 -0400
committerMark Brown <broonie@linaro.org>2013-07-24 09:56:19 -0400
commitce6cfaf1de136cd3e6ed7c0ed984be8d003a58c1 (patch)
tree1201b2e11688904d7f6c58f8202e757110f17b32
parentc3f48ae6fd5a1ebdcaff5efe35f88f31daaee225 (diff)
ASoC: dapm: Run widget updates for shared controls at the same time
Currently when updating a control that is shared between multiple widgets the whole power-up/power-down sequence is being run once for each widget. The control register is updated during the first run, which means the CODEC internal routing is also updated for all widgets during this first run. The input and output paths for each widgets are only updated though during the respective run for that widget. This leads to a slight inconsistency between the CODEC's internal state and ASoC's state, which causes non optimal behavior in regard to click and pop avoidance. E.g. consider the following setup where two MUXs share the same control. +------+ A1 ------| | | MUX1 |----- C1 B1 ------| | +------+ | control ---+ | +------+ A2 ------| | | MUX2 |----- C2 B2 ------| | +------+ If the control is updated to switch the MUXs from input A to input B with the current code the power-up/power-down sequence will look like this: Run soc_dapm_mux_update_power for MUX1 Power-down A1 Update MUXing Power-up B1 Run soc_dapm_mux_update_power for MUX2 Power-down A2 (Update MUXing) Power-up B2 Note that the second 'Update Muxing' is a no-op, since the register was already updated. While the preferred order for avoiding pops and clicks should be: Run soc_dapm_mux_update_power for control Power-down A1 Power-down A2 Update MUXing Power-up B1 Power-up B2 This patch changes the behavior to the later by running the updates for all widgets that the control is attached to at the same time. The new code is also a bit simpler since callers of soc_dapm_{mux,muxer}_update_power don't have to loop over each widget anymore and neither do we need to keep track for which of the kcontrol's widgets the current update is. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--include/sound/soc-dapm.h7
-rw-r--r--sound/soc/soc-dapm.c162
2 files changed, 71 insertions, 98 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 3e479f4e15f5..3717ad089486 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -391,10 +391,10 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
391void snd_soc_dapm_shutdown(struct snd_soc_card *card); 391void snd_soc_dapm_shutdown(struct snd_soc_card *card);
392 392
393/* external DAPM widget events */ 393/* external DAPM widget events */
394int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 394int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
395 struct snd_kcontrol *kcontrol, int connect); 395 struct snd_kcontrol *kcontrol, int connect);
396int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, 396int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
397 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e); 397 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e);
398 398
399/* dapm sys fs - used by the core */ 399/* dapm sys fs - used by the core */
400int snd_soc_dapm_sys_add(struct device *dev); 400int snd_soc_dapm_sys_add(struct device *dev);
@@ -559,7 +559,6 @@ struct snd_soc_dapm_widget {
559}; 559};
560 560
561struct snd_soc_dapm_update { 561struct snd_soc_dapm_update {
562 struct snd_soc_dapm_widget *widget;
563 struct snd_kcontrol *kcontrol; 562 struct snd_kcontrol *kcontrol;
564 int reg; 563 int reg;
565 int mask; 564 int mask;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 8d9c09b266fd..6f8a01bf6ca8 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1456,34 +1456,45 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
1456static void dapm_widget_update(struct snd_soc_dapm_context *dapm) 1456static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
1457{ 1457{
1458 struct snd_soc_dapm_update *update = dapm->update; 1458 struct snd_soc_dapm_update *update = dapm->update;
1459 struct snd_soc_dapm_widget *w; 1459 struct snd_soc_dapm_widget_list *wlist;
1460 struct snd_soc_dapm_widget *w = NULL;
1461 unsigned int wi;
1460 int ret; 1462 int ret;
1461 1463
1462 if (!update) 1464 if (!update)
1463 return; 1465 return;
1464 1466
1465 w = update->widget; 1467 wlist = snd_kcontrol_chip(update->kcontrol);
1466 1468
1467 if (w->event && 1469 for (wi = 0; wi < wlist->num_widgets; wi++) {
1468 (w->event_flags & SND_SOC_DAPM_PRE_REG)) { 1470 w = wlist->widgets[wi];
1469 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG); 1471
1470 if (ret != 0) 1472 if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
1471 dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", 1473 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
1472 w->name, ret); 1474 if (ret != 0)
1475 dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
1476 w->name, ret);
1477 }
1473 } 1478 }
1474 1479
1480 if (!w)
1481 return;
1482
1475 ret = soc_widget_update_bits_locked(w, update->reg, update->mask, 1483 ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
1476 update->val); 1484 update->val);
1477 if (ret < 0) 1485 if (ret < 0)
1478 dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n", 1486 dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n",
1479 w->name, ret); 1487 w->name, ret);
1480 1488
1481 if (w->event && 1489 for (wi = 0; wi < wlist->num_widgets; wi++) {
1482 (w->event_flags & SND_SOC_DAPM_POST_REG)) { 1490 w = wlist->widgets[wi];
1483 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG); 1491
1484 if (ret != 0) 1492 if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
1485 dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", 1493 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
1486 w->name, ret); 1494 if (ret != 0)
1495 dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
1496 w->name, ret);
1497 }
1487 } 1498 }
1488} 1499}
1489 1500
@@ -1936,19 +1947,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
1936#endif 1947#endif
1937 1948
1938/* test and update the power status of a mux widget */ 1949/* test and update the power status of a mux widget */
1939static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, 1950static int soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
1940 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) 1951 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
1941{ 1952{
1942 struct snd_soc_dapm_path *path; 1953 struct snd_soc_dapm_path *path;
1943 int found = 0; 1954 int found = 0;
1944 1955
1945 if (widget->id != snd_soc_dapm_mux &&
1946 widget->id != snd_soc_dapm_virt_mux &&
1947 widget->id != snd_soc_dapm_value_mux)
1948 return -ENODEV;
1949
1950 /* find dapm widget path assoc with kcontrol */ 1956 /* find dapm widget path assoc with kcontrol */
1951 list_for_each_entry(path, &widget->dapm->card->paths, list) { 1957 list_for_each_entry(path, &dapm->card->paths, list) {
1952 if (path->kcontrol != kcontrol) 1958 if (path->kcontrol != kcontrol)
1953 continue; 1959 continue;
1954 1960
@@ -1966,24 +1972,23 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1966 "mux disconnection"); 1972 "mux disconnection");
1967 path->connect = 0; /* old connection must be powered down */ 1973 path->connect = 0; /* old connection must be powered down */
1968 } 1974 }
1975 dapm_mark_dirty(path->sink, "mux change");
1969 } 1976 }
1970 1977
1971 if (found) { 1978 if (found)
1972 dapm_mark_dirty(widget, "mux change"); 1979 dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
1973 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
1974 }
1975 1980
1976 return found; 1981 return found;
1977} 1982}
1978 1983
1979int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, 1984int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
1980 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) 1985 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
1981{ 1986{
1982 struct snd_soc_card *card = widget->dapm->card; 1987 struct snd_soc_card *card = dapm->card;
1983 int ret; 1988 int ret;
1984 1989
1985 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 1990 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
1986 ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); 1991 ret = soc_dapm_mux_update_power(dapm, kcontrol, mux, e);
1987 mutex_unlock(&card->dapm_mutex); 1992 mutex_unlock(&card->dapm_mutex);
1988 if (ret > 0) 1993 if (ret > 0)
1989 soc_dpcm_runtime_update(card); 1994 soc_dpcm_runtime_update(card);
@@ -1992,19 +1997,14 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1992EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); 1997EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
1993 1998
1994/* test and update the power status of a mixer or switch widget */ 1999/* test and update the power status of a mixer or switch widget */
1995static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 2000static int soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
1996 struct snd_kcontrol *kcontrol, int connect) 2001 struct snd_kcontrol *kcontrol, int connect)
1997{ 2002{
1998 struct snd_soc_dapm_path *path; 2003 struct snd_soc_dapm_path *path;
1999 int found = 0; 2004 int found = 0;
2000 2005
2001 if (widget->id != snd_soc_dapm_mixer &&
2002 widget->id != snd_soc_dapm_mixer_named_ctl &&
2003 widget->id != snd_soc_dapm_switch)
2004 return -ENODEV;
2005
2006 /* find dapm widget path assoc with kcontrol */ 2006 /* find dapm widget path assoc with kcontrol */
2007 list_for_each_entry(path, &widget->dapm->card->paths, list) { 2007 list_for_each_entry(path, &dapm->card->paths, list) {
2008 if (path->kcontrol != kcontrol) 2008 if (path->kcontrol != kcontrol)
2009 continue; 2009 continue;
2010 2010
@@ -2012,24 +2012,23 @@ static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
2012 found = 1; 2012 found = 1;
2013 path->connect = connect; 2013 path->connect = connect;
2014 dapm_mark_dirty(path->source, "mixer connection"); 2014 dapm_mark_dirty(path->source, "mixer connection");
2015 dapm_mark_dirty(path->sink, "mixer update");
2015 } 2016 }
2016 2017
2017 if (found) { 2018 if (found)
2018 dapm_mark_dirty(widget, "mixer update"); 2019 dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
2019 dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
2020 }
2021 2020
2022 return found; 2021 return found;
2023} 2022}
2024 2023
2025int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 2024int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
2026 struct snd_kcontrol *kcontrol, int connect) 2025 struct snd_kcontrol *kcontrol, int connect)
2027{ 2026{
2028 struct snd_soc_card *card = widget->dapm->card; 2027 struct snd_soc_card *card = dapm->card;
2029 int ret; 2028 int ret;
2030 2029
2031 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 2030 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2032 ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); 2031 ret = soc_dapm_mixer_update_power(dapm, kcontrol, connect);
2033 mutex_unlock(&card->dapm_mutex); 2032 mutex_unlock(&card->dapm_mutex);
2034 if (ret > 0) 2033 if (ret > 0)
2035 soc_dpcm_runtime_update(card); 2034 soc_dpcm_runtime_update(card);
@@ -2695,7 +2694,6 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2695 unsigned int val; 2694 unsigned int val;
2696 int connect, change; 2695 int connect, change;
2697 struct snd_soc_dapm_update update; 2696 struct snd_soc_dapm_update update;
2698 int wi;
2699 2697
2700 if (snd_soc_volsw_is_stereo(mc)) 2698 if (snd_soc_volsw_is_stereo(mc))
2701 dev_warn(widget->dapm->dev, 2699 dev_warn(widget->dapm->dev,
@@ -2714,22 +2712,16 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2714 2712
2715 change = snd_soc_test_bits(widget->codec, reg, mask, val); 2713 change = snd_soc_test_bits(widget->codec, reg, mask, val);
2716 if (change) { 2714 if (change) {
2717 for (wi = 0; wi < wlist->num_widgets; wi++) { 2715 update.kcontrol = kcontrol;
2718 widget = wlist->widgets[wi]; 2716 update.reg = reg;
2719 2717 update.mask = mask;
2720 widget->value = val; 2718 update.val = val;
2721 2719
2722 update.kcontrol = kcontrol; 2720 widget->dapm->update = &update;
2723 update.widget = widget;
2724 update.reg = reg;
2725 update.mask = mask;
2726 update.val = val;
2727 widget->dapm->update = &update;
2728 2721
2729 soc_dapm_mixer_update_power(widget, kcontrol, connect); 2722 soc_dapm_mixer_update_power(widget->dapm, kcontrol, connect);
2730 2723
2731 widget->dapm->update = NULL; 2724 widget->dapm->update = NULL;
2732 }
2733 } 2725 }
2734 2726
2735 mutex_unlock(&card->dapm_mutex); 2727 mutex_unlock(&card->dapm_mutex);
@@ -2784,7 +2776,6 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
2784 unsigned int val, mux, change; 2776 unsigned int val, mux, change;
2785 unsigned int mask; 2777 unsigned int mask;
2786 struct snd_soc_dapm_update update; 2778 struct snd_soc_dapm_update update;
2787 int wi;
2788 2779
2789 if (ucontrol->value.enumerated.item[0] > e->max - 1) 2780 if (ucontrol->value.enumerated.item[0] > e->max - 1)
2790 return -EINVAL; 2781 return -EINVAL;
@@ -2802,22 +2793,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
2802 2793
2803 change = snd_soc_test_bits(widget->codec, e->reg, mask, val); 2794 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
2804 if (change) { 2795 if (change) {
2805 for (wi = 0; wi < wlist->num_widgets; wi++) { 2796 widget->value = val;
2806 widget = wlist->widgets[wi];
2807 2797
2808 widget->value = val; 2798 update.kcontrol = kcontrol;
2799 update.reg = e->reg;
2800 update.mask = mask;
2801 update.val = val;
2802 widget->dapm->update = &update;
2809 2803
2810 update.kcontrol = kcontrol; 2804 soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e);
2811 update.widget = widget;
2812 update.reg = e->reg;
2813 update.mask = mask;
2814 update.val = val;
2815 widget->dapm->update = &update;
2816 2805
2817 soc_dapm_mux_update_power(widget, kcontrol, mux, e); 2806 widget->dapm->update = NULL;
2818
2819 widget->dapm->update = NULL;
2820 }
2821 } 2807 }
2822 2808
2823 mutex_unlock(&card->dapm_mutex); 2809 mutex_unlock(&card->dapm_mutex);
@@ -2861,7 +2847,6 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
2861 struct soc_enum *e = 2847 struct soc_enum *e =
2862 (struct soc_enum *)kcontrol->private_value; 2848 (struct soc_enum *)kcontrol->private_value;
2863 int change; 2849 int change;
2864 int wi;
2865 2850
2866 if (ucontrol->value.enumerated.item[0] >= e->max) 2851 if (ucontrol->value.enumerated.item[0] >= e->max)
2867 return -EINVAL; 2852 return -EINVAL;
@@ -2870,13 +2855,8 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
2870 2855
2871 change = widget->value != ucontrol->value.enumerated.item[0]; 2856 change = widget->value != ucontrol->value.enumerated.item[0];
2872 if (change) { 2857 if (change) {
2873 for (wi = 0; wi < wlist->num_widgets; wi++) { 2858 widget->value = ucontrol->value.enumerated.item[0];
2874 widget = wlist->widgets[wi]; 2859 soc_dapm_mux_update_power(widget->dapm, kcontrol, widget->value, e);
2875
2876 widget->value = ucontrol->value.enumerated.item[0];
2877
2878 soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
2879 }
2880 } 2860 }
2881 2861
2882 mutex_unlock(&card->dapm_mutex); 2862 mutex_unlock(&card->dapm_mutex);
@@ -2949,7 +2929,6 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
2949 unsigned int val, mux, change; 2929 unsigned int val, mux, change;
2950 unsigned int mask; 2930 unsigned int mask;
2951 struct snd_soc_dapm_update update; 2931 struct snd_soc_dapm_update update;
2952 int wi;
2953 2932
2954 if (ucontrol->value.enumerated.item[0] > e->max - 1) 2933 if (ucontrol->value.enumerated.item[0] > e->max - 1)
2955 return -EINVAL; 2934 return -EINVAL;
@@ -2967,22 +2946,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
2967 2946
2968 change = snd_soc_test_bits(widget->codec, e->reg, mask, val); 2947 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
2969 if (change) { 2948 if (change) {
2970 for (wi = 0; wi < wlist->num_widgets; wi++) { 2949 widget->value = val;
2971 widget = wlist->widgets[wi];
2972
2973 widget->value = val;
2974 2950
2975 update.kcontrol = kcontrol; 2951 update.kcontrol = kcontrol;
2976 update.widget = widget; 2952 update.reg = e->reg;
2977 update.reg = e->reg; 2953 update.mask = mask;
2978 update.mask = mask; 2954 update.val = val;
2979 update.val = val; 2955 widget->dapm->update = &update;
2980 widget->dapm->update = &update;
2981 2956
2982 soc_dapm_mux_update_power(widget, kcontrol, mux, e); 2957 soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e);
2983 2958
2984 widget->dapm->update = NULL; 2959 widget->dapm->update = NULL;
2985 }
2986 } 2960 }
2987 2961
2988 mutex_unlock(&card->dapm_mutex); 2962 mutex_unlock(&card->dapm_mutex);