diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 275 |
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 | ||
127 | static 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 | |||
138 | static 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 | |||
149 | static 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); | ||
206 | out: | ||
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 | } |
1795 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); | 1867 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); |
1796 | 1868 | ||
1869 | static 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 | */ | ||
1930 | int 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 | } | ||
1945 | EXPORT_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); |