diff options
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 400 |
1 files changed, 285 insertions, 115 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1315663c1c09..6241490fff30 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -14,19 +14,13 @@ | |||
14 | * dynamic configuration of codec internal audio paths and active | 14 | * dynamic configuration of codec internal audio paths and active |
15 | * DACs/ADCs. | 15 | * DACs/ADCs. |
16 | * o Platform power domain - can support external components i.e. amps and | 16 | * o Platform power domain - can support external components i.e. amps and |
17 | * mic/meadphone insertion events. | 17 | * mic/headphone insertion events. |
18 | * o Automatic Mic Bias support | 18 | * o Automatic Mic Bias support |
19 | * o Jack insertion power event initiation - e.g. hp insertion will enable | 19 | * o Jack insertion power event initiation - e.g. hp insertion will enable |
20 | * sinks, dacs, etc | 20 | * sinks, dacs, etc |
21 | * o Delayed powerdown of audio susbsystem to reduce pops between a quick | 21 | * o Delayed power down of audio subsystem to reduce pops between a quick |
22 | * device reopen. | 22 | * device reopen. |
23 | * | 23 | * |
24 | * Todo: | ||
25 | * o DAPM power change sequencing - allow for configurable per | ||
26 | * codec sequences. | ||
27 | * o Support for analogue bias optimisation. | ||
28 | * o Support for reduced codec oversampling rates. | ||
29 | * o Support for reduced codec bias currents. | ||
30 | */ | 24 | */ |
31 | 25 | ||
32 | #include <linux/module.h> | 26 | #include <linux/module.h> |
@@ -40,6 +34,7 @@ | |||
40 | #include <linux/jiffies.h> | 34 | #include <linux/jiffies.h> |
41 | #include <linux/debugfs.h> | 35 | #include <linux/debugfs.h> |
42 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
37 | #include <linux/regulator/consumer.h> | ||
43 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
44 | #include <sound/core.h> | 39 | #include <sound/core.h> |
45 | #include <sound/pcm.h> | 40 | #include <sound/pcm.h> |
@@ -55,7 +50,9 @@ | |||
55 | static int dapm_up_seq[] = { | 50 | static int dapm_up_seq[] = { |
56 | [snd_soc_dapm_pre] = 0, | 51 | [snd_soc_dapm_pre] = 0, |
57 | [snd_soc_dapm_supply] = 1, | 52 | [snd_soc_dapm_supply] = 1, |
53 | [snd_soc_dapm_regulator_supply] = 1, | ||
58 | [snd_soc_dapm_micbias] = 2, | 54 | [snd_soc_dapm_micbias] = 2, |
55 | [snd_soc_dapm_dai] = 3, | ||
59 | [snd_soc_dapm_aif_in] = 3, | 56 | [snd_soc_dapm_aif_in] = 3, |
60 | [snd_soc_dapm_aif_out] = 3, | 57 | [snd_soc_dapm_aif_out] = 3, |
61 | [snd_soc_dapm_mic] = 4, | 58 | [snd_soc_dapm_mic] = 4, |
@@ -90,6 +87,8 @@ static int dapm_down_seq[] = { | |||
90 | [snd_soc_dapm_value_mux] = 9, | 87 | [snd_soc_dapm_value_mux] = 9, |
91 | [snd_soc_dapm_aif_in] = 10, | 88 | [snd_soc_dapm_aif_in] = 10, |
92 | [snd_soc_dapm_aif_out] = 10, | 89 | [snd_soc_dapm_aif_out] = 10, |
90 | [snd_soc_dapm_dai] = 10, | ||
91 | [snd_soc_dapm_regulator_supply] = 11, | ||
93 | [snd_soc_dapm_supply] = 11, | 92 | [snd_soc_dapm_supply] = 11, |
94 | [snd_soc_dapm_post] = 12, | 93 | [snd_soc_dapm_post] = 12, |
95 | }; | 94 | }; |
@@ -172,6 +171,19 @@ static inline struct snd_soc_card *dapm_get_soc_card( | |||
172 | return NULL; | 171 | return NULL; |
173 | } | 172 | } |
174 | 173 | ||
174 | static void dapm_reset(struct snd_soc_card *card) | ||
175 | { | ||
176 | struct snd_soc_dapm_widget *w; | ||
177 | |||
178 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | ||
179 | |||
180 | list_for_each_entry(w, &card->widgets, list) { | ||
181 | w->power_checked = false; | ||
182 | w->inputs = -1; | ||
183 | w->outputs = -1; | ||
184 | } | ||
185 | } | ||
186 | |||
175 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) | 187 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) |
176 | { | 188 | { |
177 | if (w->codec) | 189 | if (w->codec) |
@@ -197,21 +209,28 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) | |||
197 | static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, | 209 | static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, |
198 | unsigned short reg, unsigned int mask, unsigned int value) | 210 | unsigned short reg, unsigned int mask, unsigned int value) |
199 | { | 211 | { |
200 | int change; | 212 | bool change; |
201 | unsigned int old, new; | 213 | unsigned int old, new; |
202 | int ret; | 214 | int ret; |
203 | 215 | ||
204 | ret = soc_widget_read(w, reg); | 216 | if (w->codec && w->codec->using_regmap) { |
205 | if (ret < 0) | 217 | ret = regmap_update_bits_check(w->codec->control_data, |
206 | return ret; | 218 | reg, mask, value, &change); |
207 | 219 | if (ret != 0) | |
208 | old = ret; | 220 | return ret; |
209 | new = (old & ~mask) | (value & mask); | 221 | } else { |
210 | change = old != new; | 222 | ret = soc_widget_read(w, reg); |
211 | if (change) { | ||
212 | ret = soc_widget_write(w, reg, new); | ||
213 | if (ret < 0) | 223 | if (ret < 0) |
214 | return ret; | 224 | return ret; |
225 | |||
226 | old = ret; | ||
227 | new = (old & ~mask) | (value & mask); | ||
228 | change = old != new; | ||
229 | if (change) { | ||
230 | ret = soc_widget_write(w, reg, new); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | } | ||
215 | } | 234 | } |
216 | 235 | ||
217 | return change; | 236 | return change; |
@@ -345,8 +364,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
345 | case snd_soc_dapm_micbias: | 364 | case snd_soc_dapm_micbias: |
346 | case snd_soc_dapm_vmid: | 365 | case snd_soc_dapm_vmid: |
347 | case snd_soc_dapm_supply: | 366 | case snd_soc_dapm_supply: |
367 | case snd_soc_dapm_regulator_supply: | ||
348 | case snd_soc_dapm_aif_in: | 368 | case snd_soc_dapm_aif_in: |
349 | case snd_soc_dapm_aif_out: | 369 | case snd_soc_dapm_aif_out: |
370 | case snd_soc_dapm_dai: | ||
350 | case snd_soc_dapm_hp: | 371 | case snd_soc_dapm_hp: |
351 | case snd_soc_dapm_mic: | 372 | case snd_soc_dapm_mic: |
352 | case snd_soc_dapm_spk: | 373 | case snd_soc_dapm_spk: |
@@ -504,17 +525,17 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) | |||
504 | * for widgets so cut the prefix off | 525 | * for widgets so cut the prefix off |
505 | * the front of the widget name. | 526 | * the front of the widget name. |
506 | */ | 527 | */ |
507 | snprintf(path->long_name, name_len, "%s %s", | 528 | snprintf((char *)path->long_name, name_len, |
508 | w->name + prefix_len, | 529 | "%s %s", w->name + prefix_len, |
509 | w->kcontrol_news[i].name); | 530 | w->kcontrol_news[i].name); |
510 | break; | 531 | break; |
511 | case snd_soc_dapm_mixer_named_ctl: | 532 | case snd_soc_dapm_mixer_named_ctl: |
512 | snprintf(path->long_name, name_len, "%s", | 533 | snprintf((char *)path->long_name, name_len, |
513 | w->kcontrol_news[i].name); | 534 | "%s", w->kcontrol_news[i].name); |
514 | break; | 535 | break; |
515 | } | 536 | } |
516 | 537 | ||
517 | path->long_name[name_len - 1] = '\0'; | 538 | ((char *)path->long_name)[name_len - 1] = '\0'; |
518 | 539 | ||
519 | path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], | 540 | path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], |
520 | wlist, path->long_name, | 541 | wlist, path->long_name, |
@@ -548,7 +569,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
548 | struct snd_soc_dapm_widget_list *wlist; | 569 | struct snd_soc_dapm_widget_list *wlist; |
549 | int shared, wlistentries; | 570 | int shared, wlistentries; |
550 | size_t wlistsize; | 571 | size_t wlistsize; |
551 | char *name; | 572 | const char *name; |
552 | 573 | ||
553 | if (w->num_kcontrols != 1) { | 574 | if (w->num_kcontrols != 1) { |
554 | dev_err(dapm->dev, | 575 | dev_err(dapm->dev, |
@@ -673,12 +694,18 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) | |||
673 | 694 | ||
674 | DAPM_UPDATE_STAT(widget, path_checks); | 695 | DAPM_UPDATE_STAT(widget, path_checks); |
675 | 696 | ||
676 | if (widget->id == snd_soc_dapm_supply) | 697 | switch (widget->id) { |
698 | case snd_soc_dapm_supply: | ||
699 | case snd_soc_dapm_regulator_supply: | ||
677 | return 0; | 700 | return 0; |
701 | default: | ||
702 | break; | ||
703 | } | ||
678 | 704 | ||
679 | switch (widget->id) { | 705 | switch (widget->id) { |
680 | case snd_soc_dapm_adc: | 706 | case snd_soc_dapm_adc: |
681 | case snd_soc_dapm_aif_out: | 707 | case snd_soc_dapm_aif_out: |
708 | case snd_soc_dapm_dai: | ||
682 | if (widget->active) { | 709 | if (widget->active) { |
683 | widget->outputs = snd_soc_dapm_suspend_check(widget); | 710 | widget->outputs = snd_soc_dapm_suspend_check(widget); |
684 | return widget->outputs; | 711 | return widget->outputs; |
@@ -738,13 +765,19 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | |||
738 | 765 | ||
739 | DAPM_UPDATE_STAT(widget, path_checks); | 766 | DAPM_UPDATE_STAT(widget, path_checks); |
740 | 767 | ||
741 | if (widget->id == snd_soc_dapm_supply) | 768 | switch (widget->id) { |
769 | case snd_soc_dapm_supply: | ||
770 | case snd_soc_dapm_regulator_supply: | ||
742 | return 0; | 771 | return 0; |
772 | default: | ||
773 | break; | ||
774 | } | ||
743 | 775 | ||
744 | /* active stream ? */ | 776 | /* active stream ? */ |
745 | switch (widget->id) { | 777 | switch (widget->id) { |
746 | case snd_soc_dapm_dac: | 778 | case snd_soc_dapm_dac: |
747 | case snd_soc_dapm_aif_in: | 779 | case snd_soc_dapm_aif_in: |
780 | case snd_soc_dapm_dai: | ||
748 | if (widget->active) { | 781 | if (widget->active) { |
749 | widget->inputs = snd_soc_dapm_suspend_check(widget); | 782 | widget->inputs = snd_soc_dapm_suspend_check(widget); |
750 | return widget->inputs; | 783 | return widget->inputs; |
@@ -821,6 +854,19 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, | |||
821 | } | 854 | } |
822 | EXPORT_SYMBOL_GPL(dapm_reg_event); | 855 | EXPORT_SYMBOL_GPL(dapm_reg_event); |
823 | 856 | ||
857 | /* | ||
858 | * Handler for regulator supply widget. | ||
859 | */ | ||
860 | int dapm_regulator_event(struct snd_soc_dapm_widget *w, | ||
861 | struct snd_kcontrol *kcontrol, int event) | ||
862 | { | ||
863 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
864 | return regulator_enable(w->priv); | ||
865 | else | ||
866 | return regulator_disable_deferred(w->priv, w->shift); | ||
867 | } | ||
868 | EXPORT_SYMBOL_GPL(dapm_regulator_event); | ||
869 | |||
824 | static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) | 870 | static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) |
825 | { | 871 | { |
826 | if (w->power_checked) | 872 | if (w->power_checked) |
@@ -851,6 +897,13 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | |||
851 | return out != 0 && in != 0; | 897 | return out != 0 && in != 0; |
852 | } | 898 | } |
853 | 899 | ||
900 | static int dapm_dai_check_power(struct snd_soc_dapm_widget *w) | ||
901 | { | ||
902 | DAPM_UPDATE_STAT(w, power_checks); | ||
903 | |||
904 | return w->active; | ||
905 | } | ||
906 | |||
854 | /* Check to see if an ADC has power */ | 907 | /* Check to see if an ADC has power */ |
855 | static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) | 908 | static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) |
856 | { | 909 | { |
@@ -1251,7 +1304,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) | |||
1251 | dev_err(d->dev, "Failed to turn off bias: %d\n", ret); | 1304 | dev_err(d->dev, "Failed to turn off bias: %d\n", ret); |
1252 | 1305 | ||
1253 | if (d->dev) | 1306 | if (d->dev) |
1254 | pm_runtime_put_sync(d->dev); | 1307 | pm_runtime_put(d->dev); |
1255 | } | 1308 | } |
1256 | 1309 | ||
1257 | /* If we just powered up then move to active bias */ | 1310 | /* If we just powered up then move to active bias */ |
@@ -1301,6 +1354,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1301 | } | 1354 | } |
1302 | switch (w->id) { | 1355 | switch (w->id) { |
1303 | case snd_soc_dapm_supply: | 1356 | case snd_soc_dapm_supply: |
1357 | case snd_soc_dapm_regulator_supply: | ||
1304 | /* Supplies can't affect their outputs, only their inputs */ | 1358 | /* Supplies can't affect their outputs, only their inputs */ |
1305 | break; | 1359 | break; |
1306 | default: | 1360 | default: |
@@ -1373,13 +1427,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1373 | } | 1427 | } |
1374 | } | 1428 | } |
1375 | 1429 | ||
1376 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | 1430 | dapm_reset(card); |
1377 | |||
1378 | list_for_each_entry(w, &card->widgets, list) { | ||
1379 | w->power_checked = false; | ||
1380 | w->inputs = -1; | ||
1381 | w->outputs = -1; | ||
1382 | } | ||
1383 | 1431 | ||
1384 | /* Check which widgets we need to power and store them in | 1432 | /* Check which widgets we need to power and store them in |
1385 | * lists indicating if they should be powered up or down. We | 1433 | * lists indicating if they should be powered up or down. We |
@@ -1400,10 +1448,15 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1400 | /* Supplies and micbiases only bring the | 1448 | /* Supplies and micbiases only bring the |
1401 | * context up to STANDBY as unless something | 1449 | * context up to STANDBY as unless something |
1402 | * else is active and passing audio they | 1450 | * else is active and passing audio they |
1403 | * generally don't require full power. | 1451 | * generally don't require full power. Signal |
1452 | * generators are virtual pins and have no | ||
1453 | * power impact themselves. | ||
1404 | */ | 1454 | */ |
1405 | switch (w->id) { | 1455 | switch (w->id) { |
1456 | case snd_soc_dapm_siggen: | ||
1457 | break; | ||
1406 | case snd_soc_dapm_supply: | 1458 | case snd_soc_dapm_supply: |
1459 | case snd_soc_dapm_regulator_supply: | ||
1407 | case snd_soc_dapm_micbias: | 1460 | case snd_soc_dapm_micbias: |
1408 | if (d->target_bias_level < SND_SOC_BIAS_STANDBY) | 1461 | if (d->target_bias_level < SND_SOC_BIAS_STANDBY) |
1409 | d->target_bias_level = SND_SOC_BIAS_STANDBY; | 1462 | d->target_bias_level = SND_SOC_BIAS_STANDBY; |
@@ -1475,6 +1528,12 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1475 | &async_domain); | 1528 | &async_domain); |
1476 | async_synchronize_full_domain(&async_domain); | 1529 | async_synchronize_full_domain(&async_domain); |
1477 | 1530 | ||
1531 | /* do we need to notify any clients that DAPM event is complete */ | ||
1532 | list_for_each_entry(d, &card->dapm_list, list) { | ||
1533 | if (d->stream_event) | ||
1534 | d->stream_event(d, event); | ||
1535 | } | ||
1536 | |||
1478 | pop_dbg(dapm->dev, card->pop_time, | 1537 | pop_dbg(dapm->dev, card->pop_time, |
1479 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); | 1538 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
1480 | pop_wait(card->pop_time); | 1539 | pop_wait(card->pop_time); |
@@ -1510,8 +1569,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1510 | out = is_connected_output_ep(w); | 1569 | out = is_connected_output_ep(w); |
1511 | dapm_clear_walk(w->dapm); | 1570 | dapm_clear_walk(w->dapm); |
1512 | 1571 | ||
1513 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", | 1572 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", |
1514 | w->name, w->power ? "On" : "Off", in, out); | 1573 | w->name, w->power ? "On" : "Off", |
1574 | w->force ? " (forced)" : "", in, out); | ||
1515 | 1575 | ||
1516 | if (w->reg >= 0) | 1576 | if (w->reg >= 0) |
1517 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1577 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
@@ -1607,7 +1667,7 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, | |||
1607 | dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); | 1667 | dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); |
1608 | 1668 | ||
1609 | if (!dapm->debugfs_dapm) { | 1669 | if (!dapm->debugfs_dapm) { |
1610 | printk(KERN_WARNING | 1670 | dev_warn(dapm->dev, |
1611 | "Failed to create DAPM debugfs directory\n"); | 1671 | "Failed to create DAPM debugfs directory\n"); |
1612 | return; | 1672 | return; |
1613 | } | 1673 | } |
@@ -1659,9 +1719,8 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
1659 | #endif | 1719 | #endif |
1660 | 1720 | ||
1661 | /* test and update the power status of a mux widget */ | 1721 | /* test and update the power status of a mux widget */ |
1662 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 1722 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
1663 | struct snd_kcontrol *kcontrol, int change, | 1723 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
1664 | int mux, struct soc_enum *e) | ||
1665 | { | 1724 | { |
1666 | struct snd_soc_dapm_path *path; | 1725 | struct snd_soc_dapm_path *path; |
1667 | int found = 0; | 1726 | int found = 0; |
@@ -1671,9 +1730,6 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1671 | widget->id != snd_soc_dapm_value_mux) | 1730 | widget->id != snd_soc_dapm_value_mux) |
1672 | return -ENODEV; | 1731 | return -ENODEV; |
1673 | 1732 | ||
1674 | if (!change) | ||
1675 | return 0; | ||
1676 | |||
1677 | /* find dapm widget path assoc with kcontrol */ | 1733 | /* find dapm widget path assoc with kcontrol */ |
1678 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 1734 | list_for_each_entry(path, &widget->dapm->card->paths, list) { |
1679 | if (path->kcontrol != kcontrol) | 1735 | if (path->kcontrol != kcontrol) |
@@ -1702,9 +1758,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1702 | 1758 | ||
1703 | return 0; | 1759 | return 0; |
1704 | } | 1760 | } |
1761 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); | ||
1705 | 1762 | ||
1706 | /* test and update the power status of a mixer or switch widget */ | 1763 | /* test and update the power status of a mixer or switch widget */ |
1707 | static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | 1764 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
1708 | struct snd_kcontrol *kcontrol, int connect) | 1765 | struct snd_kcontrol *kcontrol, int connect) |
1709 | { | 1766 | { |
1710 | struct snd_soc_dapm_path *path; | 1767 | struct snd_soc_dapm_path *path; |
@@ -1733,6 +1790,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1733 | 1790 | ||
1734 | return 0; | 1791 | return 0; |
1735 | } | 1792 | } |
1793 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | ||
1736 | 1794 | ||
1737 | /* show dapm widget status in sys fs */ | 1795 | /* show dapm widget status in sys fs */ |
1738 | static ssize_t dapm_widget_show(struct device *dev, | 1796 | static ssize_t dapm_widget_show(struct device *dev, |
@@ -1762,6 +1820,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
1762 | case snd_soc_dapm_mixer: | 1820 | case snd_soc_dapm_mixer: |
1763 | case snd_soc_dapm_mixer_named_ctl: | 1821 | case snd_soc_dapm_mixer_named_ctl: |
1764 | case snd_soc_dapm_supply: | 1822 | case snd_soc_dapm_supply: |
1823 | case snd_soc_dapm_regulator_supply: | ||
1765 | if (w->name) | 1824 | if (w->name) |
1766 | count += sprintf(buf + count, "%s: %s\n", | 1825 | count += sprintf(buf + count, "%s: %s\n", |
1767 | w->name, w->power ? "On":"Off"); | 1826 | w->name, w->power ? "On":"Off"); |
@@ -1869,10 +1928,12 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
1869 | return -EINVAL; | 1928 | return -EINVAL; |
1870 | } | 1929 | } |
1871 | 1930 | ||
1931 | if (w->connected != status) | ||
1932 | dapm_mark_dirty(w, "pin configuration"); | ||
1933 | |||
1872 | w->connected = status; | 1934 | w->connected = status; |
1873 | if (status == 0) | 1935 | if (status == 0) |
1874 | w->force = 0; | 1936 | w->force = 0; |
1875 | dapm_mark_dirty(w, "pin configuration"); | ||
1876 | 1937 | ||
1877 | return 0; | 1938 | return 0; |
1878 | } | 1939 | } |
@@ -2000,8 +2061,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2000 | case snd_soc_dapm_pre: | 2061 | case snd_soc_dapm_pre: |
2001 | case snd_soc_dapm_post: | 2062 | case snd_soc_dapm_post: |
2002 | case snd_soc_dapm_supply: | 2063 | case snd_soc_dapm_supply: |
2064 | case snd_soc_dapm_regulator_supply: | ||
2003 | case snd_soc_dapm_aif_in: | 2065 | case snd_soc_dapm_aif_in: |
2004 | case snd_soc_dapm_aif_out: | 2066 | case snd_soc_dapm_aif_out: |
2067 | case snd_soc_dapm_dai: | ||
2005 | list_add(&path->list, &dapm->card->paths); | 2068 | list_add(&path->list, &dapm->card->paths); |
2006 | list_add(&path->list_sink, &wsink->sources); | 2069 | list_add(&path->list_sink, &wsink->sources); |
2007 | list_add(&path->list_source, &wsource->sinks); | 2070 | list_add(&path->list_source, &wsource->sinks); |
@@ -2315,7 +2378,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2315 | update.val = val; | 2378 | update.val = val; |
2316 | widget->dapm->update = &update; | 2379 | widget->dapm->update = &update; |
2317 | 2380 | ||
2318 | dapm_mixer_update_power(widget, kcontrol, connect); | 2381 | snd_soc_dapm_mixer_update_power(widget, kcontrol, connect); |
2319 | 2382 | ||
2320 | widget->dapm->update = NULL; | 2383 | widget->dapm->update = NULL; |
2321 | } | 2384 | } |
@@ -2406,7 +2469,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2406 | update.val = val; | 2469 | update.val = val; |
2407 | widget->dapm->update = &update; | 2470 | widget->dapm->update = &update; |
2408 | 2471 | ||
2409 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2472 | snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); |
2410 | 2473 | ||
2411 | widget->dapm->update = NULL; | 2474 | widget->dapm->update = NULL; |
2412 | } | 2475 | } |
@@ -2467,8 +2530,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | |||
2467 | 2530 | ||
2468 | widget->value = ucontrol->value.enumerated.item[0]; | 2531 | widget->value = ucontrol->value.enumerated.item[0]; |
2469 | 2532 | ||
2470 | dapm_mux_update_power(widget, kcontrol, change, | 2533 | snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); |
2471 | widget->value, e); | ||
2472 | } | 2534 | } |
2473 | } | 2535 | } |
2474 | 2536 | ||
@@ -2571,7 +2633,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2571 | update.val = val; | 2633 | update.val = val; |
2572 | widget->dapm->update = &update; | 2634 | widget->dapm->update = &update; |
2573 | 2635 | ||
2574 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2636 | snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); |
2575 | 2637 | ||
2576 | widget->dapm->update = NULL; | 2638 | widget->dapm->update = NULL; |
2577 | } | 2639 | } |
@@ -2611,15 +2673,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch); | |||
2611 | int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, | 2673 | int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, |
2612 | struct snd_ctl_elem_value *ucontrol) | 2674 | struct snd_ctl_elem_value *ucontrol) |
2613 | { | 2675 | { |
2614 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2676 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
2615 | const char *pin = (const char *)kcontrol->private_value; | 2677 | const char *pin = (const char *)kcontrol->private_value; |
2616 | 2678 | ||
2617 | mutex_lock(&codec->mutex); | 2679 | mutex_lock(&card->mutex); |
2618 | 2680 | ||
2619 | ucontrol->value.integer.value[0] = | 2681 | ucontrol->value.integer.value[0] = |
2620 | snd_soc_dapm_get_pin_status(&codec->dapm, pin); | 2682 | snd_soc_dapm_get_pin_status(&card->dapm, pin); |
2621 | 2683 | ||
2622 | mutex_unlock(&codec->mutex); | 2684 | mutex_unlock(&card->mutex); |
2623 | 2685 | ||
2624 | return 0; | 2686 | return 0; |
2625 | } | 2687 | } |
@@ -2634,41 +2696,48 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch); | |||
2634 | int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | 2696 | int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, |
2635 | struct snd_ctl_elem_value *ucontrol) | 2697 | struct snd_ctl_elem_value *ucontrol) |
2636 | { | 2698 | { |
2637 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2699 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
2638 | const char *pin = (const char *)kcontrol->private_value; | 2700 | const char *pin = (const char *)kcontrol->private_value; |
2639 | 2701 | ||
2640 | mutex_lock(&codec->mutex); | 2702 | mutex_lock(&card->mutex); |
2641 | 2703 | ||
2642 | if (ucontrol->value.integer.value[0]) | 2704 | if (ucontrol->value.integer.value[0]) |
2643 | snd_soc_dapm_enable_pin(&codec->dapm, pin); | 2705 | snd_soc_dapm_enable_pin(&card->dapm, pin); |
2644 | else | 2706 | else |
2645 | snd_soc_dapm_disable_pin(&codec->dapm, pin); | 2707 | snd_soc_dapm_disable_pin(&card->dapm, pin); |
2646 | 2708 | ||
2647 | snd_soc_dapm_sync(&codec->dapm); | 2709 | snd_soc_dapm_sync(&card->dapm); |
2648 | 2710 | ||
2649 | mutex_unlock(&codec->mutex); | 2711 | mutex_unlock(&card->mutex); |
2650 | 2712 | ||
2651 | return 0; | 2713 | return 0; |
2652 | } | 2714 | } |
2653 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); | 2715 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); |
2654 | 2716 | ||
2655 | /** | 2717 | static struct snd_soc_dapm_widget * |
2656 | * snd_soc_dapm_new_control - create new dapm control | 2718 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
2657 | * @dapm: DAPM context | 2719 | const struct snd_soc_dapm_widget *widget) |
2658 | * @widget: widget template | ||
2659 | * | ||
2660 | * Creates a new dapm control based upon the template. | ||
2661 | * | ||
2662 | * Returns 0 for success else error. | ||
2663 | */ | ||
2664 | int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | ||
2665 | const struct snd_soc_dapm_widget *widget) | ||
2666 | { | 2720 | { |
2667 | struct snd_soc_dapm_widget *w; | 2721 | struct snd_soc_dapm_widget *w; |
2668 | size_t name_len; | 2722 | size_t name_len; |
2723 | int ret; | ||
2669 | 2724 | ||
2670 | if ((w = dapm_cnew_widget(widget)) == NULL) | 2725 | if ((w = dapm_cnew_widget(widget)) == NULL) |
2671 | return -ENOMEM; | 2726 | return NULL; |
2727 | |||
2728 | switch (w->id) { | ||
2729 | case snd_soc_dapm_regulator_supply: | ||
2730 | w->priv = devm_regulator_get(dapm->dev, w->name); | ||
2731 | if (IS_ERR(w->priv)) { | ||
2732 | ret = PTR_ERR(w->priv); | ||
2733 | dev_err(dapm->dev, "Failed to request %s: %d\n", | ||
2734 | w->name, ret); | ||
2735 | return NULL; | ||
2736 | } | ||
2737 | break; | ||
2738 | default: | ||
2739 | break; | ||
2740 | } | ||
2672 | 2741 | ||
2673 | name_len = strlen(widget->name) + 1; | 2742 | name_len = strlen(widget->name) + 1; |
2674 | if (dapm->codec && dapm->codec->name_prefix) | 2743 | if (dapm->codec && dapm->codec->name_prefix) |
@@ -2676,13 +2745,13 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2676 | w->name = kmalloc(name_len, GFP_KERNEL); | 2745 | w->name = kmalloc(name_len, GFP_KERNEL); |
2677 | if (w->name == NULL) { | 2746 | if (w->name == NULL) { |
2678 | kfree(w); | 2747 | kfree(w); |
2679 | return -ENOMEM; | 2748 | return NULL; |
2680 | } | 2749 | } |
2681 | if (dapm->codec && dapm->codec->name_prefix) | 2750 | if (dapm->codec && dapm->codec->name_prefix) |
2682 | snprintf(w->name, name_len, "%s %s", | 2751 | snprintf((char *)w->name, name_len, "%s %s", |
2683 | dapm->codec->name_prefix, widget->name); | 2752 | dapm->codec->name_prefix, widget->name); |
2684 | else | 2753 | else |
2685 | snprintf(w->name, name_len, "%s", widget->name); | 2754 | snprintf((char *)w->name, name_len, "%s", widget->name); |
2686 | 2755 | ||
2687 | switch (w->id) { | 2756 | switch (w->id) { |
2688 | case snd_soc_dapm_switch: | 2757 | case snd_soc_dapm_switch: |
@@ -2715,8 +2784,12 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2715 | w->power_check = dapm_generic_check_power; | 2784 | w->power_check = dapm_generic_check_power; |
2716 | break; | 2785 | break; |
2717 | case snd_soc_dapm_supply: | 2786 | case snd_soc_dapm_supply: |
2787 | case snd_soc_dapm_regulator_supply: | ||
2718 | w->power_check = dapm_supply_check_power; | 2788 | w->power_check = dapm_supply_check_power; |
2719 | break; | 2789 | break; |
2790 | case snd_soc_dapm_dai: | ||
2791 | w->power_check = dapm_dai_check_power; | ||
2792 | break; | ||
2720 | default: | 2793 | default: |
2721 | w->power_check = dapm_always_on_check_power; | 2794 | w->power_check = dapm_always_on_check_power; |
2722 | break; | 2795 | break; |
@@ -2734,9 +2807,8 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2734 | 2807 | ||
2735 | /* machine layer set ups unconnected pins and insertions */ | 2808 | /* machine layer set ups unconnected pins and insertions */ |
2736 | w->connected = 1; | 2809 | w->connected = 1; |
2737 | return 0; | 2810 | return w; |
2738 | } | 2811 | } |
2739 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | ||
2740 | 2812 | ||
2741 | /** | 2813 | /** |
2742 | * snd_soc_dapm_new_controls - create new dapm controls | 2814 | * snd_soc_dapm_new_controls - create new dapm controls |
@@ -2752,15 +2824,16 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, | |||
2752 | const struct snd_soc_dapm_widget *widget, | 2824 | const struct snd_soc_dapm_widget *widget, |
2753 | int num) | 2825 | int num) |
2754 | { | 2826 | { |
2755 | int i, ret; | 2827 | struct snd_soc_dapm_widget *w; |
2828 | int i; | ||
2756 | 2829 | ||
2757 | for (i = 0; i < num; i++) { | 2830 | for (i = 0; i < num; i++) { |
2758 | ret = snd_soc_dapm_new_control(dapm, widget); | 2831 | w = snd_soc_dapm_new_control(dapm, widget); |
2759 | if (ret < 0) { | 2832 | if (!w) { |
2760 | dev_err(dapm->dev, | 2833 | dev_err(dapm->dev, |
2761 | "ASoC: Failed to create DAPM control %s: %d\n", | 2834 | "ASoC: Failed to create DAPM control %s\n", |
2762 | widget->name, ret); | 2835 | widget->name); |
2763 | return ret; | 2836 | return -ENOMEM; |
2764 | } | 2837 | } |
2765 | widget++; | 2838 | widget++; |
2766 | } | 2839 | } |
@@ -2768,40 +2841,140 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, | |||
2768 | } | 2841 | } |
2769 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); | 2842 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); |
2770 | 2843 | ||
2771 | static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | 2844 | int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, |
2772 | const char *stream, int event) | 2845 | struct snd_soc_dai *dai) |
2773 | { | 2846 | { |
2847 | struct snd_soc_dapm_widget template; | ||
2774 | struct snd_soc_dapm_widget *w; | 2848 | struct snd_soc_dapm_widget *w; |
2775 | 2849 | ||
2776 | list_for_each_entry(w, &dapm->card->widgets, list) | 2850 | WARN_ON(dapm->dev != dai->dev); |
2777 | { | 2851 | |
2778 | if (!w->sname || w->dapm != dapm) | 2852 | memset(&template, 0, sizeof(template)); |
2853 | template.reg = SND_SOC_NOPM; | ||
2854 | |||
2855 | if (dai->driver->playback.stream_name) { | ||
2856 | template.id = snd_soc_dapm_dai; | ||
2857 | template.name = dai->driver->playback.stream_name; | ||
2858 | template.sname = dai->driver->playback.stream_name; | ||
2859 | |||
2860 | dev_dbg(dai->dev, "adding %s widget\n", | ||
2861 | template.name); | ||
2862 | |||
2863 | w = snd_soc_dapm_new_control(dapm, &template); | ||
2864 | if (!w) { | ||
2865 | dev_err(dapm->dev, "Failed to create %s widget\n", | ||
2866 | dai->driver->playback.stream_name); | ||
2867 | } | ||
2868 | |||
2869 | w->priv = dai; | ||
2870 | dai->playback_widget = w; | ||
2871 | } | ||
2872 | |||
2873 | if (dai->driver->capture.stream_name) { | ||
2874 | template.id = snd_soc_dapm_dai; | ||
2875 | template.name = dai->driver->capture.stream_name; | ||
2876 | template.sname = dai->driver->capture.stream_name; | ||
2877 | |||
2878 | dev_dbg(dai->dev, "adding %s widget\n", | ||
2879 | template.name); | ||
2880 | |||
2881 | w = snd_soc_dapm_new_control(dapm, &template); | ||
2882 | if (!w) { | ||
2883 | dev_err(dapm->dev, "Failed to create %s widget\n", | ||
2884 | dai->driver->capture.stream_name); | ||
2885 | } | ||
2886 | |||
2887 | w->priv = dai; | ||
2888 | dai->capture_widget = w; | ||
2889 | } | ||
2890 | |||
2891 | return 0; | ||
2892 | } | ||
2893 | |||
2894 | int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | ||
2895 | { | ||
2896 | struct snd_soc_dapm_widget *dai_w, *w; | ||
2897 | struct snd_soc_dai *dai; | ||
2898 | struct snd_soc_dapm_route r; | ||
2899 | |||
2900 | memset(&r, 0, sizeof(r)); | ||
2901 | |||
2902 | /* For each DAI widget... */ | ||
2903 | list_for_each_entry(dai_w, &card->widgets, list) { | ||
2904 | if (dai_w->id != snd_soc_dapm_dai) | ||
2779 | continue; | 2905 | continue; |
2780 | dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", | 2906 | |
2781 | w->name, w->sname, stream, event); | 2907 | dai = dai_w->priv; |
2782 | if (strstr(w->sname, stream)) { | 2908 | |
2783 | dapm_mark_dirty(w, "stream event"); | 2909 | /* ...find all widgets with the same stream and link them */ |
2784 | switch(event) { | 2910 | list_for_each_entry(w, &card->widgets, list) { |
2785 | case SND_SOC_DAPM_STREAM_START: | 2911 | if (w->dapm != dai_w->dapm) |
2786 | w->active = 1; | 2912 | continue; |
2787 | break; | 2913 | |
2788 | case SND_SOC_DAPM_STREAM_STOP: | 2914 | if (w->id == snd_soc_dapm_dai) |
2789 | w->active = 0; | 2915 | continue; |
2790 | break; | 2916 | |
2791 | case SND_SOC_DAPM_STREAM_SUSPEND: | 2917 | if (!w->sname) |
2792 | case SND_SOC_DAPM_STREAM_RESUME: | 2918 | continue; |
2793 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: | 2919 | |
2794 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | 2920 | if (dai->driver->playback.stream_name && |
2795 | break; | 2921 | strstr(w->sname, |
2922 | dai->driver->playback.stream_name)) { | ||
2923 | r.source = dai->playback_widget->name; | ||
2924 | r.sink = w->name; | ||
2925 | dev_dbg(dai->dev, "%s -> %s\n", | ||
2926 | r.source, r.sink); | ||
2927 | |||
2928 | snd_soc_dapm_add_route(w->dapm, &r); | ||
2929 | } | ||
2930 | |||
2931 | if (dai->driver->capture.stream_name && | ||
2932 | strstr(w->sname, | ||
2933 | dai->driver->capture.stream_name)) { | ||
2934 | r.source = w->name; | ||
2935 | r.sink = dai->capture_widget->name; | ||
2936 | dev_dbg(dai->dev, "%s -> %s\n", | ||
2937 | r.source, r.sink); | ||
2938 | |||
2939 | snd_soc_dapm_add_route(w->dapm, &r); | ||
2796 | } | 2940 | } |
2797 | } | 2941 | } |
2798 | } | 2942 | } |
2799 | 2943 | ||
2800 | dapm_power_widgets(dapm, event); | 2944 | return 0; |
2945 | } | ||
2801 | 2946 | ||
2802 | /* do we need to notify any clients that DAPM stream is complete */ | 2947 | static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, |
2803 | if (dapm->stream_event) | 2948 | int stream, struct snd_soc_dai *dai, |
2804 | dapm->stream_event(dapm, event); | 2949 | int event) |
2950 | { | ||
2951 | struct snd_soc_dapm_widget *w; | ||
2952 | |||
2953 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2954 | w = dai->playback_widget; | ||
2955 | else | ||
2956 | w = dai->capture_widget; | ||
2957 | |||
2958 | if (!w) | ||
2959 | return; | ||
2960 | |||
2961 | dapm_mark_dirty(w, "stream event"); | ||
2962 | |||
2963 | switch (event) { | ||
2964 | case SND_SOC_DAPM_STREAM_START: | ||
2965 | w->active = 1; | ||
2966 | break; | ||
2967 | case SND_SOC_DAPM_STREAM_STOP: | ||
2968 | w->active = 0; | ||
2969 | break; | ||
2970 | case SND_SOC_DAPM_STREAM_SUSPEND: | ||
2971 | case SND_SOC_DAPM_STREAM_RESUME: | ||
2972 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: | ||
2973 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | ||
2974 | break; | ||
2975 | } | ||
2976 | |||
2977 | dapm_power_widgets(dapm, event); | ||
2805 | } | 2978 | } |
2806 | 2979 | ||
2807 | /** | 2980 | /** |
@@ -2815,16 +2988,13 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | |||
2815 | * | 2988 | * |
2816 | * Returns 0 for success else error. | 2989 | * Returns 0 for success else error. |
2817 | */ | 2990 | */ |
2818 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, | 2991 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
2819 | const char *stream, int event) | 2992 | struct snd_soc_dai *dai, int event) |
2820 | { | 2993 | { |
2821 | struct snd_soc_codec *codec = rtd->codec; | 2994 | struct snd_soc_codec *codec = rtd->codec; |
2822 | 2995 | ||
2823 | if (stream == NULL) | ||
2824 | return 0; | ||
2825 | |||
2826 | mutex_lock(&codec->mutex); | 2996 | mutex_lock(&codec->mutex); |
2827 | soc_dapm_stream_event(&codec->dapm, stream, event); | 2997 | soc_dapm_stream_event(&codec->dapm, stream, dai, event); |
2828 | mutex_unlock(&codec->mutex); | 2998 | mutex_unlock(&codec->mutex); |
2829 | return 0; | 2999 | return 0; |
2830 | } | 3000 | } |