diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 157 |
1 files changed, 117 insertions, 40 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8de6f9dec4a2..0d294ef72590 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -719,6 +719,10 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
719 | 719 | ||
720 | /* Check if one of our outputs is connected */ | 720 | /* Check if one of our outputs is connected */ |
721 | list_for_each_entry(path, &w->sinks, list_source) { | 721 | list_for_each_entry(path, &w->sinks, list_source) { |
722 | if (path->connected && | ||
723 | !path->connected(path->source, path->sink)) | ||
724 | continue; | ||
725 | |||
722 | if (path->sink && path->sink->power_check && | 726 | if (path->sink && path->sink->power_check && |
723 | path->sink->power_check(path->sink)) { | 727 | path->sink->power_check(path->sink)) { |
724 | power = 1; | 728 | power = 1; |
@@ -973,9 +977,19 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
973 | if (!w->power_check) | 977 | if (!w->power_check) |
974 | continue; | 978 | continue; |
975 | 979 | ||
976 | power = w->power_check(w); | 980 | /* If we're suspending then pull down all the |
977 | if (power) | 981 | * power. */ |
978 | sys_power = 1; | 982 | switch (event) { |
983 | case SND_SOC_DAPM_STREAM_SUSPEND: | ||
984 | power = 0; | ||
985 | break; | ||
986 | |||
987 | default: | ||
988 | power = w->power_check(w); | ||
989 | if (power) | ||
990 | sys_power = 1; | ||
991 | break; | ||
992 | } | ||
979 | 993 | ||
980 | if (w->power == power) | 994 | if (w->power == power) |
981 | continue; | 995 | continue; |
@@ -999,8 +1013,12 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
999 | case SND_SOC_DAPM_STREAM_RESUME: | 1013 | case SND_SOC_DAPM_STREAM_RESUME: |
1000 | sys_power = 1; | 1014 | sys_power = 1; |
1001 | break; | 1015 | break; |
1016 | case SND_SOC_DAPM_STREAM_SUSPEND: | ||
1017 | sys_power = 0; | ||
1018 | break; | ||
1002 | case SND_SOC_DAPM_STREAM_NOP: | 1019 | case SND_SOC_DAPM_STREAM_NOP: |
1003 | sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; | 1020 | sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; |
1021 | break; | ||
1004 | default: | 1022 | default: |
1005 | break; | 1023 | break; |
1006 | } | 1024 | } |
@@ -1138,6 +1156,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1138 | w->active ? "active" : "inactive"); | 1156 | w->active ? "active" : "inactive"); |
1139 | 1157 | ||
1140 | list_for_each_entry(p, &w->sources, list_sink) { | 1158 | list_for_each_entry(p, &w->sources, list_sink) { |
1159 | if (p->connected && !p->connected(w, p->sink)) | ||
1160 | continue; | ||
1161 | |||
1141 | if (p->connect) | 1162 | if (p->connect) |
1142 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1163 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1143 | " in %s %s\n", | 1164 | " in %s %s\n", |
@@ -1145,6 +1166,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1145 | p->source->name); | 1166 | p->source->name); |
1146 | } | 1167 | } |
1147 | list_for_each_entry(p, &w->sinks, list_source) { | 1168 | list_for_each_entry(p, &w->sinks, list_source) { |
1169 | if (p->connected && !p->connected(w, p->sink)) | ||
1170 | continue; | ||
1171 | |||
1148 | if (p->connect) | 1172 | if (p->connect) |
1149 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1173 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1150 | " out %s %s\n", | 1174 | " out %s %s\n", |
@@ -1192,8 +1216,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) | |||
1192 | 1216 | ||
1193 | /* test and update the power status of a mux widget */ | 1217 | /* test and update the power status of a mux widget */ |
1194 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 1218 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
1195 | struct snd_kcontrol *kcontrol, int mask, | 1219 | struct snd_kcontrol *kcontrol, int change, |
1196 | int mux, int val, struct soc_enum *e) | 1220 | int mux, struct soc_enum *e) |
1197 | { | 1221 | { |
1198 | struct snd_soc_dapm_path *path; | 1222 | struct snd_soc_dapm_path *path; |
1199 | int found = 0; | 1223 | int found = 0; |
@@ -1202,7 +1226,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1202 | widget->id != snd_soc_dapm_value_mux) | 1226 | widget->id != snd_soc_dapm_value_mux) |
1203 | return -ENODEV; | 1227 | return -ENODEV; |
1204 | 1228 | ||
1205 | if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) | 1229 | if (!change) |
1206 | return 0; | 1230 | return 0; |
1207 | 1231 | ||
1208 | /* find dapm widget path assoc with kcontrol */ | 1232 | /* find dapm widget path assoc with kcontrol */ |
@@ -1387,10 +1411,13 @@ int snd_soc_dapm_sync(struct snd_soc_codec *codec) | |||
1387 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 1411 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1388 | 1412 | ||
1389 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | 1413 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, |
1390 | const char *sink, const char *control, const char *source) | 1414 | const struct snd_soc_dapm_route *route) |
1391 | { | 1415 | { |
1392 | struct snd_soc_dapm_path *path; | 1416 | struct snd_soc_dapm_path *path; |
1393 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 1417 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
1418 | const char *sink = route->sink; | ||
1419 | const char *control = route->control; | ||
1420 | const char *source = route->source; | ||
1394 | int ret = 0; | 1421 | int ret = 0; |
1395 | 1422 | ||
1396 | /* find src and dest widgets */ | 1423 | /* find src and dest widgets */ |
@@ -1414,6 +1441,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1414 | 1441 | ||
1415 | path->source = wsource; | 1442 | path->source = wsource; |
1416 | path->sink = wsink; | 1443 | path->sink = wsink; |
1444 | path->connected = route->connected; | ||
1417 | INIT_LIST_HEAD(&path->list); | 1445 | INIT_LIST_HEAD(&path->list); |
1418 | INIT_LIST_HEAD(&path->list_source); | 1446 | INIT_LIST_HEAD(&path->list_source); |
1419 | INIT_LIST_HEAD(&path->list_sink); | 1447 | INIT_LIST_HEAD(&path->list_sink); |
@@ -1514,8 +1542,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | |||
1514 | int i, ret; | 1542 | int i, ret; |
1515 | 1543 | ||
1516 | for (i = 0; i < num; i++) { | 1544 | for (i = 0; i < num; i++) { |
1517 | ret = snd_soc_dapm_add_route(codec, route->sink, | 1545 | ret = snd_soc_dapm_add_route(codec, route); |
1518 | route->control, route->source); | ||
1519 | if (ret < 0) { | 1546 | if (ret < 0) { |
1520 | printk(KERN_ERR "Failed to add route %s->%s\n", | 1547 | printk(KERN_ERR "Failed to add route %s->%s\n", |
1521 | route->source, | 1548 | route->source, |
@@ -1752,7 +1779,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1752 | { | 1779 | { |
1753 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1780 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1754 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1781 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1755 | unsigned int val, mux; | 1782 | unsigned int val, mux, change; |
1756 | unsigned int mask, bitmask; | 1783 | unsigned int mask, bitmask; |
1757 | int ret = 0; | 1784 | int ret = 0; |
1758 | 1785 | ||
@@ -1772,20 +1799,21 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1772 | 1799 | ||
1773 | mutex_lock(&widget->codec->mutex); | 1800 | mutex_lock(&widget->codec->mutex); |
1774 | widget->value = val; | 1801 | widget->value = val; |
1775 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); | 1802 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1776 | if (widget->event) { | 1803 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1777 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1804 | |
1778 | ret = widget->event(widget, | 1805 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1779 | kcontrol, SND_SOC_DAPM_PRE_REG); | 1806 | ret = widget->event(widget, |
1780 | if (ret < 0) | 1807 | kcontrol, SND_SOC_DAPM_PRE_REG); |
1781 | goto out; | 1808 | if (ret < 0) |
1782 | } | 1809 | goto out; |
1783 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1810 | } |
1784 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1811 | |
1785 | ret = widget->event(widget, | 1812 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1786 | kcontrol, SND_SOC_DAPM_POST_REG); | 1813 | |
1787 | } else | 1814 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1788 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1815 | ret = widget->event(widget, |
1816 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1789 | 1817 | ||
1790 | out: | 1818 | out: |
1791 | mutex_unlock(&widget->codec->mutex); | 1819 | mutex_unlock(&widget->codec->mutex); |
@@ -1794,6 +1822,54 @@ out: | |||
1794 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 1822 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
1795 | 1823 | ||
1796 | /** | 1824 | /** |
1825 | * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux | ||
1826 | * @kcontrol: mixer control | ||
1827 | * @ucontrol: control element information | ||
1828 | * | ||
1829 | * Returns 0 for success. | ||
1830 | */ | ||
1831 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | ||
1832 | struct snd_ctl_elem_value *ucontrol) | ||
1833 | { | ||
1834 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1835 | |||
1836 | ucontrol->value.enumerated.item[0] = widget->value; | ||
1837 | |||
1838 | return 0; | ||
1839 | } | ||
1840 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | ||
1841 | |||
1842 | /** | ||
1843 | * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux | ||
1844 | * @kcontrol: mixer control | ||
1845 | * @ucontrol: control element information | ||
1846 | * | ||
1847 | * Returns 0 for success. | ||
1848 | */ | ||
1849 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | ||
1850 | struct snd_ctl_elem_value *ucontrol) | ||
1851 | { | ||
1852 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1853 | struct soc_enum *e = | ||
1854 | (struct soc_enum *)kcontrol->private_value; | ||
1855 | int change; | ||
1856 | int ret = 0; | ||
1857 | |||
1858 | if (ucontrol->value.enumerated.item[0] >= e->max) | ||
1859 | return -EINVAL; | ||
1860 | |||
1861 | mutex_lock(&widget->codec->mutex); | ||
1862 | |||
1863 | change = widget->value != ucontrol->value.enumerated.item[0]; | ||
1864 | widget->value = ucontrol->value.enumerated.item[0]; | ||
1865 | dapm_mux_update_power(widget, kcontrol, change, widget->value, e); | ||
1866 | |||
1867 | mutex_unlock(&widget->codec->mutex); | ||
1868 | return ret; | ||
1869 | } | ||
1870 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | ||
1871 | |||
1872 | /** | ||
1797 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | 1873 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get |
1798 | * callback | 1874 | * callback |
1799 | * @kcontrol: mixer control | 1875 | * @kcontrol: mixer control |
@@ -1851,7 +1927,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1851 | { | 1927 | { |
1852 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1928 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1853 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1929 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1854 | unsigned int val, mux; | 1930 | unsigned int val, mux, change; |
1855 | unsigned int mask; | 1931 | unsigned int mask; |
1856 | int ret = 0; | 1932 | int ret = 0; |
1857 | 1933 | ||
@@ -1869,20 +1945,21 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1869 | 1945 | ||
1870 | mutex_lock(&widget->codec->mutex); | 1946 | mutex_lock(&widget->codec->mutex); |
1871 | widget->value = val; | 1947 | widget->value = val; |
1872 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); | 1948 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1873 | if (widget->event) { | 1949 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1874 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1950 | |
1875 | ret = widget->event(widget, | 1951 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1876 | kcontrol, SND_SOC_DAPM_PRE_REG); | 1952 | ret = widget->event(widget, |
1877 | if (ret < 0) | 1953 | kcontrol, SND_SOC_DAPM_PRE_REG); |
1878 | goto out; | 1954 | if (ret < 0) |
1879 | } | 1955 | goto out; |
1880 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1956 | } |
1881 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1957 | |
1882 | ret = widget->event(widget, | 1958 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1883 | kcontrol, SND_SOC_DAPM_POST_REG); | 1959 | |
1884 | } else | 1960 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1885 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1961 | ret = widget->event(widget, |
1962 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1886 | 1963 | ||
1887 | out: | 1964 | out: |
1888 | mutex_unlock(&widget->codec->mutex); | 1965 | mutex_unlock(&widget->codec->mutex); |
@@ -2072,9 +2149,9 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
2072 | } | 2149 | } |
2073 | } | 2150 | } |
2074 | } | 2151 | } |
2075 | mutex_unlock(&codec->mutex); | ||
2076 | 2152 | ||
2077 | dapm_power_widgets(codec, event); | 2153 | dapm_power_widgets(codec, event); |
2154 | mutex_unlock(&codec->mutex); | ||
2078 | dump_dapm(codec, __func__); | 2155 | dump_dapm(codec, __func__); |
2079 | return 0; | 2156 | return 0; |
2080 | } | 2157 | } |