diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 142 |
1 files changed, 51 insertions, 91 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 0d294ef72590..6c3351095786 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -44,13 +44,6 @@ | |||
44 | #include <sound/soc-dapm.h> | 44 | #include <sound/soc-dapm.h> |
45 | #include <sound/initval.h> | 45 | #include <sound/initval.h> |
46 | 46 | ||
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 */ | 47 | /* dapm power sequences - make this per codec in the future */ |
55 | static int dapm_up_seq[] = { | 48 | static int dapm_up_seq[] = { |
56 | [snd_soc_dapm_pre] = 0, | 49 | [snd_soc_dapm_pre] = 0, |
@@ -739,6 +732,8 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | |||
739 | struct snd_soc_dapm_widget *b, | 732 | struct snd_soc_dapm_widget *b, |
740 | int sort[]) | 733 | int sort[]) |
741 | { | 734 | { |
735 | if (a->codec != b->codec) | ||
736 | return (unsigned long)a - (unsigned long)b; | ||
742 | if (sort[a->id] != sort[b->id]) | 737 | if (sort[a->id] != sort[b->id]) |
743 | return sort[a->id] - sort[b->id]; | 738 | return sort[a->id] - sort[b->id]; |
744 | if (a->reg != b->reg) | 739 | if (a->reg != b->reg) |
@@ -1017,13 +1012,28 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1017 | sys_power = 0; | 1012 | sys_power = 0; |
1018 | break; | 1013 | break; |
1019 | case SND_SOC_DAPM_STREAM_NOP: | 1014 | case SND_SOC_DAPM_STREAM_NOP: |
1020 | sys_power = codec->bias_level != SND_SOC_BIAS_STANDBY; | 1015 | switch (codec->bias_level) { |
1016 | case SND_SOC_BIAS_STANDBY: | ||
1017 | case SND_SOC_BIAS_OFF: | ||
1018 | sys_power = 0; | ||
1019 | break; | ||
1020 | default: | ||
1021 | sys_power = 1; | ||
1022 | break; | ||
1023 | } | ||
1021 | break; | 1024 | break; |
1022 | default: | 1025 | default: |
1023 | break; | 1026 | break; |
1024 | } | 1027 | } |
1025 | } | 1028 | } |
1026 | 1029 | ||
1030 | if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) { | ||
1031 | ret = snd_soc_dapm_set_bias_level(socdev, | ||
1032 | SND_SOC_BIAS_STANDBY); | ||
1033 | if (ret != 0) | ||
1034 | pr_err("Failed to turn on bias: %d\n", ret); | ||
1035 | } | ||
1036 | |||
1027 | /* If we're changing to all on or all off then prepare */ | 1037 | /* If we're changing to all on or all off then prepare */ |
1028 | if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || | 1038 | if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) || |
1029 | (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { | 1039 | (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) { |
@@ -1047,6 +1057,14 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1047 | pr_err("Failed to apply standby bias: %d\n", ret); | 1057 | pr_err("Failed to apply standby bias: %d\n", ret); |
1048 | } | 1058 | } |
1049 | 1059 | ||
1060 | /* If we're in standby and can support bias off then do that */ | ||
1061 | if (codec->bias_level == SND_SOC_BIAS_STANDBY && | ||
1062 | codec->idle_bias_off) { | ||
1063 | ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF); | ||
1064 | if (ret != 0) | ||
1065 | pr_err("Failed to turn off bias: %d\n", ret); | ||
1066 | } | ||
1067 | |||
1050 | /* If we just powered up then move to active bias */ | 1068 | /* If we just powered up then move to active bias */ |
1051 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { | 1069 | if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) { |
1052 | ret = snd_soc_dapm_set_bias_level(socdev, | 1070 | ret = snd_soc_dapm_set_bias_level(socdev, |
@@ -1061,66 +1079,6 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event) | |||
1061 | return 0; | 1079 | return 0; |
1062 | } | 1080 | } |
1063 | 1081 | ||
1064 | #ifdef DEBUG | ||
1065 | static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | ||
1066 | { | ||
1067 | struct snd_soc_dapm_widget *w; | ||
1068 | struct snd_soc_dapm_path *p = NULL; | ||
1069 | int in, out; | ||
1070 | |||
1071 | printk("DAPM %s %s\n", codec->name, action); | ||
1072 | |||
1073 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
1074 | |||
1075 | /* only display widgets that effect routing */ | ||
1076 | switch (w->id) { | ||
1077 | case snd_soc_dapm_pre: | ||
1078 | case snd_soc_dapm_post: | ||
1079 | case snd_soc_dapm_vmid: | ||
1080 | continue; | ||
1081 | case snd_soc_dapm_mux: | ||
1082 | case snd_soc_dapm_value_mux: | ||
1083 | case snd_soc_dapm_output: | ||
1084 | case snd_soc_dapm_input: | ||
1085 | case snd_soc_dapm_switch: | ||
1086 | case snd_soc_dapm_hp: | ||
1087 | case snd_soc_dapm_mic: | ||
1088 | case snd_soc_dapm_spk: | ||
1089 | case snd_soc_dapm_line: | ||
1090 | case snd_soc_dapm_micbias: | ||
1091 | case snd_soc_dapm_dac: | ||
1092 | case snd_soc_dapm_adc: | ||
1093 | case snd_soc_dapm_pga: | ||
1094 | case snd_soc_dapm_mixer: | ||
1095 | case snd_soc_dapm_mixer_named_ctl: | ||
1096 | case snd_soc_dapm_supply: | ||
1097 | case snd_soc_dapm_aif_in: | ||
1098 | case snd_soc_dapm_aif_out: | ||
1099 | if (w->name) { | ||
1100 | in = is_connected_input_ep(w); | ||
1101 | dapm_clear_walk(w->codec); | ||
1102 | out = is_connected_output_ep(w); | ||
1103 | dapm_clear_walk(w->codec); | ||
1104 | printk("%s: %s in %d out %d\n", w->name, | ||
1105 | w->power ? "On":"Off",in, out); | ||
1106 | |||
1107 | list_for_each_entry(p, &w->sources, list_sink) { | ||
1108 | if (p->connect) | ||
1109 | printk(" in %s %s\n", p->name ? p->name : "static", | ||
1110 | p->source->name); | ||
1111 | } | ||
1112 | list_for_each_entry(p, &w->sinks, list_source) { | ||
1113 | if (p->connect) | ||
1114 | printk(" out %s %s\n", p->name ? p->name : "static", | ||
1115 | p->sink->name); | ||
1116 | } | ||
1117 | } | ||
1118 | break; | ||
1119 | } | ||
1120 | } | ||
1121 | } | ||
1122 | #endif | ||
1123 | |||
1124 | #ifdef CONFIG_DEBUG_FS | 1082 | #ifdef CONFIG_DEBUG_FS |
1125 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) | 1083 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) |
1126 | { | 1084 | { |
@@ -1147,9 +1105,16 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1147 | out = is_connected_output_ep(w); | 1105 | out = is_connected_output_ep(w); |
1148 | dapm_clear_walk(w->codec); | 1106 | dapm_clear_walk(w->codec); |
1149 | 1107 | ||
1150 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n", | 1108 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", |
1151 | w->name, w->power ? "On" : "Off", in, out); | 1109 | w->name, w->power ? "On" : "Off", in, out); |
1152 | 1110 | ||
1111 | if (w->reg >= 0) | ||
1112 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | ||
1113 | " - R%d(0x%x) bit %d", | ||
1114 | w->reg, w->reg, w->shift); | ||
1115 | |||
1116 | ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); | ||
1117 | |||
1153 | if (w->sname) | 1118 | if (w->sname) |
1154 | ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", | 1119 | ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", |
1155 | w->sname, | 1120 | w->sname, |
@@ -1245,18 +1210,15 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1245 | path->connect = 0; /* old connection must be powered down */ | 1210 | path->connect = 0; /* old connection must be powered down */ |
1246 | } | 1211 | } |
1247 | 1212 | ||
1248 | if (found) { | 1213 | if (found) |
1249 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1214 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
1250 | dump_dapm(widget->codec, "mux power update"); | ||
1251 | } | ||
1252 | 1215 | ||
1253 | return 0; | 1216 | return 0; |
1254 | } | 1217 | } |
1255 | 1218 | ||
1256 | /* test and update the power status of a mixer or switch widget */ | 1219 | /* test and update the power status of a mixer or switch widget */ |
1257 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 1220 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
1258 | struct snd_kcontrol *kcontrol, int reg, | 1221 | struct snd_kcontrol *kcontrol, int connect) |
1259 | int val_mask, int val, int invert) | ||
1260 | { | 1222 | { |
1261 | struct snd_soc_dapm_path *path; | 1223 | struct snd_soc_dapm_path *path; |
1262 | int found = 0; | 1224 | int found = 0; |
@@ -1266,9 +1228,6 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1266 | widget->id != snd_soc_dapm_switch) | 1228 | widget->id != snd_soc_dapm_switch) |
1267 | return -ENODEV; | 1229 | return -ENODEV; |
1268 | 1230 | ||
1269 | if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) | ||
1270 | return 0; | ||
1271 | |||
1272 | /* find dapm widget path assoc with kcontrol */ | 1231 | /* find dapm widget path assoc with kcontrol */ |
1273 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { | 1232 | list_for_each_entry(path, &widget->codec->dapm_paths, list) { |
1274 | if (path->kcontrol != kcontrol) | 1233 | if (path->kcontrol != kcontrol) |
@@ -1276,19 +1235,12 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1276 | 1235 | ||
1277 | /* found, now check type */ | 1236 | /* found, now check type */ |
1278 | found = 1; | 1237 | found = 1; |
1279 | if (val) | 1238 | path->connect = connect; |
1280 | /* new connection */ | ||
1281 | path->connect = invert ? 0:1; | ||
1282 | else | ||
1283 | /* old connection must be powered down */ | ||
1284 | path->connect = invert ? 1:0; | ||
1285 | break; | 1239 | break; |
1286 | } | 1240 | } |
1287 | 1241 | ||
1288 | if (found) { | 1242 | if (found) |
1289 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); | 1243 | dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); |
1290 | dump_dapm(widget->codec, "mixer power update"); | ||
1291 | } | ||
1292 | 1244 | ||
1293 | return 0; | 1245 | return 0; |
1294 | } | 1246 | } |
@@ -1404,9 +1356,7 @@ static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, | |||
1404 | */ | 1356 | */ |
1405 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) | 1357 | int snd_soc_dapm_sync(struct snd_soc_codec *codec) |
1406 | { | 1358 | { |
1407 | int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); | 1359 | return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); |
1408 | dump_dapm(codec, "sync"); | ||
1409 | return ret; | ||
1410 | } | 1360 | } |
1411 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 1361 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1412 | 1362 | ||
@@ -1688,6 +1638,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1688 | unsigned int mask = (1 << fls(max)) - 1; | 1638 | unsigned int mask = (1 << fls(max)) - 1; |
1689 | unsigned int invert = mc->invert; | 1639 | unsigned int invert = mc->invert; |
1690 | unsigned int val, val2, val_mask; | 1640 | unsigned int val, val2, val_mask; |
1641 | int connect; | ||
1691 | int ret; | 1642 | int ret; |
1692 | 1643 | ||
1693 | val = (ucontrol->value.integer.value[0] & mask); | 1644 | val = (ucontrol->value.integer.value[0] & mask); |
@@ -1714,7 +1665,17 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
1714 | return 1; | 1665 | return 1; |
1715 | } | 1666 | } |
1716 | 1667 | ||
1717 | dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); | 1668 | if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { |
1669 | if (val) | ||
1670 | /* new connection */ | ||
1671 | connect = invert ? 0:1; | ||
1672 | else | ||
1673 | /* old connection must be powered down */ | ||
1674 | connect = invert ? 1:0; | ||
1675 | |||
1676 | dapm_mixer_update_power(widget, kcontrol, connect); | ||
1677 | } | ||
1678 | |||
1718 | if (widget->event) { | 1679 | if (widget->event) { |
1719 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | 1680 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { |
1720 | ret = widget->event(widget, kcontrol, | 1681 | ret = widget->event(widget, kcontrol, |
@@ -2152,7 +2113,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, | |||
2152 | 2113 | ||
2153 | dapm_power_widgets(codec, event); | 2114 | dapm_power_widgets(codec, event); |
2154 | mutex_unlock(&codec->mutex); | 2115 | mutex_unlock(&codec->mutex); |
2155 | dump_dapm(codec, __func__); | ||
2156 | return 0; | 2116 | return 0; |
2157 | } | 2117 | } |
2158 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | 2118 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); |