aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-02-25 09:18:50 -0500
committerTakashi Iwai <tiwai@suse.de>2015-03-23 08:19:39 -0400
commiteeecd9d10d3da0b9efd6f58fad55c4355dcc246a (patch)
tree8a664234ab300d8275d9d1acc604f52b5c7d0270 /sound/pci
parent9ba17b4d132f56a680fa1ba0bc2a8f98b6263d93 (diff)
ALSA: hda - Use regmap for amp accesses
This patch converts the amp access functions to the regmap helpers. The amp values were formerly cached in the own hash table. Now it's dropped by the regmap's cache. The only tricky conversion is snd_hda_codec_amp_init(). This function shouldn't do anything if the amp was already initialized. For achieving this behavior, a value is read once at first temporarily in the cache-only mode. Only if it returns an error, i.e. the item still doesn't exist in the cache, it proceeds to the update. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_codec.c215
-rw-r--r--sound/pci/hda/hda_local.h10
-rw-r--r--sound/pci/hda/patch_hdmi.c2
-rw-r--r--sound/pci/hda/patch_realtek.c4
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}
1544EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps); 1544EXPORT_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 */
1549static struct hda_amp_info *
1550update_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 */
1585static 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 */
1612int 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}
1625EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read);
1626
1627static 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 */
1671int 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}
1677EXPORT_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);
1719int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, 1586int 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}
1725EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init); 1600EXPORT_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}
1750EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo); 1625EXPORT_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 */
1758void 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}
1793EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp);
1794
1795static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, 1627static 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 */
3418void snd_hda_codec_flush_cache(struct hda_codec *codec) 3248void 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}
3423EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache); 3254EXPORT_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 */
130int 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)
132int 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)
134int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, 134int 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);
136int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, 136int 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);
138int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, 138int 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);
140void snd_hda_codec_resume_amp(struct hda_codec *codec);
141
142void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, 140void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir,
143 unsigned int *tlv); 141 unsigned int *tlv);
144struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, 142struct 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