aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r--sound/pci/hda/hda_codec.c239
1 files changed, 197 insertions, 42 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 043529308676..9a3b72824f87 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 */
38static int power_save = 10;
39module_param(power_save, int, 0644);
40MODULE_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
71static void hda_power_work(struct work_struct *work);
72static void hda_keep_power_on(struct hda_codec *codec);
73#else
74static 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 */
860void snd_hda_codec_resume_amp(struct hda_codec *codec) 890void 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,
1580static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, 1619static 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 */
1656static 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 */
1671static 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 */
2079int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) 2160int 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
2186static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
2187 unsigned int power_state);
2188
2189static 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
2203static void hda_keep_power_on(struct hda_codec *codec)
2204{
2205 codec->power_count++;
2206 codec->power_on = 1;
2207}
2208
2209void 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
2222void 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
2232int 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 */
2626int snd_hda_resume(struct hda_bus *bus) 2789int 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