diff options
author | Jiri Kosina <jkosina@suse.cz> | 2012-04-08 15:48:52 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-04-08 15:48:52 -0400 |
commit | e75d660672ddd11704b7f0fdb8ff21968587b266 (patch) | |
tree | ccb9c107744c10b553c0373e450bee3971d16c00 /sound/soc/soc-dapm.c | |
parent | 61282f37927143e45b03153f3e7b48d6b702147a (diff) | |
parent | 0034102808e0dbbf3a2394b82b1bb40b5778de9e (diff) |
Merge branch 'master' into for-next
Merge with latest Linus' tree, as I have incoming patches
that fix code that is newer than current HEAD of for-next.
Conflicts:
drivers/net/ethernet/realtek/r8169.c
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r-- | sound/soc/soc-dapm.c | 428 |
1 files changed, 296 insertions, 132 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1f55ded4047f..5cbd2d7623b8 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); |
@@ -1485,12 +1544,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1485 | } | 1544 | } |
1486 | 1545 | ||
1487 | #ifdef CONFIG_DEBUG_FS | 1546 | #ifdef CONFIG_DEBUG_FS |
1488 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) | ||
1489 | { | ||
1490 | file->private_data = inode->i_private; | ||
1491 | return 0; | ||
1492 | } | ||
1493 | |||
1494 | static ssize_t dapm_widget_power_read_file(struct file *file, | 1547 | static ssize_t dapm_widget_power_read_file(struct file *file, |
1495 | char __user *user_buf, | 1548 | char __user *user_buf, |
1496 | size_t count, loff_t *ppos) | 1549 | size_t count, loff_t *ppos) |
@@ -1510,8 +1563,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1510 | out = is_connected_output_ep(w); | 1563 | out = is_connected_output_ep(w); |
1511 | dapm_clear_walk(w->dapm); | 1564 | dapm_clear_walk(w->dapm); |
1512 | 1565 | ||
1513 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d", | 1566 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", |
1514 | w->name, w->power ? "On" : "Off", in, out); | 1567 | w->name, w->power ? "On" : "Off", |
1568 | w->force ? " (forced)" : "", in, out); | ||
1515 | 1569 | ||
1516 | if (w->reg >= 0) | 1570 | if (w->reg >= 0) |
1517 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1571 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
@@ -1553,17 +1607,11 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1553 | } | 1607 | } |
1554 | 1608 | ||
1555 | static const struct file_operations dapm_widget_power_fops = { | 1609 | static const struct file_operations dapm_widget_power_fops = { |
1556 | .open = dapm_widget_power_open_file, | 1610 | .open = simple_open, |
1557 | .read = dapm_widget_power_read_file, | 1611 | .read = dapm_widget_power_read_file, |
1558 | .llseek = default_llseek, | 1612 | .llseek = default_llseek, |
1559 | }; | 1613 | }; |
1560 | 1614 | ||
1561 | static int dapm_bias_open_file(struct inode *inode, struct file *file) | ||
1562 | { | ||
1563 | file->private_data = inode->i_private; | ||
1564 | return 0; | ||
1565 | } | ||
1566 | |||
1567 | static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, | 1615 | static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, |
1568 | size_t count, loff_t *ppos) | 1616 | size_t count, loff_t *ppos) |
1569 | { | 1617 | { |
@@ -1594,7 +1642,7 @@ static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf, | |||
1594 | } | 1642 | } |
1595 | 1643 | ||
1596 | static const struct file_operations dapm_bias_fops = { | 1644 | static const struct file_operations dapm_bias_fops = { |
1597 | .open = dapm_bias_open_file, | 1645 | .open = simple_open, |
1598 | .read = dapm_bias_read_file, | 1646 | .read = dapm_bias_read_file, |
1599 | .llseek = default_llseek, | 1647 | .llseek = default_llseek, |
1600 | }; | 1648 | }; |
@@ -1607,7 +1655,7 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, | |||
1607 | dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); | 1655 | dapm->debugfs_dapm = debugfs_create_dir("dapm", parent); |
1608 | 1656 | ||
1609 | if (!dapm->debugfs_dapm) { | 1657 | if (!dapm->debugfs_dapm) { |
1610 | printk(KERN_WARNING | 1658 | dev_warn(dapm->dev, |
1611 | "Failed to create DAPM debugfs directory\n"); | 1659 | "Failed to create DAPM debugfs directory\n"); |
1612 | return; | 1660 | return; |
1613 | } | 1661 | } |
@@ -1659,9 +1707,8 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
1659 | #endif | 1707 | #endif |
1660 | 1708 | ||
1661 | /* test and update the power status of a mux widget */ | 1709 | /* test and update the power status of a mux widget */ |
1662 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 1710 | int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
1663 | struct snd_kcontrol *kcontrol, int change, | 1711 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
1664 | int mux, struct soc_enum *e) | ||
1665 | { | 1712 | { |
1666 | struct snd_soc_dapm_path *path; | 1713 | struct snd_soc_dapm_path *path; |
1667 | int found = 0; | 1714 | int found = 0; |
@@ -1671,9 +1718,6 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1671 | widget->id != snd_soc_dapm_value_mux) | 1718 | widget->id != snd_soc_dapm_value_mux) |
1672 | return -ENODEV; | 1719 | return -ENODEV; |
1673 | 1720 | ||
1674 | if (!change) | ||
1675 | return 0; | ||
1676 | |||
1677 | /* find dapm widget path assoc with kcontrol */ | 1721 | /* find dapm widget path assoc with kcontrol */ |
1678 | list_for_each_entry(path, &widget->dapm->card->paths, list) { | 1722 | list_for_each_entry(path, &widget->dapm->card->paths, list) { |
1679 | if (path->kcontrol != kcontrol) | 1723 | if (path->kcontrol != kcontrol) |
@@ -1702,9 +1746,10 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | |||
1702 | 1746 | ||
1703 | return 0; | 1747 | return 0; |
1704 | } | 1748 | } |
1749 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); | ||
1705 | 1750 | ||
1706 | /* test and update the power status of a mixer or switch widget */ | 1751 | /* 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, | 1752 | int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, |
1708 | struct snd_kcontrol *kcontrol, int connect) | 1753 | struct snd_kcontrol *kcontrol, int connect) |
1709 | { | 1754 | { |
1710 | struct snd_soc_dapm_path *path; | 1755 | struct snd_soc_dapm_path *path; |
@@ -1733,6 +1778,7 @@ static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, | |||
1733 | 1778 | ||
1734 | return 0; | 1779 | return 0; |
1735 | } | 1780 | } |
1781 | EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); | ||
1736 | 1782 | ||
1737 | /* show dapm widget status in sys fs */ | 1783 | /* show dapm widget status in sys fs */ |
1738 | static ssize_t dapm_widget_show(struct device *dev, | 1784 | static ssize_t dapm_widget_show(struct device *dev, |
@@ -1762,6 +1808,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
1762 | case snd_soc_dapm_mixer: | 1808 | case snd_soc_dapm_mixer: |
1763 | case snd_soc_dapm_mixer_named_ctl: | 1809 | case snd_soc_dapm_mixer_named_ctl: |
1764 | case snd_soc_dapm_supply: | 1810 | case snd_soc_dapm_supply: |
1811 | case snd_soc_dapm_regulator_supply: | ||
1765 | if (w->name) | 1812 | if (w->name) |
1766 | count += sprintf(buf + count, "%s: %s\n", | 1813 | count += sprintf(buf + count, "%s: %s\n", |
1767 | w->name, w->power ? "On":"Off"); | 1814 | w->name, w->power ? "On":"Off"); |
@@ -1869,10 +1916,12 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
1869 | return -EINVAL; | 1916 | return -EINVAL; |
1870 | } | 1917 | } |
1871 | 1918 | ||
1919 | if (w->connected != status) | ||
1920 | dapm_mark_dirty(w, "pin configuration"); | ||
1921 | |||
1872 | w->connected = status; | 1922 | w->connected = status; |
1873 | if (status == 0) | 1923 | if (status == 0) |
1874 | w->force = 0; | 1924 | w->force = 0; |
1875 | dapm_mark_dirty(w, "pin configuration"); | ||
1876 | 1925 | ||
1877 | return 0; | 1926 | return 0; |
1878 | } | 1927 | } |
@@ -2000,8 +2049,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2000 | case snd_soc_dapm_pre: | 2049 | case snd_soc_dapm_pre: |
2001 | case snd_soc_dapm_post: | 2050 | case snd_soc_dapm_post: |
2002 | case snd_soc_dapm_supply: | 2051 | case snd_soc_dapm_supply: |
2052 | case snd_soc_dapm_regulator_supply: | ||
2003 | case snd_soc_dapm_aif_in: | 2053 | case snd_soc_dapm_aif_in: |
2004 | case snd_soc_dapm_aif_out: | 2054 | case snd_soc_dapm_aif_out: |
2055 | case snd_soc_dapm_dai: | ||
2005 | list_add(&path->list, &dapm->card->paths); | 2056 | list_add(&path->list, &dapm->card->paths); |
2006 | list_add(&path->list_sink, &wsink->sources); | 2057 | list_add(&path->list_sink, &wsink->sources); |
2007 | list_add(&path->list_source, &wsource->sinks); | 2058 | list_add(&path->list_source, &wsource->sinks); |
@@ -2315,7 +2366,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2315 | update.val = val; | 2366 | update.val = val; |
2316 | widget->dapm->update = &update; | 2367 | widget->dapm->update = &update; |
2317 | 2368 | ||
2318 | dapm_mixer_update_power(widget, kcontrol, connect); | 2369 | snd_soc_dapm_mixer_update_power(widget, kcontrol, connect); |
2319 | 2370 | ||
2320 | widget->dapm->update = NULL; | 2371 | widget->dapm->update = NULL; |
2321 | } | 2372 | } |
@@ -2406,7 +2457,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2406 | update.val = val; | 2457 | update.val = val; |
2407 | widget->dapm->update = &update; | 2458 | widget->dapm->update = &update; |
2408 | 2459 | ||
2409 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2460 | snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); |
2410 | 2461 | ||
2411 | widget->dapm->update = NULL; | 2462 | widget->dapm->update = NULL; |
2412 | } | 2463 | } |
@@ -2467,8 +2518,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | |||
2467 | 2518 | ||
2468 | widget->value = ucontrol->value.enumerated.item[0]; | 2519 | widget->value = ucontrol->value.enumerated.item[0]; |
2469 | 2520 | ||
2470 | dapm_mux_update_power(widget, kcontrol, change, | 2521 | snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); |
2471 | widget->value, e); | ||
2472 | } | 2522 | } |
2473 | } | 2523 | } |
2474 | 2524 | ||
@@ -2571,7 +2621,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
2571 | update.val = val; | 2621 | update.val = val; |
2572 | widget->dapm->update = &update; | 2622 | widget->dapm->update = &update; |
2573 | 2623 | ||
2574 | dapm_mux_update_power(widget, kcontrol, change, mux, e); | 2624 | snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); |
2575 | 2625 | ||
2576 | widget->dapm->update = NULL; | 2626 | widget->dapm->update = NULL; |
2577 | } | 2627 | } |
@@ -2611,15 +2661,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch); | |||
2611 | int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, | 2661 | int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, |
2612 | struct snd_ctl_elem_value *ucontrol) | 2662 | struct snd_ctl_elem_value *ucontrol) |
2613 | { | 2663 | { |
2614 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2664 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
2615 | const char *pin = (const char *)kcontrol->private_value; | 2665 | const char *pin = (const char *)kcontrol->private_value; |
2616 | 2666 | ||
2617 | mutex_lock(&codec->mutex); | 2667 | mutex_lock(&card->mutex); |
2618 | 2668 | ||
2619 | ucontrol->value.integer.value[0] = | 2669 | ucontrol->value.integer.value[0] = |
2620 | snd_soc_dapm_get_pin_status(&codec->dapm, pin); | 2670 | snd_soc_dapm_get_pin_status(&card->dapm, pin); |
2621 | 2671 | ||
2622 | mutex_unlock(&codec->mutex); | 2672 | mutex_unlock(&card->mutex); |
2623 | 2673 | ||
2624 | return 0; | 2674 | return 0; |
2625 | } | 2675 | } |
@@ -2634,41 +2684,48 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch); | |||
2634 | int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | 2684 | int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, |
2635 | struct snd_ctl_elem_value *ucontrol) | 2685 | struct snd_ctl_elem_value *ucontrol) |
2636 | { | 2686 | { |
2637 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2687 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
2638 | const char *pin = (const char *)kcontrol->private_value; | 2688 | const char *pin = (const char *)kcontrol->private_value; |
2639 | 2689 | ||
2640 | mutex_lock(&codec->mutex); | 2690 | mutex_lock(&card->mutex); |
2641 | 2691 | ||
2642 | if (ucontrol->value.integer.value[0]) | 2692 | if (ucontrol->value.integer.value[0]) |
2643 | snd_soc_dapm_enable_pin(&codec->dapm, pin); | 2693 | snd_soc_dapm_enable_pin(&card->dapm, pin); |
2644 | else | 2694 | else |
2645 | snd_soc_dapm_disable_pin(&codec->dapm, pin); | 2695 | snd_soc_dapm_disable_pin(&card->dapm, pin); |
2646 | 2696 | ||
2647 | snd_soc_dapm_sync(&codec->dapm); | 2697 | snd_soc_dapm_sync(&card->dapm); |
2648 | 2698 | ||
2649 | mutex_unlock(&codec->mutex); | 2699 | mutex_unlock(&card->mutex); |
2650 | 2700 | ||
2651 | return 0; | 2701 | return 0; |
2652 | } | 2702 | } |
2653 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); | 2703 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); |
2654 | 2704 | ||
2655 | /** | 2705 | static struct snd_soc_dapm_widget * |
2656 | * snd_soc_dapm_new_control - create new dapm control | 2706 | snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, |
2657 | * @dapm: DAPM context | 2707 | 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 | { | 2708 | { |
2667 | struct snd_soc_dapm_widget *w; | 2709 | struct snd_soc_dapm_widget *w; |
2668 | size_t name_len; | 2710 | size_t name_len; |
2711 | int ret; | ||
2669 | 2712 | ||
2670 | if ((w = dapm_cnew_widget(widget)) == NULL) | 2713 | if ((w = dapm_cnew_widget(widget)) == NULL) |
2671 | return -ENOMEM; | 2714 | return NULL; |
2715 | |||
2716 | switch (w->id) { | ||
2717 | case snd_soc_dapm_regulator_supply: | ||
2718 | w->priv = devm_regulator_get(dapm->dev, w->name); | ||
2719 | if (IS_ERR(w->priv)) { | ||
2720 | ret = PTR_ERR(w->priv); | ||
2721 | dev_err(dapm->dev, "Failed to request %s: %d\n", | ||
2722 | w->name, ret); | ||
2723 | return NULL; | ||
2724 | } | ||
2725 | break; | ||
2726 | default: | ||
2727 | break; | ||
2728 | } | ||
2672 | 2729 | ||
2673 | name_len = strlen(widget->name) + 1; | 2730 | name_len = strlen(widget->name) + 1; |
2674 | if (dapm->codec && dapm->codec->name_prefix) | 2731 | if (dapm->codec && dapm->codec->name_prefix) |
@@ -2676,13 +2733,13 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2676 | w->name = kmalloc(name_len, GFP_KERNEL); | 2733 | w->name = kmalloc(name_len, GFP_KERNEL); |
2677 | if (w->name == NULL) { | 2734 | if (w->name == NULL) { |
2678 | kfree(w); | 2735 | kfree(w); |
2679 | return -ENOMEM; | 2736 | return NULL; |
2680 | } | 2737 | } |
2681 | if (dapm->codec && dapm->codec->name_prefix) | 2738 | if (dapm->codec && dapm->codec->name_prefix) |
2682 | snprintf(w->name, name_len, "%s %s", | 2739 | snprintf((char *)w->name, name_len, "%s %s", |
2683 | dapm->codec->name_prefix, widget->name); | 2740 | dapm->codec->name_prefix, widget->name); |
2684 | else | 2741 | else |
2685 | snprintf(w->name, name_len, "%s", widget->name); | 2742 | snprintf((char *)w->name, name_len, "%s", widget->name); |
2686 | 2743 | ||
2687 | switch (w->id) { | 2744 | switch (w->id) { |
2688 | case snd_soc_dapm_switch: | 2745 | case snd_soc_dapm_switch: |
@@ -2715,8 +2772,12 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2715 | w->power_check = dapm_generic_check_power; | 2772 | w->power_check = dapm_generic_check_power; |
2716 | break; | 2773 | break; |
2717 | case snd_soc_dapm_supply: | 2774 | case snd_soc_dapm_supply: |
2775 | case snd_soc_dapm_regulator_supply: | ||
2718 | w->power_check = dapm_supply_check_power; | 2776 | w->power_check = dapm_supply_check_power; |
2719 | break; | 2777 | break; |
2778 | case snd_soc_dapm_dai: | ||
2779 | w->power_check = dapm_dai_check_power; | ||
2780 | break; | ||
2720 | default: | 2781 | default: |
2721 | w->power_check = dapm_always_on_check_power; | 2782 | w->power_check = dapm_always_on_check_power; |
2722 | break; | 2783 | break; |
@@ -2734,9 +2795,8 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2734 | 2795 | ||
2735 | /* machine layer set ups unconnected pins and insertions */ | 2796 | /* machine layer set ups unconnected pins and insertions */ |
2736 | w->connected = 1; | 2797 | w->connected = 1; |
2737 | return 0; | 2798 | return w; |
2738 | } | 2799 | } |
2739 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | ||
2740 | 2800 | ||
2741 | /** | 2801 | /** |
2742 | * snd_soc_dapm_new_controls - create new dapm controls | 2802 | * snd_soc_dapm_new_controls - create new dapm controls |
@@ -2752,15 +2812,16 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, | |||
2752 | const struct snd_soc_dapm_widget *widget, | 2812 | const struct snd_soc_dapm_widget *widget, |
2753 | int num) | 2813 | int num) |
2754 | { | 2814 | { |
2755 | int i, ret; | 2815 | struct snd_soc_dapm_widget *w; |
2816 | int i; | ||
2756 | 2817 | ||
2757 | for (i = 0; i < num; i++) { | 2818 | for (i = 0; i < num; i++) { |
2758 | ret = snd_soc_dapm_new_control(dapm, widget); | 2819 | w = snd_soc_dapm_new_control(dapm, widget); |
2759 | if (ret < 0) { | 2820 | if (!w) { |
2760 | dev_err(dapm->dev, | 2821 | dev_err(dapm->dev, |
2761 | "ASoC: Failed to create DAPM control %s: %d\n", | 2822 | "ASoC: Failed to create DAPM control %s\n", |
2762 | widget->name, ret); | 2823 | widget->name); |
2763 | return ret; | 2824 | return -ENOMEM; |
2764 | } | 2825 | } |
2765 | widget++; | 2826 | widget++; |
2766 | } | 2827 | } |
@@ -2768,40 +2829,140 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, | |||
2768 | } | 2829 | } |
2769 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); | 2830 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); |
2770 | 2831 | ||
2771 | static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | 2832 | int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, |
2772 | const char *stream, int event) | 2833 | struct snd_soc_dai *dai) |
2773 | { | 2834 | { |
2835 | struct snd_soc_dapm_widget template; | ||
2774 | struct snd_soc_dapm_widget *w; | 2836 | struct snd_soc_dapm_widget *w; |
2775 | 2837 | ||
2776 | list_for_each_entry(w, &dapm->card->widgets, list) | 2838 | WARN_ON(dapm->dev != dai->dev); |
2777 | { | 2839 | |
2778 | if (!w->sname || w->dapm != dapm) | 2840 | memset(&template, 0, sizeof(template)); |
2841 | template.reg = SND_SOC_NOPM; | ||
2842 | |||
2843 | if (dai->driver->playback.stream_name) { | ||
2844 | template.id = snd_soc_dapm_dai; | ||
2845 | template.name = dai->driver->playback.stream_name; | ||
2846 | template.sname = dai->driver->playback.stream_name; | ||
2847 | |||
2848 | dev_dbg(dai->dev, "adding %s widget\n", | ||
2849 | template.name); | ||
2850 | |||
2851 | w = snd_soc_dapm_new_control(dapm, &template); | ||
2852 | if (!w) { | ||
2853 | dev_err(dapm->dev, "Failed to create %s widget\n", | ||
2854 | dai->driver->playback.stream_name); | ||
2855 | } | ||
2856 | |||
2857 | w->priv = dai; | ||
2858 | dai->playback_widget = w; | ||
2859 | } | ||
2860 | |||
2861 | if (dai->driver->capture.stream_name) { | ||
2862 | template.id = snd_soc_dapm_dai; | ||
2863 | template.name = dai->driver->capture.stream_name; | ||
2864 | template.sname = dai->driver->capture.stream_name; | ||
2865 | |||
2866 | dev_dbg(dai->dev, "adding %s widget\n", | ||
2867 | template.name); | ||
2868 | |||
2869 | w = snd_soc_dapm_new_control(dapm, &template); | ||
2870 | if (!w) { | ||
2871 | dev_err(dapm->dev, "Failed to create %s widget\n", | ||
2872 | dai->driver->capture.stream_name); | ||
2873 | } | ||
2874 | |||
2875 | w->priv = dai; | ||
2876 | dai->capture_widget = w; | ||
2877 | } | ||
2878 | |||
2879 | return 0; | ||
2880 | } | ||
2881 | |||
2882 | int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) | ||
2883 | { | ||
2884 | struct snd_soc_dapm_widget *dai_w, *w; | ||
2885 | struct snd_soc_dai *dai; | ||
2886 | struct snd_soc_dapm_route r; | ||
2887 | |||
2888 | memset(&r, 0, sizeof(r)); | ||
2889 | |||
2890 | /* For each DAI widget... */ | ||
2891 | list_for_each_entry(dai_w, &card->widgets, list) { | ||
2892 | if (dai_w->id != snd_soc_dapm_dai) | ||
2779 | continue; | 2893 | continue; |
2780 | dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", | 2894 | |
2781 | w->name, w->sname, stream, event); | 2895 | dai = dai_w->priv; |
2782 | if (strstr(w->sname, stream)) { | 2896 | |
2783 | dapm_mark_dirty(w, "stream event"); | 2897 | /* ...find all widgets with the same stream and link them */ |
2784 | switch(event) { | 2898 | list_for_each_entry(w, &card->widgets, list) { |
2785 | case SND_SOC_DAPM_STREAM_START: | 2899 | if (w->dapm != dai_w->dapm) |
2786 | w->active = 1; | 2900 | continue; |
2787 | break; | 2901 | |
2788 | case SND_SOC_DAPM_STREAM_STOP: | 2902 | if (w->id == snd_soc_dapm_dai) |
2789 | w->active = 0; | 2903 | continue; |
2790 | break; | 2904 | |
2791 | case SND_SOC_DAPM_STREAM_SUSPEND: | 2905 | if (!w->sname) |
2792 | case SND_SOC_DAPM_STREAM_RESUME: | 2906 | continue; |
2793 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: | 2907 | |
2794 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | 2908 | if (dai->driver->playback.stream_name && |
2795 | break; | 2909 | strstr(w->sname, |
2910 | dai->driver->playback.stream_name)) { | ||
2911 | r.source = dai->playback_widget->name; | ||
2912 | r.sink = w->name; | ||
2913 | dev_dbg(dai->dev, "%s -> %s\n", | ||
2914 | r.source, r.sink); | ||
2915 | |||
2916 | snd_soc_dapm_add_route(w->dapm, &r); | ||
2917 | } | ||
2918 | |||
2919 | if (dai->driver->capture.stream_name && | ||
2920 | strstr(w->sname, | ||
2921 | dai->driver->capture.stream_name)) { | ||
2922 | r.source = w->name; | ||
2923 | r.sink = dai->capture_widget->name; | ||
2924 | dev_dbg(dai->dev, "%s -> %s\n", | ||
2925 | r.source, r.sink); | ||
2926 | |||
2927 | snd_soc_dapm_add_route(w->dapm, &r); | ||
2796 | } | 2928 | } |
2797 | } | 2929 | } |
2798 | } | 2930 | } |
2799 | 2931 | ||
2800 | dapm_power_widgets(dapm, event); | 2932 | return 0; |
2933 | } | ||
2934 | |||
2935 | static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | ||
2936 | int stream, struct snd_soc_dai *dai, | ||
2937 | int event) | ||
2938 | { | ||
2939 | struct snd_soc_dapm_widget *w; | ||
2940 | |||
2941 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2942 | w = dai->playback_widget; | ||
2943 | else | ||
2944 | w = dai->capture_widget; | ||
2945 | |||
2946 | if (!w) | ||
2947 | return; | ||
2948 | |||
2949 | dapm_mark_dirty(w, "stream event"); | ||
2801 | 2950 | ||
2802 | /* do we need to notify any clients that DAPM stream is complete */ | 2951 | switch (event) { |
2803 | if (dapm->stream_event) | 2952 | case SND_SOC_DAPM_STREAM_START: |
2804 | dapm->stream_event(dapm, event); | 2953 | w->active = 1; |
2954 | break; | ||
2955 | case SND_SOC_DAPM_STREAM_STOP: | ||
2956 | w->active = 0; | ||
2957 | break; | ||
2958 | case SND_SOC_DAPM_STREAM_SUSPEND: | ||
2959 | case SND_SOC_DAPM_STREAM_RESUME: | ||
2960 | case SND_SOC_DAPM_STREAM_PAUSE_PUSH: | ||
2961 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | ||
2962 | break; | ||
2963 | } | ||
2964 | |||
2965 | dapm_power_widgets(dapm, event); | ||
2805 | } | 2966 | } |
2806 | 2967 | ||
2807 | /** | 2968 | /** |
@@ -2815,16 +2976,13 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, | |||
2815 | * | 2976 | * |
2816 | * Returns 0 for success else error. | 2977 | * Returns 0 for success else error. |
2817 | */ | 2978 | */ |
2818 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, | 2979 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, |
2819 | const char *stream, int event) | 2980 | struct snd_soc_dai *dai, int event) |
2820 | { | 2981 | { |
2821 | struct snd_soc_codec *codec = rtd->codec; | 2982 | struct snd_soc_codec *codec = rtd->codec; |
2822 | 2983 | ||
2823 | if (stream == NULL) | ||
2824 | return 0; | ||
2825 | |||
2826 | mutex_lock(&codec->mutex); | 2984 | mutex_lock(&codec->mutex); |
2827 | soc_dapm_stream_event(&codec->dapm, stream, event); | 2985 | soc_dapm_stream_event(&codec->dapm, stream, dai, event); |
2828 | mutex_unlock(&codec->mutex); | 2986 | mutex_unlock(&codec->mutex); |
2829 | return 0; | 2987 | return 0; |
2830 | } | 2988 | } |
@@ -3068,9 +3226,13 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
3068 | * standby. | 3226 | * standby. |
3069 | */ | 3227 | */ |
3070 | if (powerdown) { | 3228 | if (powerdown) { |
3071 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); | 3229 | if (dapm->bias_level == SND_SOC_BIAS_ON) |
3230 | snd_soc_dapm_set_bias_level(dapm, | ||
3231 | SND_SOC_BIAS_PREPARE); | ||
3072 | dapm_seq_run(dapm, &down_list, 0, false); | 3232 | dapm_seq_run(dapm, &down_list, 0, false); |
3073 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); | 3233 | if (dapm->bias_level == SND_SOC_BIAS_PREPARE) |
3234 | snd_soc_dapm_set_bias_level(dapm, | ||
3235 | SND_SOC_BIAS_STANDBY); | ||
3074 | } | 3236 | } |
3075 | } | 3237 | } |
3076 | 3238 | ||
@@ -3083,7 +3245,9 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) | |||
3083 | 3245 | ||
3084 | list_for_each_entry(codec, &card->codec_dev_list, list) { | 3246 | list_for_each_entry(codec, &card->codec_dev_list, list) { |
3085 | soc_dapm_shutdown_codec(&codec->dapm); | 3247 | soc_dapm_shutdown_codec(&codec->dapm); |
3086 | snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); | 3248 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) |
3249 | snd_soc_dapm_set_bias_level(&codec->dapm, | ||
3250 | SND_SOC_BIAS_OFF); | ||
3087 | } | 3251 | } |
3088 | } | 3252 | } |
3089 | 3253 | ||