aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-12-14 11:13:57 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-12-17 06:18:04 -0500
commit97404f2e0386ac147cec00fc5d89ea475b04bd78 (patch)
treec84f883afed54cb7d20e74818302a6f960c59317 /sound/soc/soc-dapm.c
parent7be31be880ee00c6f8d38184368e8a834923b469 (diff)
ASoC: Do DAPM control updates in the middle of DAPM sequences
Attempt to minimise audible effects from mixer and mux updates by implementing the actual register changes between powering down widgets that have become unused and powering up widgets that are newly used. This means that we're making the change with the minimum set of widgets powered, that the input path is connected when we're powering up widgets (so things like DC offset correction can run with their signal active) and that we bring things down to cold before switching away. Since hardware tends to be designed for the power on/off case more than for dynamic reconfiguration this should minimise pops and clicks during reconfiguration while active. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Tested-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c130
1 files changed, 72 insertions, 58 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index f362d1de78f3..1debc3b05665 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -920,6 +920,41 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
920 dapm_seq_run_coalesced(dapm, &pending); 920 dapm_seq_run_coalesced(dapm, &pending);
921} 921}
922 922
923static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
924{
925 struct snd_soc_dapm_update *update = dapm->update;
926 struct snd_soc_dapm_widget *w;
927 int ret;
928
929 if (!update)
930 return;
931
932 w = update->widget;
933
934 if (w->event &&
935 (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
936 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
937 if (ret != 0)
938 pr_err("%s DAPM pre-event failed: %d\n",
939 w->name, ret);
940 }
941
942 ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
943 update->val);
944 if (ret < 0)
945 pr_err("%s DAPM update failed: %d\n", w->name, ret);
946
947 if (w->event &&
948 (w->event_flags & SND_SOC_DAPM_POST_REG)) {
949 ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
950 if (ret != 0)
951 pr_err("%s DAPM post-event failed: %d\n",
952 w->name, ret);
953 }
954}
955
956
957
923/* 958/*
924 * Scan each dapm widget for complete audio path. 959 * Scan each dapm widget for complete audio path.
925 * A complete path is a route that has valid endpoints i.e.:- 960 * A complete path is a route that has valid endpoints i.e.:-
@@ -1037,6 +1072,8 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1037 /* Power down widgets first; try to avoid amplifying pops. */ 1072 /* Power down widgets first; try to avoid amplifying pops. */
1038 dapm_seq_run(dapm, &down_list, event, dapm_down_seq); 1073 dapm_seq_run(dapm, &down_list, event, dapm_down_seq);
1039 1074
1075 dapm_widget_update(dapm);
1076
1040 /* Now power up. */ 1077 /* Now power up. */
1041 dapm_seq_run(dapm, &up_list, event, dapm_up_seq); 1078 dapm_seq_run(dapm, &up_list, event, dapm_up_seq);
1042 1079
@@ -1683,13 +1720,12 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1683 (struct soc_mixer_control *)kcontrol->private_value; 1720 (struct soc_mixer_control *)kcontrol->private_value;
1684 unsigned int reg = mc->reg; 1721 unsigned int reg = mc->reg;
1685 unsigned int shift = mc->shift; 1722 unsigned int shift = mc->shift;
1686 unsigned int rshift = mc->rshift;
1687 int max = mc->max; 1723 int max = mc->max;
1688 unsigned int mask = (1 << fls(max)) - 1; 1724 unsigned int mask = (1 << fls(max)) - 1;
1689 unsigned int invert = mc->invert; 1725 unsigned int invert = mc->invert;
1690 unsigned int val, val2, val_mask; 1726 unsigned int val, val_mask;
1691 int connect; 1727 int connect, change;
1692 int ret; 1728 struct snd_soc_dapm_update update;
1693 1729
1694 val = (ucontrol->value.integer.value[0] & mask); 1730 val = (ucontrol->value.integer.value[0] & mask);
1695 1731
@@ -1697,18 +1733,12 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1697 val = max - val; 1733 val = max - val;
1698 val_mask = mask << shift; 1734 val_mask = mask << shift;
1699 val = val << shift; 1735 val = val << shift;
1700 if (shift != rshift) {
1701 val2 = (ucontrol->value.integer.value[1] & mask);
1702 if (invert)
1703 val2 = max - val2;
1704 val_mask |= mask << rshift;
1705 val |= val2 << rshift;
1706 }
1707 1736
1708 mutex_lock(&widget->codec->mutex); 1737 mutex_lock(&widget->codec->mutex);
1709 widget->value = val; 1738 widget->value = val;
1710 1739
1711 if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { 1740 change = snd_soc_test_bits(widget->codec, reg, val_mask, val);
1741 if (change) {
1712 if (val) 1742 if (val)
1713 /* new connection */ 1743 /* new connection */
1714 connect = invert ? 0:1; 1744 connect = invert ? 0:1;
@@ -1716,28 +1746,20 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
1716 /* old connection must be powered down */ 1746 /* old connection must be powered down */
1717 connect = invert ? 1:0; 1747 connect = invert ? 1:0;
1718 1748
1749 update.kcontrol = kcontrol;
1750 update.widget = widget;
1751 update.reg = reg;
1752 update.mask = mask;
1753 update.val = val;
1754 widget->dapm->update = &update;
1755
1719 dapm_mixer_update_power(widget, kcontrol, connect); 1756 dapm_mixer_update_power(widget, kcontrol, connect);
1757
1758 widget->dapm->update = NULL;
1720 } 1759 }
1721 1760
1722 if (widget->event) {
1723 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
1724 ret = widget->event(widget, kcontrol,
1725 SND_SOC_DAPM_PRE_REG);
1726 if (ret < 0) {
1727 ret = 1;
1728 goto out;
1729 }
1730 }
1731 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1732 if (widget->event_flags & SND_SOC_DAPM_POST_REG)
1733 ret = widget->event(widget, kcontrol,
1734 SND_SOC_DAPM_POST_REG);
1735 } else
1736 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
1737
1738out:
1739 mutex_unlock(&widget->codec->mutex); 1761 mutex_unlock(&widget->codec->mutex);
1740 return ret; 1762 return 0;
1741} 1763}
1742EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); 1764EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
1743 1765
@@ -1785,7 +1807,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1785 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 1807 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1786 unsigned int val, mux, change; 1808 unsigned int val, mux, change;
1787 unsigned int mask, bitmask; 1809 unsigned int mask, bitmask;
1788 int ret = 0; 1810 struct snd_soc_dapm_update update;
1789 1811
1790 for (bitmask = 1; bitmask < e->max; bitmask <<= 1) 1812 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
1791 ; 1813 ;
@@ -1804,24 +1826,20 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
1804 mutex_lock(&widget->codec->mutex); 1826 mutex_lock(&widget->codec->mutex);
1805 widget->value = val; 1827 widget->value = val;
1806 change = snd_soc_test_bits(widget->codec, e->reg, mask, val); 1828 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
1807 dapm_mux_update_power(widget, kcontrol, change, mux, e);
1808 1829
1809 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1830 update.kcontrol = kcontrol;
1810 ret = widget->event(widget, 1831 update.widget = widget;
1811 kcontrol, SND_SOC_DAPM_PRE_REG); 1832 update.reg = e->reg;
1812 if (ret < 0) 1833 update.mask = mask;
1813 goto out; 1834 update.val = val;
1814 } 1835 widget->dapm->update = &update;
1815 1836
1816 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); 1837 dapm_mux_update_power(widget, kcontrol, change, mux, e);
1817 1838
1818 if (widget->event_flags & SND_SOC_DAPM_POST_REG) 1839 widget->dapm->update = NULL;
1819 ret = widget->event(widget,
1820 kcontrol, SND_SOC_DAPM_POST_REG);
1821 1840
1822out:
1823 mutex_unlock(&widget->codec->mutex); 1841 mutex_unlock(&widget->codec->mutex);
1824 return ret; 1842 return change;
1825} 1843}
1826EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); 1844EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
1827 1845
@@ -1933,7 +1951,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
1933 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 1951 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1934 unsigned int val, mux, change; 1952 unsigned int val, mux, change;
1935 unsigned int mask; 1953 unsigned int mask;
1936 int ret = 0; 1954 struct snd_soc_dapm_update update;
1937 1955
1938 if (ucontrol->value.enumerated.item[0] > e->max - 1) 1956 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1939 return -EINVAL; 1957 return -EINVAL;
@@ -1950,24 +1968,20 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
1950 mutex_lock(&widget->codec->mutex); 1968 mutex_lock(&widget->codec->mutex);
1951 widget->value = val; 1969 widget->value = val;
1952 change = snd_soc_test_bits(widget->codec, e->reg, mask, val); 1970 change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
1953 dapm_mux_update_power(widget, kcontrol, change, mux, e);
1954 1971
1955 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1972 update.kcontrol = kcontrol;
1956 ret = widget->event(widget, 1973 update.widget = widget;
1957 kcontrol, SND_SOC_DAPM_PRE_REG); 1974 update.reg = e->reg;
1958 if (ret < 0) 1975 update.mask = mask;
1959 goto out; 1976 update.val = val;
1960 } 1977 widget->dapm->update = &update;
1961 1978
1962 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); 1979 dapm_mux_update_power(widget, kcontrol, change, mux, e);
1963 1980
1964 if (widget->event_flags & SND_SOC_DAPM_POST_REG) 1981 widget->dapm->update = NULL;
1965 ret = widget->event(widget,
1966 kcontrol, SND_SOC_DAPM_POST_REG);
1967 1982
1968out:
1969 mutex_unlock(&widget->codec->mutex); 1983 mutex_unlock(&widget->codec->mutex);
1970 return ret; 1984 return change;
1971} 1985}
1972EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); 1986EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
1973 1987