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.c275
1 files changed, 213 insertions, 62 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 32ab7fc4579a..fbfcda062839 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -124,6 +124,51 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
124 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); 124 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
125} 125}
126 126
127static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
128{
129 if (w->codec)
130 return snd_soc_read(w->codec, reg);
131 else if (w->platform)
132 return snd_soc_platform_read(w->platform, reg);
133
134 dev_err(w->dapm->dev, "no valid widget read method\n");
135 return -1;
136}
137
138static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
139{
140 if (w->codec)
141 return snd_soc_write(w->codec, reg, val);
142 else if (w->platform)
143 return snd_soc_platform_write(w->platform, reg, val);
144
145 dev_err(w->dapm->dev, "no valid widget write method\n");
146 return -1;
147}
148
149static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
150 unsigned short reg, unsigned int mask, unsigned int value)
151{
152 int change;
153 unsigned int old, new;
154 int ret;
155
156 ret = soc_widget_read(w, reg);
157 if (ret < 0)
158 return ret;
159
160 old = ret;
161 new = (old & ~mask) | (value & mask);
162 change = old != new;
163 if (change) {
164 ret = soc_widget_write(w, reg, new);
165 if (ret < 0)
166 return ret;
167 }
168
169 return change;
170}
171
127/** 172/**
128 * snd_soc_dapm_set_bias_level - set the bias level for the system 173 * snd_soc_dapm_set_bias_level - set the bias level for the system
129 * @dapm: DAPM context 174 * @dapm: DAPM context
@@ -139,39 +184,26 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
139 struct snd_soc_card *card = dapm->card; 184 struct snd_soc_card *card = dapm->card;
140 int ret = 0; 185 int ret = 0;
141 186
142 switch (level) {
143 case SND_SOC_BIAS_ON:
144 dev_dbg(dapm->dev, "Setting full bias\n");
145 break;
146 case SND_SOC_BIAS_PREPARE:
147 dev_dbg(dapm->dev, "Setting bias prepare\n");
148 break;
149 case SND_SOC_BIAS_STANDBY:
150 dev_dbg(dapm->dev, "Setting standby bias\n");
151 break;
152 case SND_SOC_BIAS_OFF:
153 dev_dbg(dapm->dev, "Setting bias off\n");
154 break;
155 default:
156 dev_err(dapm->dev, "Setting invalid bias %d\n", level);
157 return -EINVAL;
158 }
159
160 trace_snd_soc_bias_level_start(card, level); 187 trace_snd_soc_bias_level_start(card, level);
161 188
162 if (card && card->set_bias_level) 189 if (card && card->set_bias_level)
163 ret = card->set_bias_level(card, level); 190 ret = card->set_bias_level(card, dapm, level);
164 if (ret == 0) { 191 if (ret != 0)
165 if (dapm->codec && dapm->codec->driver->set_bias_level) 192 goto out;
166 ret = dapm->codec->driver->set_bias_level(dapm->codec, level); 193
194 if (dapm->codec) {
195 if (dapm->codec->driver->set_bias_level)
196 ret = dapm->codec->driver->set_bias_level(dapm->codec,
197 level);
167 else 198 else
168 dapm->bias_level = level; 199 dapm->bias_level = level;
169 } 200 }
170 if (ret == 0) { 201 if (ret != 0)
171 if (card && card->set_bias_level_post) 202 goto out;
172 ret = card->set_bias_level_post(card, level);
173 }
174 203
204 if (card && card->set_bias_level_post)
205 ret = card->set_bias_level_post(card, dapm, level);
206out:
175 trace_snd_soc_bias_level_done(card, level); 207 trace_snd_soc_bias_level_done(card, level);
176 208
177 return ret; 209 return ret;
@@ -194,7 +226,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
194 unsigned int mask = (1 << fls(max)) - 1; 226 unsigned int mask = (1 << fls(max)) - 1;
195 unsigned int invert = mc->invert; 227 unsigned int invert = mc->invert;
196 228
197 val = snd_soc_read(w->codec, reg); 229 val = soc_widget_read(w, reg);
198 val = (val >> shift) & mask; 230 val = (val >> shift) & mask;
199 231
200 if ((invert && !val) || (!invert && val)) 232 if ((invert && !val) || (!invert && val))
@@ -209,8 +241,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
209 int val, item, bitmask; 241 int val, item, bitmask;
210 242
211 for (bitmask = 1; bitmask < e->max; bitmask <<= 1) 243 for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
212 ; 244 ;
213 val = snd_soc_read(w->codec, e->reg); 245 val = soc_widget_read(w, e->reg);
214 item = (val >> e->shift_l) & (bitmask - 1); 246 item = (val >> e->shift_l) & (bitmask - 1);
215 247
216 p->connect = 0; 248 p->connect = 0;
@@ -240,7 +272,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
240 w->kcontrol_news[i].private_value; 272 w->kcontrol_news[i].private_value;
241 int val, item; 273 int val, item;
242 274
243 val = snd_soc_read(w->codec, e->reg); 275 val = soc_widget_read(w, e->reg);
244 val = (val >> e->shift_l) & e->mask; 276 val = (val >> e->shift_l) & e->mask;
245 for (item = 0; item < e->max; item++) { 277 for (item = 0; item < e->max; item++) {
246 if (val == e->values[item]) 278 if (val == e->values[item])
@@ -606,6 +638,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
606 } 638 }
607 639
608 list_for_each_entry(path, &widget->sinks, list_source) { 640 list_for_each_entry(path, &widget->sinks, list_source) {
641 if (path->weak)
642 continue;
643
609 if (path->walked) 644 if (path->walked)
610 continue; 645 continue;
611 646
@@ -656,6 +691,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
656 } 691 }
657 692
658 list_for_each_entry(path, &widget->sources, list_sink) { 693 list_for_each_entry(path, &widget->sources, list_sink) {
694 if (path->weak)
695 continue;
696
659 if (path->walked) 697 if (path->walked)
660 continue; 698 continue;
661 699
@@ -681,7 +719,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
681 else 719 else
682 val = w->off_val; 720 val = w->off_val;
683 721
684 snd_soc_update_bits(w->codec, -(w->reg + 1), 722 soc_widget_update_bits(w, -(w->reg + 1),
685 w->mask << w->shift, val << w->shift); 723 w->mask << w->shift, val << w->shift);
686 724
687 return 0; 725 return 0;
@@ -737,6 +775,9 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
737 775
738 /* Check if one of our outputs is connected */ 776 /* Check if one of our outputs is connected */
739 list_for_each_entry(path, &w->sinks, list_source) { 777 list_for_each_entry(path, &w->sinks, list_source) {
778 if (path->weak)
779 continue;
780
740 if (path->connected && 781 if (path->connected &&
741 !path->connected(path->source, path->sink)) 782 !path->connected(path->source, path->sink))
742 continue; 783 continue;
@@ -885,11 +926,17 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
885 } 926 }
886 927
887 if (reg >= 0) { 928 if (reg >= 0) {
929 /* Any widget will do, they should all be updating the
930 * same register.
931 */
932 w = list_first_entry(pending, struct snd_soc_dapm_widget,
933 power_list);
934
888 pop_dbg(dapm->dev, card->pop_time, 935 pop_dbg(dapm->dev, card->pop_time,
889 "pop test : Applying 0x%x/0x%x to %x in %dms\n", 936 "pop test : Applying 0x%x/0x%x to %x in %dms\n",
890 value, mask, reg, card->pop_time); 937 value, mask, reg, card->pop_time);
891 pop_wait(card->pop_time); 938 pop_wait(card->pop_time);
892 snd_soc_update_bits(dapm->codec, reg, mask, value); 939 soc_widget_update_bits(w, reg, mask, value);
893 } 940 }
894 941
895 list_for_each_entry(w, pending, power_list) { 942 list_for_each_entry(w, pending, power_list) {
@@ -942,7 +989,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
942 989
943 INIT_LIST_HEAD(&pending); 990 INIT_LIST_HEAD(&pending);
944 cur_sort = -1; 991 cur_sort = -1;
945 cur_subseq = -1; 992 cur_subseq = INT_MIN;
946 cur_reg = SND_SOC_NOPM; 993 cur_reg = SND_SOC_NOPM;
947 cur_dapm = NULL; 994 cur_dapm = NULL;
948 } 995 }
@@ -1041,16 +1088,17 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
1041 struct snd_soc_dapm_context *d = data; 1088 struct snd_soc_dapm_context *d = data;
1042 int ret; 1089 int ret;
1043 1090
1044 if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) { 1091 /* If we're off and we're not supposed to be go into STANDBY */
1092 if (d->bias_level == SND_SOC_BIAS_OFF &&
1093 d->target_bias_level != SND_SOC_BIAS_OFF) {
1045 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); 1094 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1046 if (ret != 0) 1095 if (ret != 0)
1047 dev_err(d->dev, 1096 dev_err(d->dev,
1048 "Failed to turn on bias: %d\n", ret); 1097 "Failed to turn on bias: %d\n", ret);
1049 } 1098 }
1050 1099
1051 /* If we're changing to all on or all off then prepare */ 1100 /* Prepare for a STADDBY->ON or ON->STANDBY transition */
1052 if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) || 1101 if (d->bias_level != d->target_bias_level) {
1053 (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) {
1054 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); 1102 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
1055 if (ret != 0) 1103 if (ret != 0)
1056 dev_err(d->dev, 1104 dev_err(d->dev,
@@ -1067,7 +1115,9 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1067 int ret; 1115 int ret;
1068 1116
1069 /* If we just powered the last thing off drop to standby bias */ 1117 /* If we just powered the last thing off drop to standby bias */
1070 if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) { 1118 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1119 (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
1120 d->target_bias_level == SND_SOC_BIAS_OFF)) {
1071 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); 1121 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
1072 if (ret != 0) 1122 if (ret != 0)
1073 dev_err(d->dev, "Failed to apply standby bias: %d\n", 1123 dev_err(d->dev, "Failed to apply standby bias: %d\n",
@@ -1075,14 +1125,16 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
1075 } 1125 }
1076 1126
1077 /* If we're in standby and can support bias off then do that */ 1127 /* If we're in standby and can support bias off then do that */
1078 if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) { 1128 if (d->bias_level == SND_SOC_BIAS_STANDBY &&
1129 d->target_bias_level == SND_SOC_BIAS_OFF) {
1079 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); 1130 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
1080 if (ret != 0) 1131 if (ret != 0)
1081 dev_err(d->dev, "Failed to turn off bias: %d\n", ret); 1132 dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
1082 } 1133 }
1083 1134
1084 /* If we just powered up then move to active bias */ 1135 /* If we just powered up then move to active bias */
1085 if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) { 1136 if (d->bias_level == SND_SOC_BIAS_PREPARE &&
1137 d->target_bias_level == SND_SOC_BIAS_ON) {
1086 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); 1138 ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
1087 if (ret != 0) 1139 if (ret != 0)
1088 dev_err(d->dev, "Failed to apply active bias: %d\n", 1140 dev_err(d->dev, "Failed to apply active bias: %d\n",
@@ -1107,13 +1159,19 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1107 LIST_HEAD(up_list); 1159 LIST_HEAD(up_list);
1108 LIST_HEAD(down_list); 1160 LIST_HEAD(down_list);
1109 LIST_HEAD(async_domain); 1161 LIST_HEAD(async_domain);
1162 enum snd_soc_bias_level bias;
1110 int power; 1163 int power;
1111 1164
1112 trace_snd_soc_dapm_start(card); 1165 trace_snd_soc_dapm_start(card);
1113 1166
1114 list_for_each_entry(d, &card->dapm_list, list) 1167 list_for_each_entry(d, &card->dapm_list, list) {
1115 if (d->n_widgets || d->codec == NULL) 1168 if (d->n_widgets || d->codec == NULL) {
1116 d->dev_power = 0; 1169 if (d->idle_bias_off)
1170 d->target_bias_level = SND_SOC_BIAS_OFF;
1171 else
1172 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1173 }
1174 }
1117 1175
1118 /* Check which widgets we need to power and store them in 1176 /* Check which widgets we need to power and store them in
1119 * lists indicating if they should be powered up or down. 1177 * lists indicating if they should be powered up or down.
@@ -1135,8 +1193,27 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1135 power = w->power_check(w); 1193 power = w->power_check(w);
1136 else 1194 else
1137 power = 1; 1195 power = 1;
1138 if (power) 1196
1139 w->dapm->dev_power = 1; 1197 if (power) {
1198 d = w->dapm;
1199
1200 /* Supplies and micbiases only bring
1201 * the context up to STANDBY as unless
1202 * something else is active and
1203 * passing audio they generally don't
1204 * require full power.
1205 */
1206 switch (w->id) {
1207 case snd_soc_dapm_supply:
1208 case snd_soc_dapm_micbias:
1209 if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
1210 d->target_bias_level = SND_SOC_BIAS_STANDBY;
1211 break;
1212 default:
1213 d->target_bias_level = SND_SOC_BIAS_ON;
1214 break;
1215 }
1216 }
1140 1217
1141 if (w->power == power) 1218 if (w->power == power)
1142 continue; 1219 continue;
@@ -1160,24 +1237,19 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1160 switch (event) { 1237 switch (event) {
1161 case SND_SOC_DAPM_STREAM_START: 1238 case SND_SOC_DAPM_STREAM_START:
1162 case SND_SOC_DAPM_STREAM_RESUME: 1239 case SND_SOC_DAPM_STREAM_RESUME:
1163 dapm->dev_power = 1; 1240 dapm->target_bias_level = SND_SOC_BIAS_ON;
1164 break; 1241 break;
1165 case SND_SOC_DAPM_STREAM_STOP: 1242 case SND_SOC_DAPM_STREAM_STOP:
1166 dapm->dev_power = !!dapm->codec->active; 1243 if (dapm->codec->active)
1244 dapm->target_bias_level = SND_SOC_BIAS_ON;
1245 else
1246 dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
1167 break; 1247 break;
1168 case SND_SOC_DAPM_STREAM_SUSPEND: 1248 case SND_SOC_DAPM_STREAM_SUSPEND:
1169 dapm->dev_power = 0; 1249 dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
1170 break; 1250 break;
1171 case SND_SOC_DAPM_STREAM_NOP: 1251 case SND_SOC_DAPM_STREAM_NOP:
1172 switch (dapm->bias_level) { 1252 dapm->target_bias_level = dapm->bias_level;
1173 case SND_SOC_BIAS_STANDBY:
1174 case SND_SOC_BIAS_OFF:
1175 dapm->dev_power = 0;
1176 break;
1177 default:
1178 dapm->dev_power = 1;
1179 break;
1180 }
1181 break; 1253 break;
1182 default: 1254 default:
1183 break; 1255 break;
@@ -1185,12 +1257,12 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1185 } 1257 }
1186 1258
1187 /* Force all contexts in the card to the same bias state */ 1259 /* Force all contexts in the card to the same bias state */
1188 power = 0; 1260 bias = SND_SOC_BIAS_OFF;
1189 list_for_each_entry(d, &card->dapm_list, list) 1261 list_for_each_entry(d, &card->dapm_list, list)
1190 if (d->dev_power) 1262 if (d->target_bias_level > bias)
1191 power = 1; 1263 bias = d->target_bias_level;
1192 list_for_each_entry(d, &card->dapm_list, list) 1264 list_for_each_entry(d, &card->dapm_list, list)
1193 d->dev_power = power; 1265 d->target_bias_level = bias;
1194 1266
1195 1267
1196 /* Run all the bias changes in parallel */ 1268 /* Run all the bias changes in parallel */
@@ -1794,6 +1866,84 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
1794} 1866}
1795EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); 1867EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
1796 1868
1869static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
1870 const struct snd_soc_dapm_route *route)
1871{
1872 struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
1873 route->source,
1874 true);
1875 struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
1876 route->sink,
1877 true);
1878 struct snd_soc_dapm_path *path;
1879 int count = 0;
1880
1881 if (!source) {
1882 dev_err(dapm->dev, "Unable to find source %s for weak route\n",
1883 route->source);
1884 return -ENODEV;
1885 }
1886
1887 if (!sink) {
1888 dev_err(dapm->dev, "Unable to find sink %s for weak route\n",
1889 route->sink);
1890 return -ENODEV;
1891 }
1892
1893 if (route->control || route->connected)
1894 dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n",
1895 route->source, route->sink);
1896
1897 list_for_each_entry(path, &source->sinks, list_source) {
1898 if (path->sink == sink) {
1899 path->weak = 1;
1900 count++;
1901 }
1902 }
1903
1904 if (count == 0)
1905 dev_err(dapm->dev, "No path found for weak route %s->%s\n",
1906 route->source, route->sink);
1907 if (count > 1)
1908 dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n",
1909 count, route->source, route->sink);
1910
1911 return 0;
1912}
1913
1914/**
1915 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
1916 * @dapm: DAPM context
1917 * @route: audio routes
1918 * @num: number of routes
1919 *
1920 * Mark existing routes matching those specified in the passed array
1921 * as being weak, meaning that they are ignored for the purpose of
1922 * power decisions. The main intended use case is for sidetone paths
1923 * which couple audio between other independent paths if they are both
1924 * active in order to make the combination work better at the user
1925 * level but which aren't intended to be "used".
1926 *
1927 * Note that CODEC drivers should not use this as sidetone type paths
1928 * can frequently also be used as bypass paths.
1929 */
1930int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
1931 const struct snd_soc_dapm_route *route, int num)
1932{
1933 int i, err;
1934 int ret = 0;
1935
1936 for (i = 0; i < num; i++) {
1937 err = snd_soc_dapm_weak_route(dapm, route);
1938 if (err)
1939 ret = err;
1940 route++;
1941 }
1942
1943 return ret;
1944}
1945EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
1946
1797/** 1947/**
1798 * snd_soc_dapm_new_widgets - add new dapm widgets 1948 * snd_soc_dapm_new_widgets - add new dapm widgets
1799 * @dapm: DAPM context 1949 * @dapm: DAPM context
@@ -1865,7 +2015,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
1865 2015
1866 /* Read the initial power state from the device */ 2016 /* Read the initial power state from the device */
1867 if (w->reg >= 0) { 2017 if (w->reg >= 0) {
1868 val = snd_soc_read(w->codec, w->reg); 2018 val = soc_widget_read(w, w->reg);
1869 val &= 1 << w->shift; 2019 val &= 1 << w->shift;
1870 if (w->invert) 2020 if (w->invert)
1871 val = !val; 2021 val = !val;
@@ -2353,6 +2503,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
2353 dapm->n_widgets++; 2503 dapm->n_widgets++;
2354 w->dapm = dapm; 2504 w->dapm = dapm;
2355 w->codec = dapm->codec; 2505 w->codec = dapm->codec;
2506 w->platform = dapm->platform;
2356 INIT_LIST_HEAD(&w->sources); 2507 INIT_LIST_HEAD(&w->sources);
2357 INIT_LIST_HEAD(&w->sinks); 2508 INIT_LIST_HEAD(&w->sinks);
2358 INIT_LIST_HEAD(&w->list); 2509 INIT_LIST_HEAD(&w->list);