diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 215 | ||||
-rw-r--r-- | sound/pci/hda/hda_local.h | 10 | ||||
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 4 |
4 files changed, 32 insertions, 199 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 39b5660653f0..52962f697825 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -1543,139 +1543,6 @@ int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, | |||
1543 | } | 1543 | } |
1544 | EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps); | 1544 | EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps); |
1545 | 1545 | ||
1546 | /* read or sync the hash value with the current value; | ||
1547 | * call within hash_mutex | ||
1548 | */ | ||
1549 | static struct hda_amp_info * | ||
1550 | update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, | ||
1551 | int direction, int index, bool init_only) | ||
1552 | { | ||
1553 | struct hda_amp_info *info; | ||
1554 | unsigned int parm, val = 0; | ||
1555 | bool val_read = false; | ||
1556 | |||
1557 | retry: | ||
1558 | info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); | ||
1559 | if (!info) | ||
1560 | return NULL; | ||
1561 | if (!(info->head.val & INFO_AMP_VOL(ch))) { | ||
1562 | if (!val_read) { | ||
1563 | mutex_unlock(&codec->hash_mutex); | ||
1564 | parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; | ||
1565 | parm |= direction == HDA_OUTPUT ? | ||
1566 | AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; | ||
1567 | parm |= index; | ||
1568 | val = snd_hda_codec_read(codec, nid, 0, | ||
1569 | AC_VERB_GET_AMP_GAIN_MUTE, parm); | ||
1570 | val &= 0xff; | ||
1571 | val_read = true; | ||
1572 | mutex_lock(&codec->hash_mutex); | ||
1573 | goto retry; | ||
1574 | } | ||
1575 | info->vol[ch] = val; | ||
1576 | info->head.val |= INFO_AMP_VOL(ch); | ||
1577 | } else if (init_only) | ||
1578 | return NULL; | ||
1579 | return info; | ||
1580 | } | ||
1581 | |||
1582 | /* | ||
1583 | * write the current volume in info to the h/w | ||
1584 | */ | ||
1585 | static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps, | ||
1586 | hda_nid_t nid, int ch, int direction, int index, | ||
1587 | int val) | ||
1588 | { | ||
1589 | u32 parm; | ||
1590 | |||
1591 | parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; | ||
1592 | parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; | ||
1593 | parm |= index << AC_AMP_SET_INDEX_SHIFT; | ||
1594 | if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) && | ||
1595 | (amp_caps & AC_AMPCAP_MIN_MUTE)) | ||
1596 | ; /* set the zero value as a fake mute */ | ||
1597 | else | ||
1598 | parm |= val; | ||
1599 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); | ||
1600 | } | ||
1601 | |||
1602 | /** | ||
1603 | * snd_hda_codec_amp_read - Read AMP value | ||
1604 | * @codec: HD-audio codec | ||
1605 | * @nid: NID to read the AMP value | ||
1606 | * @ch: channel (left=0 or right=1) | ||
1607 | * @direction: #HDA_INPUT or #HDA_OUTPUT | ||
1608 | * @index: the index value (only for input direction) | ||
1609 | * | ||
1610 | * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. | ||
1611 | */ | ||
1612 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, | ||
1613 | int direction, int index) | ||
1614 | { | ||
1615 | struct hda_amp_info *info; | ||
1616 | unsigned int val = 0; | ||
1617 | |||
1618 | mutex_lock(&codec->hash_mutex); | ||
1619 | info = update_amp_hash(codec, nid, ch, direction, index, false); | ||
1620 | if (info) | ||
1621 | val = info->vol[ch]; | ||
1622 | mutex_unlock(&codec->hash_mutex); | ||
1623 | return val; | ||
1624 | } | ||
1625 | EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read); | ||
1626 | |||
1627 | static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | ||
1628 | int direction, int idx, int mask, int val, | ||
1629 | bool init_only, bool cache_only) | ||
1630 | { | ||
1631 | struct hda_amp_info *info; | ||
1632 | unsigned int caps; | ||
1633 | |||
1634 | if (snd_BUG_ON(mask & ~0xff)) | ||
1635 | mask &= 0xff; | ||
1636 | val &= mask; | ||
1637 | |||
1638 | mutex_lock(&codec->hash_mutex); | ||
1639 | info = update_amp_hash(codec, nid, ch, direction, idx, init_only); | ||
1640 | if (!info) { | ||
1641 | mutex_unlock(&codec->hash_mutex); | ||
1642 | return 0; | ||
1643 | } | ||
1644 | val |= info->vol[ch] & ~mask; | ||
1645 | if (info->vol[ch] == val) { | ||
1646 | mutex_unlock(&codec->hash_mutex); | ||
1647 | return 0; | ||
1648 | } | ||
1649 | info->vol[ch] = val; | ||
1650 | info->head.dirty |= cache_only; | ||
1651 | caps = info->amp_caps; | ||
1652 | mutex_unlock(&codec->hash_mutex); | ||
1653 | if (!cache_only) | ||
1654 | put_vol_mute(codec, caps, nid, ch, direction, idx, val); | ||
1655 | return 1; | ||
1656 | } | ||
1657 | |||
1658 | /** | ||
1659 | * snd_hda_codec_amp_update - update the AMP value | ||
1660 | * @codec: HD-audio codec | ||
1661 | * @nid: NID to read the AMP value | ||
1662 | * @ch: channel (left=0 or right=1) | ||
1663 | * @direction: #HDA_INPUT or #HDA_OUTPUT | ||
1664 | * @idx: the index value (only for input direction) | ||
1665 | * @mask: bit mask to set | ||
1666 | * @val: the bits value to set | ||
1667 | * | ||
1668 | * Update the AMP value with a bit mask. | ||
1669 | * Returns 0 if the value is unchanged, 1 if changed. | ||
1670 | */ | ||
1671 | int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | ||
1672 | int direction, int idx, int mask, int val) | ||
1673 | { | ||
1674 | return codec_amp_update(codec, nid, ch, direction, idx, mask, val, | ||
1675 | false, codec->cached_write); | ||
1676 | } | ||
1677 | EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); | ||
1678 | |||
1679 | /** | 1546 | /** |
1680 | * snd_hda_codec_amp_stereo - update the AMP stereo values | 1547 | * snd_hda_codec_amp_stereo - update the AMP stereo values |
1681 | * @codec: HD-audio codec | 1548 | * @codec: HD-audio codec |
@@ -1719,8 +1586,16 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); | |||
1719 | int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, | 1586 | int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, |
1720 | int dir, int idx, int mask, int val) | 1587 | int dir, int idx, int mask, int val) |
1721 | { | 1588 | { |
1722 | return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true, | 1589 | int orig; |
1723 | codec->cached_write); | 1590 | |
1591 | if (!codec->core.regmap) | ||
1592 | return -EINVAL; | ||
1593 | regcache_cache_only(codec->core.regmap, true); | ||
1594 | orig = snd_hda_codec_amp_read(codec, nid, ch, dir, idx); | ||
1595 | regcache_cache_only(codec->core.regmap, false); | ||
1596 | if (orig >= 0) | ||
1597 | return 0; | ||
1598 | return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val); | ||
1724 | } | 1599 | } |
1725 | EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init); | 1600 | EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init); |
1726 | 1601 | ||
@@ -1749,49 +1624,6 @@ int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, | |||
1749 | } | 1624 | } |
1750 | EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo); | 1625 | EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo); |
1751 | 1626 | ||
1752 | /** | ||
1753 | * snd_hda_codec_resume_amp - Resume all AMP commands from the cache | ||
1754 | * @codec: HD-audio codec | ||
1755 | * | ||
1756 | * Resume the all amp commands from the cache. | ||
1757 | */ | ||
1758 | void snd_hda_codec_resume_amp(struct hda_codec *codec) | ||
1759 | { | ||
1760 | int i; | ||
1761 | |||
1762 | mutex_lock(&codec->hash_mutex); | ||
1763 | codec->cached_write = 0; | ||
1764 | for (i = 0; i < codec->amp_cache.buf.used; i++) { | ||
1765 | struct hda_amp_info *buffer; | ||
1766 | u32 key; | ||
1767 | hda_nid_t nid; | ||
1768 | unsigned int idx, dir, ch; | ||
1769 | struct hda_amp_info info; | ||
1770 | |||
1771 | buffer = snd_array_elem(&codec->amp_cache.buf, i); | ||
1772 | if (!buffer->head.dirty) | ||
1773 | continue; | ||
1774 | buffer->head.dirty = 0; | ||
1775 | info = *buffer; | ||
1776 | key = info.head.key; | ||
1777 | if (!key) | ||
1778 | continue; | ||
1779 | nid = key & 0xff; | ||
1780 | idx = (key >> 16) & 0xff; | ||
1781 | dir = (key >> 24) & 0xff; | ||
1782 | for (ch = 0; ch < 2; ch++) { | ||
1783 | if (!(info.head.val & INFO_AMP_VOL(ch))) | ||
1784 | continue; | ||
1785 | mutex_unlock(&codec->hash_mutex); | ||
1786 | put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx, | ||
1787 | info.vol[ch]); | ||
1788 | mutex_lock(&codec->hash_mutex); | ||
1789 | } | ||
1790 | } | ||
1791 | mutex_unlock(&codec->hash_mutex); | ||
1792 | } | ||
1793 | EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp); | ||
1794 | |||
1795 | static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, | 1627 | static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, |
1796 | unsigned int ofs) | 1628 | unsigned int ofs) |
1797 | { | 1629 | { |
@@ -1862,8 +1694,8 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, | |||
1862 | maxval = get_amp_max_value(codec, nid, dir, 0); | 1694 | maxval = get_amp_max_value(codec, nid, dir, 0); |
1863 | if (val > maxval) | 1695 | if (val > maxval) |
1864 | val = maxval; | 1696 | val = maxval; |
1865 | return codec_amp_update(codec, nid, ch, dir, idx, HDA_AMP_VOLMASK, val, | 1697 | return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, |
1866 | false, !hda_codec_is_power_on(codec)); | 1698 | HDA_AMP_VOLMASK, val); |
1867 | } | 1699 | } |
1868 | 1700 | ||
1869 | /** | 1701 | /** |
@@ -2546,17 +2378,15 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, | |||
2546 | int change = 0; | 2378 | int change = 0; |
2547 | 2379 | ||
2548 | if (chs & 1) { | 2380 | if (chs & 1) { |
2549 | change = codec_amp_update(codec, nid, 0, dir, idx, | 2381 | change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx, |
2550 | HDA_AMP_MUTE, | 2382 | HDA_AMP_MUTE, |
2551 | *valp ? 0 : HDA_AMP_MUTE, false, | 2383 | *valp ? 0 : HDA_AMP_MUTE); |
2552 | !hda_codec_is_power_on(codec)); | ||
2553 | valp++; | 2384 | valp++; |
2554 | } | 2385 | } |
2555 | if (chs & 2) | 2386 | if (chs & 2) |
2556 | change |= codec_amp_update(codec, nid, 1, dir, idx, | 2387 | change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx, |
2557 | HDA_AMP_MUTE, | 2388 | HDA_AMP_MUTE, |
2558 | *valp ? 0 : HDA_AMP_MUTE, false, | 2389 | *valp ? 0 : HDA_AMP_MUTE); |
2559 | !hda_codec_is_power_on(codec)); | ||
2560 | hda_call_check_power_status(codec, nid); | 2390 | hda_call_check_power_status(codec, nid); |
2561 | return change; | 2391 | return change; |
2562 | } | 2392 | } |
@@ -3417,7 +3247,8 @@ EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache); | |||
3417 | */ | 3247 | */ |
3418 | void snd_hda_codec_flush_cache(struct hda_codec *codec) | 3248 | void snd_hda_codec_flush_cache(struct hda_codec *codec) |
3419 | { | 3249 | { |
3420 | snd_hda_codec_resume_amp(codec); | 3250 | if (codec->core.regmap) |
3251 | regcache_sync(codec->core.regmap); | ||
3421 | snd_hda_codec_resume_cache(codec); | 3252 | snd_hda_codec_resume_cache(codec); |
3422 | } | 3253 | } |
3423 | EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache); | 3254 | EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache); |
@@ -3645,6 +3476,9 @@ static void hda_call_codec_resume(struct hda_codec *codec) | |||
3645 | { | 3476 | { |
3646 | atomic_inc(&codec->core.in_pm); | 3477 | atomic_inc(&codec->core.in_pm); |
3647 | 3478 | ||
3479 | if (codec->core.regmap) | ||
3480 | regcache_mark_dirty(codec->core.regmap); | ||
3481 | |||
3648 | hda_mark_cmd_cache_dirty(codec); | 3482 | hda_mark_cmd_cache_dirty(codec); |
3649 | 3483 | ||
3650 | codec->power_jiffies = jiffies; | 3484 | codec->power_jiffies = jiffies; |
@@ -3658,7 +3492,8 @@ static void hda_call_codec_resume(struct hda_codec *codec) | |||
3658 | else { | 3492 | else { |
3659 | if (codec->patch_ops.init) | 3493 | if (codec->patch_ops.init) |
3660 | codec->patch_ops.init(codec); | 3494 | codec->patch_ops.init(codec); |
3661 | snd_hda_codec_resume_amp(codec); | 3495 | if (codec->core.regmap) |
3496 | regcache_sync(codec->core.regmap); | ||
3662 | snd_hda_codec_resume_cache(codec); | 3497 | snd_hda_codec_resume_cache(codec); |
3663 | } | 3498 | } |
3664 | 3499 | ||
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8a83775e0e27..7023eeee8b9d 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
@@ -127,18 +127,16 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, | |||
127 | struct snd_ctl_elem_value *ucontrol); | 127 | struct snd_ctl_elem_value *ucontrol); |
128 | #endif | 128 | #endif |
129 | /* lowlevel accessor with caching; use carefully */ | 129 | /* lowlevel accessor with caching; use carefully */ |
130 | int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, | 130 | #define snd_hda_codec_amp_read(codec, nid, ch, dir, idx) \ |
131 | int direction, int index); | 131 | snd_hdac_regmap_get_amp(&(codec)->core, nid, ch, dir, idx) |
132 | int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, | 132 | #define snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val) \ |
133 | int direction, int idx, int mask, int val); | 133 | snd_hdac_regmap_update_amp(&(codec)->core, nid, ch, dir, idx, mask, val) |
134 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, | 134 | int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, |
135 | int dir, int idx, int mask, int val); | 135 | int dir, int idx, int mask, int val); |
136 | int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, | 136 | int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, |
137 | int direction, int idx, int mask, int val); | 137 | int direction, int idx, int mask, int val); |
138 | int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, | 138 | int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, |
139 | int dir, int idx, int mask, int val); | 139 | int dir, int idx, int mask, int val); |
140 | void snd_hda_codec_resume_amp(struct hda_codec *codec); | ||
141 | |||
142 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | 140 | void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, |
143 | unsigned int *tlv); | 141 | unsigned int *tlv); |
144 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | 142 | struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 35d92a8a99ce..04c5ab20eb76 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -2211,7 +2211,7 @@ static int generic_hdmi_resume(struct hda_codec *codec) | |||
2211 | int pin_idx; | 2211 | int pin_idx; |
2212 | 2212 | ||
2213 | codec->patch_ops.init(codec); | 2213 | codec->patch_ops.init(codec); |
2214 | snd_hda_codec_resume_amp(codec); | 2214 | regcache_sync(codec->core.regmap); |
2215 | snd_hda_codec_resume_cache(codec); | 2215 | snd_hda_codec_resume_cache(codec); |
2216 | 2216 | ||
2217 | for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { | 2217 | for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index eee4532ab5f6..a440e539230f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -799,7 +799,7 @@ static int alc_resume(struct hda_codec *codec) | |||
799 | if (!spec->no_depop_delay) | 799 | if (!spec->no_depop_delay) |
800 | msleep(150); /* to avoid pop noise */ | 800 | msleep(150); /* to avoid pop noise */ |
801 | codec->patch_ops.init(codec); | 801 | codec->patch_ops.init(codec); |
802 | snd_hda_codec_resume_amp(codec); | 802 | regcache_sync(codec->core.regmap); |
803 | snd_hda_codec_resume_cache(codec); | 803 | snd_hda_codec_resume_cache(codec); |
804 | hda_call_check_power_status(codec, 0x01); | 804 | hda_call_check_power_status(codec, 0x01); |
805 | return 0; | 805 | return 0; |
@@ -3058,7 +3058,7 @@ static int alc269_resume(struct hda_codec *codec) | |||
3058 | msleep(200); | 3058 | msleep(200); |
3059 | } | 3059 | } |
3060 | 3060 | ||
3061 | snd_hda_codec_resume_amp(codec); | 3061 | regcache_sync(codec->core.regmap); |
3062 | snd_hda_codec_resume_cache(codec); | 3062 | snd_hda_codec_resume_cache(codec); |
3063 | hda_call_check_power_status(codec, 0x01); | 3063 | hda_call_check_power_status(codec, 0x01); |
3064 | 3064 | ||