diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 140 |
1 files changed, 131 insertions, 9 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8863eddbac02..a2f1da8b4646 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -53,13 +53,15 @@ | |||
53 | /* dapm power sequences - make this per codec in the future */ | 53 | /* dapm power sequences - make this per codec in the future */ |
54 | static int dapm_up_seq[] = { | 54 | static int dapm_up_seq[] = { |
55 | snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, | 55 | snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, |
56 | snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga, | 56 | snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac, |
57 | snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post | 57 | snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, |
58 | snd_soc_dapm_spk, snd_soc_dapm_post | ||
58 | }; | 59 | }; |
59 | static int dapm_down_seq[] = { | 60 | static int dapm_down_seq[] = { |
60 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, | 61 | snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, |
61 | snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, | 62 | snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, |
62 | snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post | 63 | snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux, |
64 | snd_soc_dapm_post | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | static int dapm_status = 1; | 67 | static int dapm_status = 1; |
@@ -134,6 +136,25 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
134 | } | 136 | } |
135 | } | 137 | } |
136 | break; | 138 | break; |
139 | case snd_soc_dapm_value_mux: { | ||
140 | struct soc_enum *e = (struct soc_enum *) | ||
141 | w->kcontrols[i].private_value; | ||
142 | int val, item; | ||
143 | |||
144 | val = snd_soc_read(w->codec, e->reg); | ||
145 | val = (val >> e->shift_l) & e->mask; | ||
146 | for (item = 0; item < e->max; item++) { | ||
147 | if (val == e->values[item]) | ||
148 | break; | ||
149 | } | ||
150 | |||
151 | p->connect = 0; | ||
152 | for (i = 0; i < e->max; i++) { | ||
153 | if (!(strcmp(p->name, e->texts[i])) && item == i) | ||
154 | p->connect = 1; | ||
155 | } | ||
156 | } | ||
157 | break; | ||
137 | /* does not effect routing - always connected */ | 158 | /* does not effect routing - always connected */ |
138 | case snd_soc_dapm_pga: | 159 | case snd_soc_dapm_pga: |
139 | case snd_soc_dapm_output: | 160 | case snd_soc_dapm_output: |
@@ -653,6 +674,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | |||
653 | case snd_soc_dapm_vmid: | 674 | case snd_soc_dapm_vmid: |
654 | continue; | 675 | continue; |
655 | case snd_soc_dapm_mux: | 676 | case snd_soc_dapm_mux: |
677 | case snd_soc_dapm_value_mux: | ||
656 | case snd_soc_dapm_output: | 678 | case snd_soc_dapm_output: |
657 | case snd_soc_dapm_input: | 679 | case snd_soc_dapm_input: |
658 | case snd_soc_dapm_switch: | 680 | case snd_soc_dapm_switch: |
@@ -698,7 +720,8 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
698 | struct snd_soc_dapm_path *path; | 720 | struct snd_soc_dapm_path *path; |
699 | int found = 0; | 721 | int found = 0; |
700 | 722 | ||
701 | if (widget->id != snd_soc_dapm_mux) | 723 | if (widget->id != snd_soc_dapm_mux && |
724 | widget->id != snd_soc_dapm_value_mux) | ||
702 | return -ENODEV; | 725 | return -ENODEV; |
703 | 726 | ||
704 | if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) | 727 | if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) |
@@ -960,6 +983,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
960 | path->connect = 1; | 983 | path->connect = 1; |
961 | return 0; | 984 | return 0; |
962 | case snd_soc_dapm_mux: | 985 | case snd_soc_dapm_mux: |
986 | case snd_soc_dapm_value_mux: | ||
963 | ret = dapm_connect_mux(codec, wsource, wsink, path, control, | 987 | ret = dapm_connect_mux(codec, wsource, wsink, path, control, |
964 | &wsink->kcontrols[0]); | 988 | &wsink->kcontrols[0]); |
965 | if (ret != 0) | 989 | if (ret != 0) |
@@ -1047,6 +1071,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
1047 | dapm_new_mixer(codec, w); | 1071 | dapm_new_mixer(codec, w); |
1048 | break; | 1072 | break; |
1049 | case snd_soc_dapm_mux: | 1073 | case snd_soc_dapm_mux: |
1074 | case snd_soc_dapm_value_mux: | ||
1050 | dapm_new_mux(codec, w); | 1075 | dapm_new_mux(codec, w); |
1051 | break; | 1076 | break; |
1052 | case snd_soc_dapm_adc: | 1077 | case snd_soc_dapm_adc: |
@@ -1077,7 +1102,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); | |||
1077 | /** | 1102 | /** |
1078 | * snd_soc_dapm_get_volsw - dapm mixer get callback | 1103 | * snd_soc_dapm_get_volsw - dapm mixer get callback |
1079 | * @kcontrol: mixer control | 1104 | * @kcontrol: mixer control |
1080 | * @uinfo: control element information | 1105 | * @ucontrol: control element information |
1081 | * | 1106 | * |
1082 | * Callback to get the value of a dapm mixer control. | 1107 | * Callback to get the value of a dapm mixer control. |
1083 | * | 1108 | * |
@@ -1122,7 +1147,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); | |||
1122 | /** | 1147 | /** |
1123 | * snd_soc_dapm_put_volsw - dapm mixer set callback | 1148 | * snd_soc_dapm_put_volsw - dapm mixer set callback |
1124 | * @kcontrol: mixer control | 1149 | * @kcontrol: mixer control |
1125 | * @uinfo: control element information | 1150 | * @ucontrol: control element information |
1126 | * | 1151 | * |
1127 | * Callback to set the value of a dapm mixer control. | 1152 | * Callback to set the value of a dapm mixer control. |
1128 | * | 1153 | * |
@@ -1193,7 +1218,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); | |||
1193 | /** | 1218 | /** |
1194 | * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback | 1219 | * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback |
1195 | * @kcontrol: mixer control | 1220 | * @kcontrol: mixer control |
1196 | * @uinfo: control element information | 1221 | * @ucontrol: control element information |
1197 | * | 1222 | * |
1198 | * Callback to get the value of a dapm enumerated double mixer control. | 1223 | * Callback to get the value of a dapm enumerated double mixer control. |
1199 | * | 1224 | * |
@@ -1221,7 +1246,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | |||
1221 | /** | 1246 | /** |
1222 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback | 1247 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback |
1223 | * @kcontrol: mixer control | 1248 | * @kcontrol: mixer control |
1224 | * @uinfo: control element information | 1249 | * @ucontrol: control element information |
1225 | * | 1250 | * |
1226 | * Callback to set the value of a dapm enumerated double mixer control. | 1251 | * Callback to set the value of a dapm enumerated double mixer control. |
1227 | * | 1252 | * |
@@ -1274,6 +1299,103 @@ out: | |||
1274 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | 1299 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
1275 | 1300 | ||
1276 | /** | 1301 | /** |
1302 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | ||
1303 | * callback | ||
1304 | * @kcontrol: mixer control | ||
1305 | * @ucontrol: control element information | ||
1306 | * | ||
1307 | * Callback to get the value of a dapm semi enumerated double mixer control. | ||
1308 | * | ||
1309 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
1310 | * used for handling bitfield coded enumeration for example. | ||
1311 | * | ||
1312 | * Returns 0 for success. | ||
1313 | */ | ||
1314 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
1315 | struct snd_ctl_elem_value *ucontrol) | ||
1316 | { | ||
1317 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1318 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1319 | unsigned short reg_val, val, mux; | ||
1320 | |||
1321 | reg_val = snd_soc_read(widget->codec, e->reg); | ||
1322 | val = (reg_val >> e->shift_l) & e->mask; | ||
1323 | for (mux = 0; mux < e->max; mux++) { | ||
1324 | if (val == e->values[mux]) | ||
1325 | break; | ||
1326 | } | ||
1327 | ucontrol->value.enumerated.item[0] = mux; | ||
1328 | if (e->shift_l != e->shift_r) { | ||
1329 | val = (reg_val >> e->shift_r) & e->mask; | ||
1330 | for (mux = 0; mux < e->max; mux++) { | ||
1331 | if (val == e->values[mux]) | ||
1332 | break; | ||
1333 | } | ||
1334 | ucontrol->value.enumerated.item[1] = mux; | ||
1335 | } | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | ||
1340 | |||
1341 | /** | ||
1342 | * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set | ||
1343 | * callback | ||
1344 | * @kcontrol: mixer control | ||
1345 | * @ucontrol: control element information | ||
1346 | * | ||
1347 | * Callback to set the value of a dapm semi enumerated double mixer control. | ||
1348 | * | ||
1349 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
1350 | * used for handling bitfield coded enumeration for example. | ||
1351 | * | ||
1352 | * Returns 0 for success. | ||
1353 | */ | ||
1354 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
1355 | struct snd_ctl_elem_value *ucontrol) | ||
1356 | { | ||
1357 | struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); | ||
1358 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
1359 | unsigned short val, mux; | ||
1360 | unsigned short mask; | ||
1361 | int ret = 0; | ||
1362 | |||
1363 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | ||
1364 | return -EINVAL; | ||
1365 | mux = ucontrol->value.enumerated.item[0]; | ||
1366 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | ||
1367 | mask = e->mask << e->shift_l; | ||
1368 | if (e->shift_l != e->shift_r) { | ||
1369 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
1370 | return -EINVAL; | ||
1371 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | ||
1372 | mask |= e->mask << e->shift_r; | ||
1373 | } | ||
1374 | |||
1375 | mutex_lock(&widget->codec->mutex); | ||
1376 | widget->value = val; | ||
1377 | dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); | ||
1378 | if (widget->event) { | ||
1379 | if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { | ||
1380 | ret = widget->event(widget, | ||
1381 | kcontrol, SND_SOC_DAPM_PRE_REG); | ||
1382 | if (ret < 0) | ||
1383 | goto out; | ||
1384 | } | ||
1385 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | ||
1386 | if (widget->event_flags & SND_SOC_DAPM_POST_REG) | ||
1387 | ret = widget->event(widget, | ||
1388 | kcontrol, SND_SOC_DAPM_POST_REG); | ||
1389 | } else | ||
1390 | ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); | ||
1391 | |||
1392 | out: | ||
1393 | mutex_unlock(&widget->codec->mutex); | ||
1394 | return ret; | ||
1395 | } | ||
1396 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | ||
1397 | |||
1398 | /** | ||
1277 | * snd_soc_dapm_new_control - create new dapm control | 1399 | * snd_soc_dapm_new_control - create new dapm control |
1278 | * @codec: audio codec | 1400 | * @codec: audio codec |
1279 | * @widget: widget template | 1401 | * @widget: widget template |
@@ -1419,7 +1541,7 @@ int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, | |||
1419 | 1541 | ||
1420 | /** | 1542 | /** |
1421 | * snd_soc_dapm_enable_pin - enable pin. | 1543 | * snd_soc_dapm_enable_pin - enable pin. |
1422 | * @snd_soc_codec: SoC codec | 1544 | * @codec: SoC codec |
1423 | * @pin: pin name | 1545 | * @pin: pin name |
1424 | * | 1546 | * |
1425 | * Enables input/output pin and it's parents or children widgets iff there is | 1547 | * Enables input/output pin and it's parents or children widgets iff there is |