diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 278 |
1 files changed, 151 insertions, 127 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 66d4c165f99b..7c28f401f436 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -38,19 +38,13 @@ | |||
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/jiffies.h> | 39 | #include <linux/jiffies.h> |
40 | #include <linux/debugfs.h> | 40 | #include <linux/debugfs.h> |
41 | #include <linux/slab.h> | ||
41 | #include <sound/core.h> | 42 | #include <sound/core.h> |
42 | #include <sound/pcm.h> | 43 | #include <sound/pcm.h> |
43 | #include <sound/pcm_params.h> | 44 | #include <sound/pcm_params.h> |
44 | #include <sound/soc-dapm.h> | 45 | #include <sound/soc-dapm.h> |
45 | #include <sound/initval.h> | 46 | #include <sound/initval.h> |
46 | 47 | ||
47 | /* debug */ | ||
48 | #ifdef DEBUG | ||
49 | #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) | ||
50 | #else | ||
51 | #define dump_dapm(codec, action) | ||
52 | #endif | ||
53 | |||
54 | /* dapm power sequences - make this per codec in the future */ | 48 | /* dapm power sequences - make this per codec in the future */ |
55 | static int dapm_up_seq[] = { | 49 | static int dapm_up_seq[] = { |
56 | [snd_soc_dapm_pre] = 0, | 50 | [snd_soc_dapm_pre] = 0, |
@@ -719,6 +713,10 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
719 | 713 | ||
720 | /* Check if one of our outputs is connected */ | 714 | /* Check if one of our outputs is connected */ |
721 | list_for_each_entry(path, &w->sinks, list_source) { | 715 | list_for_each_entry(path, &w->sinks, list_source) { |
716 | if (path->connected && | ||
717 | !path->connected(path->source, path->sink)) | ||
718 | continue; | ||
719 | |||
722 | if (path->sink && path->sink->power_check && | 720 | if (path->sink && path->sink->power_check && |
723 | path->sink->power_check(path->sink)) { | 721 | path->sink->power_check(path->sink)) { |
724 | power = 1; | 722 | power = 1; |
@@ -735,6 +733,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | |||
735 | struct snd_soc_dapm_widget *b, | 733 | struct snd_soc_dapm_widget *b, |
736 | int sort[]) | 734 | int sort[]) |
737 | { | 735 | { |
736 | if (a->codec != b->codec) | ||
737 | return (unsigned long)a - (unsigned long)b; | ||
738 | if (sort[a->id] != sort[b->id]) | 738 | if (sort[a->id] != sort[b->id]) |
739 | return sort[a->id] - sort[b->id]; | 739 | return sort[a->id] - sort[b->id]; |
740 | if (a->reg != b->reg) | 740 | if (a->reg != b->reg) |
@@ -1013,13 +1013,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1013 | sys_power = 0; | 1013 | sys_power = 0; |
1014 | break; | 1014 | break; |
1015 | case SND_SOC_DAPM_STREAM_NOP: | 1015 | case SND_SOC_DAPM_STREAM_NOP: |
1016 | sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; | 1016 | switch (codec->bias_level) { |
1017 | case SND_SOC_BIAS_STANDBY: | ||
1018 | case SND_SOC_BIAS_OFF: | ||
1019 | sys_power = 0; | ||
1020 | break; | ||
1021 | default: | ||
1022 | sys_power = 1; | ||
1023 | break; | ||
1024 | } | ||
1017 | break; | 1025 | break; |
1018 | default: | 1026 | default: |
1019 | break; | 1027 | break; |
1020 | } | 1028 | } |
1021 | } | 1029 | } |
1022 | 1030 | ||
1031 | if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1032 | ret = snd_soc_dapm_set_bias_level(socdev, | ||
1033 | SND_SOC_BIAS_STANDBY); | ||
1034 | if (ret != 0) | ||
1035 | pr_err("Failed to turn on bias: %d\n", ret); | ||
1036 | } | ||
1037 | |||
1023 | /* If we're changing to all on or all off then prepare */ | 1038 | /* If we're changing to all on or all off then prepare */ |
1024 | if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || | 1039 | if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || |
1025 | (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { | 1040 | (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { |
@@ -1043,6 +1058,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1043 | pr_err("Failed to apply standby bias: %d\n", ret); | 1058 | pr_err("Failed to apply standby bias: %d\n", ret); |
1044 | } | 1059 | } |
1045 | 1060 | ||
1061 | /* If we're in standby and can support bias off then do that */ | ||
1062 | if (codec->bias_level == SND_SOC_BIAS_STANDBY && | ||
1063 | codec->idle_bias_off) { | ||
1064 | ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); | ||
1065 | if (ret != 0) | ||
1066 | pr_err("Failed to turn off bias: %d\n", ret); | ||
1067 | } | ||
1068 | |||
1046 | /* If we just powered up then move to active bias */ | 1069 | /* If we just powered up then move to active bias */ |
1047 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { | 1070 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { |
1048 | ret = snd_soc_dapm_set_bias_level(socdev, | 1071 | ret = snd_soc_dapm_set_bias_level(socdev, |
@@ -1057,66 +1080,6 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1057 | return 0; | 1080 | return 0; |
1058 | } | 1081 | } |
1059 | 1082 | ||
1060 | #ifdef DEBUG | ||
1061 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | ||
1062 | { | ||
1063 | struct snd_soc_dapm_widget *w; | ||
1064 | struct snd_soc_dapm_path *p = NULL; | ||
1065 | int in, out; | ||
1066 | |||
1067 | printk("DAPM %s %s\n", codec->name, action); | ||
1068 | |||
1069 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
1070 | |||
1071 | /* only display widgets that effect routing */ | ||
1072 | switch (w->id) { | ||
1073 | case snd_soc_dapm_pre: | ||
1074 | case snd_soc_dapm_post: | ||
1075 | case snd_soc_dapm_vmid: | ||
1076 | continue; | ||
1077 | case snd_soc_dapm_mux: | ||
1078 | case snd_soc_dapm_value_mux: | ||
1079 | case snd_soc_dapm_output: | ||
1080 | case snd_soc_dapm_input: | ||
1081 | case snd_soc_dapm_switch: | ||
1082 | case snd_soc_dapm_hp: | ||
1083 | case snd_soc_dapm_mic: | ||
1084 | case snd_soc_dapm_spk: | ||
1085 | case snd_soc_dapm_line: | ||
1086 | case snd_soc_dapm_micbias: | ||
1087 | case snd_soc_dapm_dac: | ||
1088 | case snd_soc_dapm_adc: | ||
1089 | case snd_soc_dapm_pga: | ||
1090 | case snd_soc_dapm_mixer: | ||
1091 | case snd_soc_dapm_mixer_named_ctl: | ||
1092 | case snd_soc_dapm_supply: | ||
1093 | case snd_soc_dapm_aif_in: | ||
1094 | case snd_soc_dapm_aif_out: | ||
1095 | if (w->name) { | ||
1096 | in = is_connected_input_ep(w); | ||
1097 | dapm_clear_walk(w->codec); | ||
1098 | out = is_connected_output_ep(w); | ||
1099 | dapm_clear_walk(w->codec); | ||
1100 | printk("%s: %s in %d out %d\n", w->name, | ||
1101 | w->power ? "On":"Off",in, out); | ||
1102 | |||
1103 | list_for_each_entry(p, &w->sources, list_sink) { | ||
1104 | if (p->connect) | ||
1105 | printk(" in %s %s\n", p->name ? p->name : "static", | ||
1106 | p->source->name); | ||
1107 | } | ||
1108 | list_for_each_entry(p, &w->sinks, list_source) { | ||
1109 | if (p->connect) | ||
1110 | printk(" out %s %s\n", p->name ? p->name : "static", | ||
1111 | p->sink->name); | ||
1112 | } | ||
1113 | } | ||
1114 | break; | ||
1115 | } | ||
1116 | } | ||
1117 | } | ||
1118 | #endif | ||
1119 | |||
1120 | #ifdef CONFIG_DEBUG_FS | 1083 | #ifdef CONFIG_DEBUG_FS |
1121 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) | 1084 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) |
1122 | { | 1085 | { |
@@ -1143,15 +1106,25 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1143 | out = is_connected_output_ep(w); | 1106 | out = is_connected_output_ep(w); |
1144 | dapm_clear_walk(w->codec); | 1107 | dapm_clear_walk(w->codec); |
1145 | 1108 | ||
1146 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n", | 1109 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", |
1147 | w->name, w->power ? "On" : "Off", in, out); | 1110 | w->name, w->power ? "On" : "Off", in, out); |
1148 | 1111 | ||
1112 | if (w->reg >= 0) | ||
1113 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | ||
1114 | " - R%d(0x%x) bit %d", | ||
1115 | w->reg, w->reg, w->shift); | ||
1116 | |||
1117 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); | ||
1118 | |||
1149 | if (w->sname) | 1119 | if (w->sname) |
1150 | ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", | 1120 | ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", |
1151 | w->sname, | 1121 | w->sname, |
1152 | w->active ? "active" : "inactive"); | 1122 | w->active ? "active" : "inactive"); |
1153 | 1123 | ||
1154 | list_for_each_entry(p, &w->sources, list_sink) { | 1124 | list_for_each_entry(p, &w->sources, list_sink) { |
1125 | if (p->connected && !p->connected(w, p->sink)) | ||
1126 | continue; | ||
1127 | |||
1155 | if (p->connect) | 1128 | if (p->connect) |
1156 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1129 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1157 | " in %s %s\n", | 1130 | " in %s %s\n", |
@@ -1159,6 +1132,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1159 | p->source->name); | 1132 | p->source->name); |
1160 | } | 1133 | } |
1161 | list_for_each_entry(p, &w->sinks, list_source) { | 1134 | list_for_each_entry(p, &w->sinks, list_source) { |
1135 | if (p->connected && !p->connected(w, p->sink)) | ||
1136 | continue; | ||
1137 | |||
1162 | if (p->connect) | 1138 | if (p->connect) |
1163 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1139 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1164 | " out %s %s\n", | 1140 | " out %s %s\n", |
@@ -1206,8 +1182,8 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) | |||
1206 | 1182 | ||
1207 | /* test and update the power status of a mux widget */ | 1183 | /* test and update the power status of a mux widget */ |
1208 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 1184 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
1209 | struct snd_kcontrol *kcontrol, int mask, | 1185 | struct snd_kcontrol *kcontrol, int change, |
1210 | int mux, int val, struct soc_enum *e) | 1186 | int mux, struct soc_enum *e) |
1211 | { | 1187 | { |
1212 | struct snd_soc_dapm_path *path; | 1188 | struct snd_soc_dapm_path *path; |
1213 | int found = 0; | 1189 | int found = 0; |
@@ -1216,7 +1192,7 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1216 | widget->id != snd_soc_dapm_value_mux) | 1192 | widget->id != snd_soc_dapm_value_mux) |
1217 | return -ENODEV; | 1193 | return -ENODEV; |
1218 | 1194 | ||
1219 | if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) | 1195 | if (!change) |
1220 | return 0; | 1196 | return 0; |
1221 | 1197 | ||
1222 | /* find dapm widget path assoc with kcontrol */ | 1198 | /* find dapm widget path assoc with kcontrol */ |
@@ -1235,18 +1211,15 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1235 | path->connect = 0; /* old connection must be powered down */ | 1211 | path->connect = 0; /* old connection must be powered down */ |
1236 | } | 1212 | } |
1237 | 1213 | ||
1238 | if (found) { | 1214 | if (found) |
1239 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1215 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
1240 | dump_dapm(widget->codec, "mux power update"); | ||
1241 | } | ||
1242 | 1216 | ||
1243 | return 0; | 1217 | return 0; |
1244 | } | 1218 | } |
1245 | 1219 | ||
1246 | /* test and update the power status of a mixer or switch widget */ | 1220 | /* test and update the power status of a mixer or switch widget */ |
1247 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 1221 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
1248 | struct snd_kcontrol *kcontrol, int reg, | 1222 | struct snd_kcontrol *kcontrol, int connect) |
1249 | int val_mask, int val, int invert) | ||
1250 | { | 1223 | { |
1251 | struct snd_soc_dapm_path *path; | 1224 | struct snd_soc_dapm_path *path; |
1252 | int found = 0; | 1225 | int found = 0; |
@@ -1256,9 +1229,6 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1256 | widget->id != snd_soc_dapm_switch) | 1229 | widget->id != snd_soc_dapm_switch) |
1257 | return -ENODEV; | 1230 | return -ENODEV; |
1258 | 1231 | ||
1259 | if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) | ||
1260 | return 0; | ||
1261 | |||
1262 | /* find dapm widget path assoc with kcontrol */ | 1232 | /* find dapm widget path assoc with kcontrol */ |
1263 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | 1233 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { |
1264 | if (path->kcontrol != kcontrol) | 1234 | if (path->kcontrol != kcontrol) |
@@ -1266,19 +1236,12 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1266 | 1236 | ||
1267 | /* found, now check type */ | 1237 | /* found, now check type */ |
1268 | found = 1; | 1238 | found = 1; |
1269 | if (val) | 1239 | path->connect = connect; |
1270 | /* new connection */ | ||
1271 | path->connect = invert ? 0:1; | ||
1272 | else | ||
1273 | /* old connection must be powered down */ | ||
1274 | path->connect = invert ? 1:0; | ||
1275 | break; | 1240 | break; |
1276 | } | 1241 | } |
1277 | 1242 | ||
1278 | if (found) { | 1243 | if (found) |
1279 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1244 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
1280 | dump_dapm(widget->codec, "mixer power update"); | ||
1281 | } | ||
1282 | 1245 | ||
1283 | return 0; | 1246 | return 0; |
1284 | } | 1247 | } |
@@ -1394,17 +1357,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | |||
1394 | */ | 1357 | */ |
1395 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) | 1358 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) |
1396 | { | 1359 | { |
1397 | int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 1360 | return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); |
1398 | dump_dapm(codec, "sync"); | ||
1399 | return ret; | ||
1400 | } | 1361 | } |
1401 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 1362 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1402 | 1363 | ||
1403 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | 1364 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, |
1404 | const char *sink, const char *control, const char *source) | 1365 | const struct snd_soc_dapm_route *route) |
1405 | { | 1366 | { |
1406 | struct snd_soc_dapm_path *path; | 1367 | struct snd_soc_dapm_path *path; |
1407 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 1368 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
1369 | const char *sink = route->sink; | ||
1370 | const char *control = route->control; | ||
1371 | const char *source = route->source; | ||
1408 | int ret = 0; | 1372 | int ret = 0; |
1409 | 1373 | ||
1410 | /* find src and dest widgets */ | 1374 | /* find src and dest widgets */ |
@@ -1428,6 +1392,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1428 | 1392 | ||
1429 | path->source = wsource; | 1393 | path->source = wsource; |
1430 | path->sink = wsink; | 1394 | path->sink = wsink; |
1395 | path->connected = route->connected; | ||
1431 | INIT_LIST_HEAD(&path->list); | 1396 | INIT_LIST_HEAD(&path->list); |
1432 | INIT_LIST_HEAD(&path->list_source); | 1397 | INIT_LIST_HEAD(&path->list_source); |
1433 | INIT_LIST_HEAD(&path->list_sink); | 1398 | INIT_LIST_HEAD(&path->list_sink); |
@@ -1528,8 +1493,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | |||
1528 | int i, ret; | 1493 | int i, ret; |
1529 | 1494 | ||
1530 | for (i = 0; i < num; i++) { | 1495 | for (i = 0; i < num; i++) { |
1531 | ret = snd_soc_dapm_add_route(codec, route->sink, | 1496 | ret = snd_soc_dapm_add_route(codec, route); |
1532 | route->control, route->source); | ||
1533 | if (ret < 0) { | 1497 | if (ret < 0) { |
1534 | printk(KERN_ERR "Failed to add route %s->%s\n", | 1498 | printk(KERN_ERR "Failed to add route %s->%s\n", |
1535 | route->source, | 1499 | route->source, |
@@ -1675,6 +1639,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1675 | unsigned int mask = (1 << fls(max)) - 1; | 1639 | unsigned int mask = (1 << fls(max)) - 1; |
1676 | unsigned int invert = mc->invert; | 1640 | unsigned int invert = mc->invert; |
1677 | unsigned int val, val2, val_mask; | 1641 | unsigned int val, val2, val_mask; |
1642 | int connect; | ||
1678 | int ret; | 1643 | int ret; |
1679 | 1644 | ||
1680 | val = (ucontrol->value.integer.value[0] & mask); | 1645 | val = (ucontrol->value.integer.value[0] & mask); |
@@ -1701,7 +1666,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1701 | return 1; | 1666 | return 1; |
1702 | } | 1667 | } |
1703 | 1668 | ||
1704 | dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); | 1669 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { |
1670 | if (val) | ||
1671 | /* new connection */ | ||
1672 | connect = invert ? 0:1; | ||
1673 | else | ||
1674 | /* old connection must be powered down */ | ||
1675 | connect = invert ? 1:0; | ||
1676 | |||
1677 | dapm_mixer_update_power(widget, kcontrol, connect); | ||
1678 | } | ||
1679 | |||
1705 | if (widget->event) { | 1680 | if (widget->event) { |
1706 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1681 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1707 | ret = widget->event(widget, kcontrol, | 1682 | ret = widget->event(widget, kcontrol, |
@@ -1766,7 +1741,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1766 | { | 1741 | { |
1767 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1742 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1768 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1743 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1769 | unsigned int val, mux; | 1744 | unsigned int val, mux, change; |
1770 | unsigned int mask, bitmask; | 1745 | unsigned int mask, bitmask; |
1771 | int ret = 0; | 1746 | int ret = 0; |
1772 | 1747 | ||
@@ -1786,20 +1761,21 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1786 | 1761 | ||
1787 | mutex_lock(&widget->codec->mutex); | 1762 | mutex_lock(&widget->codec->mutex); |
1788 | widget->value = val; | 1763 | widget->value = val; |
1789 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); | 1764 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1790 | if (widget->event) { | 1765 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1791 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1766 | |
1792 | ret = widget->event(widget, | 1767 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1793 | kcontrol, SND_SOC_DAPM_PRE_REG); | 1768 | ret = widget->event(widget, |
1794 | if (ret < 0) | 1769 | kcontrol, SND_SOC_DAPM_PRE_REG); |
1795 | goto out; | 1770 | if (ret < 0) |
1796 | } | 1771 | goto out; |
1797 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1772 | } |
1798 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1773 | |
1799 | ret = widget->event(widget, | 1774 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1800 | kcontrol, SND_SOC_DAPM_POST_REG); | 1775 | |
1801 | } else | 1776 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1802 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1777 | ret = widget->event(widget, |
1778 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1803 | 1779 | ||
1804 | out: | 1780 | out: |
1805 | mutex_unlock(&widget->codec->mutex); | 1781 | mutex_unlock(&widget->codec->mutex); |
@@ -1808,6 +1784,54 @@ out: | |||
1808 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 1784 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
1809 | 1785 | ||
1810 | /** | 1786 | /** |
1787 | * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux | ||
1788 | * @kcontrol: mixer control | ||
1789 | * @ucontrol: control element information | ||
1790 | * | ||
1791 | * Returns 0 for success. | ||
1792 | */ | ||
1793 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | ||
1794 | struct snd_ctl_elem_value *ucontrol) | ||
1795 | { | ||
1796 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1797 | |||
1798 | ucontrol->value.enumerated.item[0] = widget->value; | ||
1799 | |||
1800 | return 0; | ||
1801 | } | ||
1802 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | ||
1803 | |||
1804 | /** | ||
1805 | * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux | ||
1806 | * @kcontrol: mixer control | ||
1807 | * @ucontrol: control element information | ||
1808 | * | ||
1809 | * Returns 0 for success. | ||
1810 | */ | ||
1811 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | ||
1812 | struct snd_ctl_elem_value *ucontrol) | ||
1813 | { | ||
1814 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1815 | struct soc_enum *e = | ||
1816 | (struct soc_enum *)kcontrol->private_value; | ||
1817 | int change; | ||
1818 | int ret = 0; | ||
1819 | |||
1820 | if (ucontrol->value.enumerated.item[0] >= e->max) | ||
1821 | return -EINVAL; | ||
1822 | |||
1823 | mutex_lock(&widget->codec->mutex); | ||
1824 | |||
1825 | change = widget->value != ucontrol->value.enumerated.item[0]; | ||
1826 | widget->value = ucontrol->value.enumerated.item[0]; | ||
1827 | dapm_mux_update_power(widget, kcontrol, change, widget->value, e); | ||
1828 | |||
1829 | mutex_unlock(&widget->codec->mutex); | ||
1830 | return ret; | ||
1831 | } | ||
1832 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | ||
1833 | |||
1834 | /** | ||
1811 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | 1835 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get |
1812 | * callback | 1836 | * callback |
1813 | * @kcontrol: mixer control | 1837 | * @kcontrol: mixer control |
@@ -1865,7 +1889,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1865 | { | 1889 | { |
1866 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | 1890 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); |
1867 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1891 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1868 | unsigned int val, mux; | 1892 | unsigned int val, mux, change; |
1869 | unsigned int mask; | 1893 | unsigned int mask; |
1870 | int ret = 0; | 1894 | int ret = 0; |
1871 | 1895 | ||
@@ -1883,20 +1907,21 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1883 | 1907 | ||
1884 | mutex_lock(&widget->codec->mutex); | 1908 | mutex_lock(&widget->codec->mutex); |
1885 | widget->value = val; | 1909 | widget->value = val; |
1886 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); | 1910 | change = snd_soc_test_bits(widget->codec, e->reg, mask, val); |
1887 | if (widget->event) { | 1911 | dapm_mux_update_power(widget, kcontrol, change, mux, e); |
1888 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1912 | |
1889 | ret = widget->event(widget, | 1913 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1890 | kcontrol, SND_SOC_DAPM_PRE_REG); | 1914 | ret = widget->event(widget, |
1891 | if (ret < 0) | 1915 | kcontrol, SND_SOC_DAPM_PRE_REG); |
1892 | goto out; | 1916 | if (ret < 0) |
1893 | } | 1917 | goto out; |
1894 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1918 | } |
1895 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | 1919 | |
1896 | ret = widget->event(widget, | 1920 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); |
1897 | kcontrol, SND_SOC_DAPM_POST_REG); | 1921 | |
1898 | } else | 1922 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) |
1899 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | 1923 | ret = widget->event(widget, |
1924 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1900 | 1925 | ||
1901 | out: | 1926 | out: |
1902 | mutex_unlock(&widget->codec->mutex); | 1927 | mutex_unlock(&widget->codec->mutex); |
@@ -2089,7 +2114,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
2089 | 2114 | ||
2090 | dapm_power_widgets(codec, event); | 2115 | dapm_power_widgets(codec, event); |
2091 | mutex_unlock(&codec->mutex); | 2116 | mutex_unlock(&codec->mutex); |
2092 | dump_dapm(codec, __func__); | ||
2093 | return 0; | 2117 | return 0; |
2094 | } | 2118 | } |
2095 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | 2119 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); |