aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c142
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 */
55static int dapm_up_seq[] = { 48static 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
1065static 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
1125static int dapm_widget_power_open_file(struct inode *inode, struct file *file) 1083static 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 */
1257static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 1220static 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 */
1405int snd_soc_dapm_sync(struct snd_soc_codec *codec) 1357int 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}
1411EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); 1361EXPORT_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}
2158EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); 2118EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);