diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 239 |
1 files changed, 197 insertions, 42 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 04352930867..9a3b72824f8 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -33,6 +33,13 @@ | |||
33 | #include "hda_local.h" | 33 | #include "hda_local.h" |
34 | #include <sound/hda_hwdep.h> | 34 | #include <sound/hda_hwdep.h> |
35 | 35 | ||
36 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
37 | /* define this option here to hide as static */ | ||
38 | static int power_save = 10; | ||
39 | module_param(power_save, int, 0644); | ||
40 | MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " | ||
41 | "(in second, 0 = disable)."); | ||
42 | #endif | ||
36 | 43 | ||
37 | /* | 44 | /* |
38 | * vendor / preset table | 45 | * vendor / preset table |
@@ -60,6 +67,13 @@ static struct hda_vendor_id hda_vendor_ids[] = { | |||
60 | #include "hda_patch.h" | 67 | #include "hda_patch.h" |
61 | 68 | ||
62 | 69 | ||
70 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
71 | static void hda_power_work(struct work_struct *work); | ||
72 | static void hda_keep_power_on(struct hda_codec *codec); | ||
73 | #else | ||
74 | static inline void hda_keep_power_on(struct hda_codec *codec) {} | ||
75 | #endif | ||
76 | |||
63 | /** | 77 | /** |
64 | * snd_hda_codec_read - send a command and get the response | 78 | * snd_hda_codec_read - send a command and get the response |
65 | * @codec: the HDA codec | 79 | * @codec: the HDA codec |
@@ -77,12 +91,14 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, | |||
77 | unsigned int verb, unsigned int parm) | 91 | unsigned int verb, unsigned int parm) |
78 | { | 92 | { |
79 | unsigned int res; | 93 | unsigned int res; |
94 | snd_hda_power_up(codec); | ||
80 | mutex_lock(&codec->bus->cmd_mutex); | 95 | mutex_lock(&codec->bus->cmd_mutex); |
81 | if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) | 96 | if (!codec->bus->ops.command(codec, nid, direct, verb, parm)) |
82 | res = codec->bus->ops.get_response(codec); | 97 | res = codec->bus->ops.get_response(codec); |
83 | else | 98 | else |
84 | res = (unsigned int)-1; | 99 | res = (unsigned int)-1; |
85 | mutex_unlock(&codec->bus->cmd_mutex); | 100 | mutex_unlock(&codec->bus->cmd_mutex); |
101 | snd_hda_power_down(codec); | ||
86 | return res; | 102 | return res; |
87 | } | 103 | } |
88 | 104 | ||
@@ -102,9 +118,11 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | |||
102 | unsigned int verb, unsigned int parm) | 118 | unsigned int verb, unsigned int parm) |
103 | { | 119 | { |
104 | int err; | 120 | int err; |
121 | snd_hda_power_up(codec); | ||
105 | mutex_lock(&codec->bus->cmd_mutex); | 122 | mutex_lock(&codec->bus->cmd_mutex); |
106 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); | 123 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); |
107 | mutex_unlock(&codec->bus->cmd_mutex); | 124 | mutex_unlock(&codec->bus->cmd_mutex); |
125 | snd_hda_power_down(codec); | ||
108 | return err; | 126 | return err; |
109 | } | 127 | } |
110 | 128 | ||
@@ -505,6 +523,9 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
505 | { | 523 | { |
506 | if (!codec) | 524 | if (!codec) |
507 | return; | 525 | return; |
526 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
527 | cancel_delayed_work(&codec->power_work); | ||
528 | #endif | ||
508 | list_del(&codec->list); | 529 | list_del(&codec->list); |
509 | codec->bus->caddr_tbl[codec->addr] = NULL; | 530 | codec->bus->caddr_tbl[codec->addr] = NULL; |
510 | if (codec->patch_ops.free) | 531 | if (codec->patch_ops.free) |
@@ -551,6 +572,15 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
551 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | 572 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
552 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | 573 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); |
553 | 574 | ||
575 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
576 | INIT_DELAYED_WORK(&codec->power_work, hda_power_work); | ||
577 | /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. | ||
578 | * the caller has to power down appropriatley after initialization | ||
579 | * phase. | ||
580 | */ | ||
581 | hda_keep_power_on(codec); | ||
582 | #endif | ||
583 | |||
554 | list_add_tail(&codec->list, &bus->codec_list); | 584 | list_add_tail(&codec->list, &bus->codec_list); |
555 | bus->caddr_tbl[codec_addr] = codec; | 585 | bus->caddr_tbl[codec_addr] = codec; |
556 | 586 | ||
@@ -855,7 +885,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | |||
855 | return ret; | 885 | return ret; |
856 | } | 886 | } |
857 | 887 | ||
858 | #ifdef CONFIG_PM | 888 | #ifdef SND_HDA_NEEDS_RESUME |
859 | /* resume the all amp commands from the cache */ | 889 | /* resume the all amp commands from the cache */ |
860 | void snd_hda_codec_resume_amp(struct hda_codec *codec) | 890 | void snd_hda_codec_resume_amp(struct hda_codec *codec) |
861 | { | 891 | { |
@@ -879,7 +909,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) | |||
879 | } | 909 | } |
880 | } | 910 | } |
881 | } | 911 | } |
882 | #endif /* CONFIG_PM */ | 912 | #endif /* SND_HDA_NEEDS_RESUME */ |
883 | 913 | ||
884 | /* | 914 | /* |
885 | * AMP control callbacks | 915 | * AMP control callbacks |
@@ -945,6 +975,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, | |||
945 | long *valp = ucontrol->value.integer.value; | 975 | long *valp = ucontrol->value.integer.value; |
946 | int change = 0; | 976 | int change = 0; |
947 | 977 | ||
978 | snd_hda_power_up(codec); | ||
948 | if (chs & 1) { | 979 | if (chs & 1) { |
949 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | 980 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
950 | 0x7f, *valp); | 981 | 0x7f, *valp); |
@@ -953,6 +984,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, | |||
953 | if (chs & 2) | 984 | if (chs & 2) |
954 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | 985 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
955 | 0x7f, *valp); | 986 | 0x7f, *valp); |
987 | snd_hda_power_down(codec); | ||
956 | return change; | 988 | return change; |
957 | } | 989 | } |
958 | 990 | ||
@@ -1025,6 +1057,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, | |||
1025 | long *valp = ucontrol->value.integer.value; | 1057 | long *valp = ucontrol->value.integer.value; |
1026 | int change = 0; | 1058 | int change = 0; |
1027 | 1059 | ||
1060 | snd_hda_power_up(codec); | ||
1028 | if (chs & 1) { | 1061 | if (chs & 1) { |
1029 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, | 1062 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
1030 | HDA_AMP_MUTE, | 1063 | HDA_AMP_MUTE, |
@@ -1035,7 +1068,11 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, | |||
1035 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, | 1068 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
1036 | HDA_AMP_MUTE, | 1069 | HDA_AMP_MUTE, |
1037 | *valp ? 0 : HDA_AMP_MUTE); | 1070 | *valp ? 0 : HDA_AMP_MUTE); |
1038 | 1071 | #ifdef CONFIG_SND_HDA_POWER_SAVE | |
1072 | if (codec->patch_ops.check_power_status) | ||
1073 | codec->patch_ops.check_power_status(codec, nid); | ||
1074 | #endif | ||
1075 | snd_hda_power_down(codec); | ||
1039 | return change; | 1076 | return change; |
1040 | } | 1077 | } |
1041 | 1078 | ||
@@ -1502,7 +1539,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) | |||
1502 | return 0; | 1539 | return 0; |
1503 | } | 1540 | } |
1504 | 1541 | ||
1505 | #ifdef CONFIG_PM | 1542 | #ifdef SND_HDA_NEEDS_RESUME |
1506 | /* | 1543 | /* |
1507 | * command cache | 1544 | * command cache |
1508 | */ | 1545 | */ |
@@ -1528,6 +1565,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | |||
1528 | int direct, unsigned int verb, unsigned int parm) | 1565 | int direct, unsigned int verb, unsigned int parm) |
1529 | { | 1566 | { |
1530 | int err; | 1567 | int err; |
1568 | snd_hda_power_up(codec); | ||
1531 | mutex_lock(&codec->bus->cmd_mutex); | 1569 | mutex_lock(&codec->bus->cmd_mutex); |
1532 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); | 1570 | err = codec->bus->ops.command(codec, nid, direct, verb, parm); |
1533 | if (!err) { | 1571 | if (!err) { |
@@ -1538,6 +1576,7 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | |||
1538 | c->val = parm; | 1576 | c->val = parm; |
1539 | } | 1577 | } |
1540 | mutex_unlock(&codec->bus->cmd_mutex); | 1578 | mutex_unlock(&codec->bus->cmd_mutex); |
1579 | snd_hda_power_down(codec); | ||
1541 | return err; | 1580 | return err; |
1542 | } | 1581 | } |
1543 | 1582 | ||
@@ -1572,7 +1611,7 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, | |||
1572 | snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, | 1611 | snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, |
1573 | seq->param); | 1612 | seq->param); |
1574 | } | 1613 | } |
1575 | #endif /* CONFIG_PM */ | 1614 | #endif /* SND_HDA_NEEDS_RESUME */ |
1576 | 1615 | ||
1577 | /* | 1616 | /* |
1578 | * set power state of the codec | 1617 | * set power state of the codec |
@@ -1580,24 +1619,70 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, | |||
1580 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | 1619 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, |
1581 | unsigned int power_state) | 1620 | unsigned int power_state) |
1582 | { | 1621 | { |
1583 | hda_nid_t nid, nid_start; | 1622 | hda_nid_t nid; |
1584 | int nodes; | 1623 | int i; |
1585 | 1624 | ||
1586 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, | 1625 | snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE, |
1587 | power_state); | 1626 | power_state); |
1588 | 1627 | ||
1589 | nodes = snd_hda_get_sub_nodes(codec, fg, &nid_start); | 1628 | nid = codec->start_nid; |
1590 | for (nid = nid_start; nid < nodes + nid_start; nid++) { | 1629 | for (i = 0; i < codec->num_nodes; i++, nid++) { |
1591 | if (get_wcaps(codec, nid) & AC_WCAP_POWER) | 1630 | if (get_wcaps(codec, nid) & AC_WCAP_POWER) |
1592 | snd_hda_codec_write(codec, nid, 0, | 1631 | snd_hda_codec_write(codec, nid, 0, |
1593 | AC_VERB_SET_POWER_STATE, | 1632 | AC_VERB_SET_POWER_STATE, |
1594 | power_state); | 1633 | power_state); |
1595 | } | 1634 | } |
1596 | 1635 | ||
1597 | if (power_state == AC_PWRST_D0) | 1636 | if (power_state == AC_PWRST_D0) { |
1637 | unsigned long end_time; | ||
1638 | int state; | ||
1598 | msleep(10); | 1639 | msleep(10); |
1640 | /* wait until the codec reachs to D0 */ | ||
1641 | end_time = jiffies + msecs_to_jiffies(500); | ||
1642 | do { | ||
1643 | state = snd_hda_codec_read(codec, fg, 0, | ||
1644 | AC_VERB_GET_POWER_STATE, 0); | ||
1645 | if (state == power_state) | ||
1646 | break; | ||
1647 | msleep(1); | ||
1648 | } while (time_after_eq(end_time, jiffies)); | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | #ifdef SND_HDA_NEEDS_RESUME | ||
1653 | /* | ||
1654 | * call suspend and power-down; used both from PM and power-save | ||
1655 | */ | ||
1656 | static void hda_call_codec_suspend(struct hda_codec *codec) | ||
1657 | { | ||
1658 | if (codec->patch_ops.suspend) | ||
1659 | codec->patch_ops.suspend(codec, PMSG_SUSPEND); | ||
1660 | hda_set_power_state(codec, | ||
1661 | codec->afg ? codec->afg : codec->mfg, | ||
1662 | AC_PWRST_D3); | ||
1663 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
1664 | cancel_delayed_work(&codec->power_work); | ||
1665 | #endif | ||
1599 | } | 1666 | } |
1600 | 1667 | ||
1668 | /* | ||
1669 | * kick up codec; used both from PM and power-save | ||
1670 | */ | ||
1671 | static void hda_call_codec_resume(struct hda_codec *codec) | ||
1672 | { | ||
1673 | hda_set_power_state(codec, | ||
1674 | codec->afg ? codec->afg : codec->mfg, | ||
1675 | AC_PWRST_D0); | ||
1676 | if (codec->patch_ops.resume) | ||
1677 | codec->patch_ops.resume(codec); | ||
1678 | else { | ||
1679 | codec->patch_ops.init(codec); | ||
1680 | snd_hda_codec_resume_amp(codec); | ||
1681 | snd_hda_codec_resume_cache(codec); | ||
1682 | } | ||
1683 | } | ||
1684 | #endif /* SND_HDA_NEEDS_RESUME */ | ||
1685 | |||
1601 | 1686 | ||
1602 | /** | 1687 | /** |
1603 | * snd_hda_build_controls - build mixer controls | 1688 | * snd_hda_build_controls - build mixer controls |
@@ -1611,28 +1696,24 @@ int __devinit snd_hda_build_controls(struct hda_bus *bus) | |||
1611 | { | 1696 | { |
1612 | struct hda_codec *codec; | 1697 | struct hda_codec *codec; |
1613 | 1698 | ||
1614 | /* build controls */ | ||
1615 | list_for_each_entry(codec, &bus->codec_list, list) { | 1699 | list_for_each_entry(codec, &bus->codec_list, list) { |
1616 | int err; | 1700 | int err = 0; |
1617 | if (!codec->patch_ops.build_controls) | 1701 | /* fake as if already powered-on */ |
1618 | continue; | 1702 | hda_keep_power_on(codec); |
1619 | err = codec->patch_ops.build_controls(codec); | 1703 | /* then fire up */ |
1620 | if (err < 0) | ||
1621 | return err; | ||
1622 | } | ||
1623 | |||
1624 | /* initialize */ | ||
1625 | list_for_each_entry(codec, &bus->codec_list, list) { | ||
1626 | int err; | ||
1627 | hda_set_power_state(codec, | 1704 | hda_set_power_state(codec, |
1628 | codec->afg ? codec->afg : codec->mfg, | 1705 | codec->afg ? codec->afg : codec->mfg, |
1629 | AC_PWRST_D0); | 1706 | AC_PWRST_D0); |
1630 | if (!codec->patch_ops.init) | 1707 | /* continue to initialize... */ |
1631 | continue; | 1708 | if (codec->patch_ops.init) |
1632 | err = codec->patch_ops.init(codec); | 1709 | err = codec->patch_ops.init(codec); |
1710 | if (!err && codec->patch_ops.build_controls) | ||
1711 | err = codec->patch_ops.build_controls(codec); | ||
1712 | snd_hda_power_down(codec); | ||
1633 | if (err < 0) | 1713 | if (err < 0) |
1634 | return err; | 1714 | return err; |
1635 | } | 1715 | } |
1716 | |||
1636 | return 0; | 1717 | return 0; |
1637 | } | 1718 | } |
1638 | 1719 | ||
@@ -2078,7 +2159,7 @@ int snd_hda_check_board_config(struct hda_codec *codec, | |||
2078 | */ | 2159 | */ |
2079 | int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | 2160 | int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) |
2080 | { | 2161 | { |
2081 | int err; | 2162 | int err; |
2082 | 2163 | ||
2083 | for (; knew->name; knew++) { | 2164 | for (; knew->name; knew++) { |
2084 | struct snd_kcontrol *kctl; | 2165 | struct snd_kcontrol *kctl; |
@@ -2101,6 +2182,89 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | |||
2101 | return 0; | 2182 | return 0; |
2102 | } | 2183 | } |
2103 | 2184 | ||
2185 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
2186 | static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | ||
2187 | unsigned int power_state); | ||
2188 | |||
2189 | static void hda_power_work(struct work_struct *work) | ||
2190 | { | ||
2191 | struct hda_codec *codec = | ||
2192 | container_of(work, struct hda_codec, power_work.work); | ||
2193 | |||
2194 | if (!codec->power_on || codec->power_count) | ||
2195 | return; | ||
2196 | |||
2197 | hda_call_codec_suspend(codec); | ||
2198 | codec->power_on = 0; | ||
2199 | if (codec->bus->ops.pm_notify) | ||
2200 | codec->bus->ops.pm_notify(codec); | ||
2201 | } | ||
2202 | |||
2203 | static void hda_keep_power_on(struct hda_codec *codec) | ||
2204 | { | ||
2205 | codec->power_count++; | ||
2206 | codec->power_on = 1; | ||
2207 | } | ||
2208 | |||
2209 | void snd_hda_power_up(struct hda_codec *codec) | ||
2210 | { | ||
2211 | codec->power_count++; | ||
2212 | if (codec->power_on) | ||
2213 | return; | ||
2214 | |||
2215 | codec->power_on = 1; | ||
2216 | if (codec->bus->ops.pm_notify) | ||
2217 | codec->bus->ops.pm_notify(codec); | ||
2218 | hda_call_codec_resume(codec); | ||
2219 | cancel_delayed_work(&codec->power_work); | ||
2220 | } | ||
2221 | |||
2222 | void snd_hda_power_down(struct hda_codec *codec) | ||
2223 | { | ||
2224 | --codec->power_count; | ||
2225 | if (!codec->power_on) | ||
2226 | return; | ||
2227 | if (power_save) | ||
2228 | schedule_delayed_work(&codec->power_work, | ||
2229 | msecs_to_jiffies(power_save * 1000)); | ||
2230 | } | ||
2231 | |||
2232 | int snd_hda_check_amp_list_power(struct hda_codec *codec, | ||
2233 | struct hda_loopback_check *check, | ||
2234 | hda_nid_t nid) | ||
2235 | { | ||
2236 | struct hda_amp_list *p; | ||
2237 | int ch, v; | ||
2238 | |||
2239 | if (!check->amplist) | ||
2240 | return 0; | ||
2241 | for (p = check->amplist; p->nid; p++) { | ||
2242 | if (p->nid == nid) | ||
2243 | break; | ||
2244 | } | ||
2245 | if (!p->nid) | ||
2246 | return 0; /* nothing changed */ | ||
2247 | |||
2248 | for (p = check->amplist; p->nid; p++) { | ||
2249 | for (ch = 0; ch < 2; ch++) { | ||
2250 | v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, | ||
2251 | p->idx); | ||
2252 | if (!(v & HDA_AMP_MUTE) && v > 0) { | ||
2253 | if (!check->power_on) { | ||
2254 | check->power_on = 1; | ||
2255 | snd_hda_power_up(codec); | ||
2256 | } | ||
2257 | return 1; | ||
2258 | } | ||
2259 | } | ||
2260 | } | ||
2261 | if (check->power_on) { | ||
2262 | check->power_on = 0; | ||
2263 | snd_hda_power_down(codec); | ||
2264 | } | ||
2265 | return 0; | ||
2266 | } | ||
2267 | #endif | ||
2104 | 2268 | ||
2105 | /* | 2269 | /* |
2106 | * Channel mode helper | 2270 | * Channel mode helper |
@@ -2605,41 +2769,32 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) | |||
2605 | { | 2769 | { |
2606 | struct hda_codec *codec; | 2770 | struct hda_codec *codec; |
2607 | 2771 | ||
2608 | /* FIXME: should handle power widget capabilities */ | ||
2609 | list_for_each_entry(codec, &bus->codec_list, list) { | 2772 | list_for_each_entry(codec, &bus->codec_list, list) { |
2610 | if (codec->patch_ops.suspend) | 2773 | hda_call_codec_suspend(codec); |
2611 | codec->patch_ops.suspend(codec, state); | ||
2612 | hda_set_power_state(codec, | ||
2613 | codec->afg ? codec->afg : codec->mfg, | ||
2614 | AC_PWRST_D3); | ||
2615 | } | 2774 | } |
2616 | return 0; | 2775 | return 0; |
2617 | } | 2776 | } |
2618 | 2777 | ||
2778 | #ifndef CONFIG_SND_HDA_POWER_SAVE | ||
2619 | /** | 2779 | /** |
2620 | * snd_hda_resume - resume the codecs | 2780 | * snd_hda_resume - resume the codecs |
2621 | * @bus: the HDA bus | 2781 | * @bus: the HDA bus |
2622 | * @state: resume state | 2782 | * @state: resume state |
2623 | * | 2783 | * |
2624 | * Returns 0 if successful. | 2784 | * Returns 0 if successful. |
2785 | * | ||
2786 | * This fucntion is defined only when POWER_SAVE isn't set. | ||
2787 | * In the power-save mode, the codec is resumed dynamically. | ||
2625 | */ | 2788 | */ |
2626 | int snd_hda_resume(struct hda_bus *bus) | 2789 | int snd_hda_resume(struct hda_bus *bus) |
2627 | { | 2790 | { |
2628 | struct hda_codec *codec; | 2791 | struct hda_codec *codec; |
2629 | 2792 | ||
2630 | list_for_each_entry(codec, &bus->codec_list, list) { | 2793 | list_for_each_entry(codec, &bus->codec_list, list) { |
2631 | hda_set_power_state(codec, | 2794 | hda_call_codec_resume(codec); |
2632 | codec->afg ? codec->afg : codec->mfg, | ||
2633 | AC_PWRST_D0); | ||
2634 | if (codec->patch_ops.resume) | ||
2635 | codec->patch_ops.resume(codec); | ||
2636 | else { | ||
2637 | codec->patch_ops.init(codec); | ||
2638 | snd_hda_codec_resume_amp(codec); | ||
2639 | snd_hda_codec_resume_cache(codec); | ||
2640 | } | ||
2641 | } | 2795 | } |
2642 | return 0; | 2796 | return 0; |
2643 | } | 2797 | } |
2798 | #endif /* !CONFIG_SND_HDA_POWER_SAVE */ | ||
2644 | 2799 | ||
2645 | #endif | 2800 | #endif |