1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
24d75faa0STakashi Iwai /*
34d75faa0STakashi Iwai * HD-audio regmap helpers
44d75faa0STakashi Iwai */
54d75faa0STakashi Iwai
64d75faa0STakashi Iwai #ifndef __SOUND_HDA_REGMAP_H
74d75faa0STakashi Iwai #define __SOUND_HDA_REGMAP_H
84d75faa0STakashi Iwai
94d75faa0STakashi Iwai #include <linux/regmap.h>
104d75faa0STakashi Iwai #include <sound/core.h>
114d75faa0STakashi Iwai #include <sound/hdaudio.h>
124d75faa0STakashi Iwai
13a686ec4cSTakashi Iwai #define AC_AMP_FAKE_MUTE 0x10 /* fake mute bit set to amp verbs */
14a686ec4cSTakashi Iwai
154d75faa0STakashi Iwai int snd_hdac_regmap_init(struct hdac_device *codec);
164d75faa0STakashi Iwai void snd_hdac_regmap_exit(struct hdac_device *codec);
175e56bceaSTakashi Iwai int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
185e56bceaSTakashi Iwai unsigned int verb);
194d75faa0STakashi Iwai int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
204d75faa0STakashi Iwai unsigned int *val);
213194ed49STakashi Iwai int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec,
223194ed49STakashi Iwai unsigned int reg, unsigned int *val);
234d75faa0STakashi Iwai int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
244d75faa0STakashi Iwai unsigned int val);
254d75faa0STakashi Iwai int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
264d75faa0STakashi Iwai unsigned int mask, unsigned int val);
27*1a462be5STakashi Iwai int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg,
28*1a462be5STakashi Iwai unsigned int mask, unsigned int val);
29*1a462be5STakashi Iwai void snd_hdac_regmap_sync(struct hdac_device *codec);
304d75faa0STakashi Iwai
314d75faa0STakashi Iwai /**
324d75faa0STakashi Iwai * snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
334d75faa0STakashi Iwai * @nid: widget NID
344d75faa0STakashi Iwai * @verb: codec verb
354d75faa0STakashi Iwai *
364d75faa0STakashi Iwai * Returns an encoded pseudo register.
374d75faa0STakashi Iwai */
384d75faa0STakashi Iwai #define snd_hdac_regmap_encode_verb(nid, verb) \
394d75faa0STakashi Iwai (((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
404d75faa0STakashi Iwai
414d75faa0STakashi Iwai /**
424d75faa0STakashi Iwai * snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
434d75faa0STakashi Iwai * @nid: widget NID
444d75faa0STakashi Iwai * @ch: channel (left = 0, right = 1)
454d75faa0STakashi Iwai * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
464d75faa0STakashi Iwai * @idx: input index value
474d75faa0STakashi Iwai *
484d75faa0STakashi Iwai * Returns an encoded pseudo register.
494d75faa0STakashi Iwai */
504d75faa0STakashi Iwai #define snd_hdac_regmap_encode_amp(nid, ch, dir, idx) \
514d75faa0STakashi Iwai (snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
524d75faa0STakashi Iwai ((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) | \
534d75faa0STakashi Iwai ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
544d75faa0STakashi Iwai (idx))
554d75faa0STakashi Iwai
564d75faa0STakashi Iwai /**
57d313e0a8STakashi Iwai * snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
58d313e0a8STakashi Iwai * @nid: widget NID
59d313e0a8STakashi Iwai * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
60d313e0a8STakashi Iwai * @idx: input index value
61d313e0a8STakashi Iwai *
62d313e0a8STakashi Iwai * Returns an encoded pseudo register.
63d313e0a8STakashi Iwai */
64d313e0a8STakashi Iwai #define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx) \
65d313e0a8STakashi Iwai (snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
66d313e0a8STakashi Iwai AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */ \
67d313e0a8STakashi Iwai ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
68d313e0a8STakashi Iwai (idx))
69d313e0a8STakashi Iwai
70d313e0a8STakashi Iwai /**
714d75faa0STakashi Iwai * snd_hdac_regmap_write - Write a verb with caching
724d75faa0STakashi Iwai * @nid: codec NID
734d75faa0STakashi Iwai * @reg: verb to write
744d75faa0STakashi Iwai * @val: value to write
754d75faa0STakashi Iwai *
76b7631a12STakashi Iwai * For writing an amp value, use snd_hdac_regmap_update_amp().
774d75faa0STakashi Iwai */
784d75faa0STakashi Iwai static inline int
snd_hdac_regmap_write(struct hdac_device * codec,hda_nid_t nid,unsigned int verb,unsigned int val)794d75faa0STakashi Iwai snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
804d75faa0STakashi Iwai unsigned int verb, unsigned int val)
814d75faa0STakashi Iwai {
824d75faa0STakashi Iwai unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
834d75faa0STakashi Iwai
844d75faa0STakashi Iwai return snd_hdac_regmap_write_raw(codec, cmd, val);
854d75faa0STakashi Iwai }
864d75faa0STakashi Iwai
874d75faa0STakashi Iwai /**
884d75faa0STakashi Iwai * snd_hda_regmap_update - Update a verb value with caching
894d75faa0STakashi Iwai * @nid: codec NID
904d75faa0STakashi Iwai * @verb: verb to update
914d75faa0STakashi Iwai * @mask: bit mask to update
924d75faa0STakashi Iwai * @val: value to update
934d75faa0STakashi Iwai *
94b7631a12STakashi Iwai * For updating an amp value, use snd_hdac_regmap_update_amp().
954d75faa0STakashi Iwai */
964d75faa0STakashi Iwai static inline int
snd_hdac_regmap_update(struct hdac_device * codec,hda_nid_t nid,unsigned int verb,unsigned int mask,unsigned int val)974d75faa0STakashi Iwai snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
984d75faa0STakashi Iwai unsigned int verb, unsigned int mask,
994d75faa0STakashi Iwai unsigned int val)
1004d75faa0STakashi Iwai {
1014d75faa0STakashi Iwai unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
1024d75faa0STakashi Iwai
1034d75faa0STakashi Iwai return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
1044d75faa0STakashi Iwai }
1054d75faa0STakashi Iwai
1064d75faa0STakashi Iwai /**
1074d75faa0STakashi Iwai * snd_hda_regmap_read - Read a verb with caching
1084d75faa0STakashi Iwai * @nid: codec NID
1094d75faa0STakashi Iwai * @verb: verb to read
1104d75faa0STakashi Iwai * @val: pointer to store the value
1114d75faa0STakashi Iwai *
1124d75faa0STakashi Iwai * For reading an amp value, use snd_hda_regmap_get_amp().
1134d75faa0STakashi Iwai */
1144d75faa0STakashi Iwai static inline int
snd_hdac_regmap_read(struct hdac_device * codec,hda_nid_t nid,unsigned int verb,unsigned int * val)1154d75faa0STakashi Iwai snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
1164d75faa0STakashi Iwai unsigned int verb, unsigned int *val)
1174d75faa0STakashi Iwai {
1184d75faa0STakashi Iwai unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
1194d75faa0STakashi Iwai
1204d75faa0STakashi Iwai return snd_hdac_regmap_read_raw(codec, cmd, val);
1214d75faa0STakashi Iwai }
1224d75faa0STakashi Iwai
1234d75faa0STakashi Iwai /**
1244d75faa0STakashi Iwai * snd_hdac_regmap_get_amp - Read AMP value
1254d75faa0STakashi Iwai * @codec: HD-audio codec
1264d75faa0STakashi Iwai * @nid: NID to read the AMP value
1274d75faa0STakashi Iwai * @ch: channel (left=0 or right=1)
1284d75faa0STakashi Iwai * @direction: #HDA_INPUT or #HDA_OUTPUT
1294d75faa0STakashi Iwai * @index: the index value (only for input direction)
1304d75faa0STakashi Iwai * @val: the pointer to store the value
1314d75faa0STakashi Iwai *
1324d75faa0STakashi Iwai * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
1334d75faa0STakashi Iwai * Returns the value or a negative error.
1344d75faa0STakashi Iwai */
1354d75faa0STakashi Iwai static inline int
snd_hdac_regmap_get_amp(struct hdac_device * codec,hda_nid_t nid,int ch,int dir,int idx)1364d75faa0STakashi Iwai snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
1374d75faa0STakashi Iwai int ch, int dir, int idx)
1384d75faa0STakashi Iwai {
1394d75faa0STakashi Iwai unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
1404d75faa0STakashi Iwai int err, val;
1414d75faa0STakashi Iwai
1424d75faa0STakashi Iwai err = snd_hdac_regmap_read_raw(codec, cmd, &val);
1434d75faa0STakashi Iwai return err < 0 ? err : val;
1444d75faa0STakashi Iwai }
1454d75faa0STakashi Iwai
1464d75faa0STakashi Iwai /**
1474d75faa0STakashi Iwai * snd_hdac_regmap_update_amp - update the AMP value
1484d75faa0STakashi Iwai * @codec: HD-audio codec
1494d75faa0STakashi Iwai * @nid: NID to read the AMP value
1504d75faa0STakashi Iwai * @ch: channel (left=0 or right=1)
1514d75faa0STakashi Iwai * @direction: #HDA_INPUT or #HDA_OUTPUT
1524d75faa0STakashi Iwai * @idx: the index value (only for input direction)
1534d75faa0STakashi Iwai * @mask: bit mask to set
1544d75faa0STakashi Iwai * @val: the bits value to set
1554d75faa0STakashi Iwai *
1564d75faa0STakashi Iwai * Update the AMP value with a bit mask.
1574d75faa0STakashi Iwai * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
1584d75faa0STakashi Iwai */
1594d75faa0STakashi Iwai static inline int
snd_hdac_regmap_update_amp(struct hdac_device * codec,hda_nid_t nid,int ch,int dir,int idx,int mask,int val)1604d75faa0STakashi Iwai snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
1614d75faa0STakashi Iwai int ch, int dir, int idx, int mask, int val)
1624d75faa0STakashi Iwai {
1634d75faa0STakashi Iwai unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
1644d75faa0STakashi Iwai
1654d75faa0STakashi Iwai return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
1664d75faa0STakashi Iwai }
1674d75faa0STakashi Iwai
168d313e0a8STakashi Iwai /**
169d313e0a8STakashi Iwai * snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
170d313e0a8STakashi Iwai * @codec: HD-audio codec
171d313e0a8STakashi Iwai * @nid: NID to read the AMP value
172d313e0a8STakashi Iwai * @ch: channel (left=0 or right=1)
173d313e0a8STakashi Iwai * @direction: #HDA_INPUT or #HDA_OUTPUT
174d313e0a8STakashi Iwai * @index: the index value (only for input direction)
175d313e0a8STakashi Iwai * @val: the pointer to store the value
176d313e0a8STakashi Iwai *
177d313e0a8STakashi Iwai * Read stereo AMP values. The lower byte is left, the upper byte is right.
178d313e0a8STakashi Iwai * Returns the value or a negative error.
179d313e0a8STakashi Iwai */
180d313e0a8STakashi Iwai static inline int
snd_hdac_regmap_get_amp_stereo(struct hdac_device * codec,hda_nid_t nid,int dir,int idx)181d313e0a8STakashi Iwai snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
182d313e0a8STakashi Iwai int dir, int idx)
183d313e0a8STakashi Iwai {
184d313e0a8STakashi Iwai unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
185d313e0a8STakashi Iwai int err, val;
186d313e0a8STakashi Iwai
187d313e0a8STakashi Iwai err = snd_hdac_regmap_read_raw(codec, cmd, &val);
188d313e0a8STakashi Iwai return err < 0 ? err : val;
189d313e0a8STakashi Iwai }
190d313e0a8STakashi Iwai
191d313e0a8STakashi Iwai /**
192d313e0a8STakashi Iwai * snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
193d313e0a8STakashi Iwai * @codec: HD-audio codec
194d313e0a8STakashi Iwai * @nid: NID to read the AMP value
195d313e0a8STakashi Iwai * @direction: #HDA_INPUT or #HDA_OUTPUT
196d313e0a8STakashi Iwai * @idx: the index value (only for input direction)
197d313e0a8STakashi Iwai * @mask: bit mask to set
198d313e0a8STakashi Iwai * @val: the bits value to set
199d313e0a8STakashi Iwai *
200d313e0a8STakashi Iwai * Update the stereo AMP value with a bit mask.
201d313e0a8STakashi Iwai * The lower byte is left, the upper byte is right.
202d313e0a8STakashi Iwai * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
203d313e0a8STakashi Iwai */
204d313e0a8STakashi Iwai static inline int
snd_hdac_regmap_update_amp_stereo(struct hdac_device * codec,hda_nid_t nid,int dir,int idx,int mask,int val)205d313e0a8STakashi Iwai snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
206d313e0a8STakashi Iwai int dir, int idx, int mask, int val)
207d313e0a8STakashi Iwai {
208d313e0a8STakashi Iwai unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
209d313e0a8STakashi Iwai
210d313e0a8STakashi Iwai return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
211d313e0a8STakashi Iwai }
212d313e0a8STakashi Iwai
213d545a57cSTakashi Iwai /**
214d545a57cSTakashi Iwai * snd_hdac_regmap_sync_node - sync the widget node attributes
215d545a57cSTakashi Iwai * @codec: HD-audio codec
216d545a57cSTakashi Iwai * @nid: NID to sync
217d545a57cSTakashi Iwai */
218d545a57cSTakashi Iwai static inline void
snd_hdac_regmap_sync_node(struct hdac_device * codec,hda_nid_t nid)219d545a57cSTakashi Iwai snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid)
220d545a57cSTakashi Iwai {
221d545a57cSTakashi Iwai regcache_mark_dirty(codec->regmap);
222d545a57cSTakashi Iwai regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1);
223d545a57cSTakashi Iwai }
224d545a57cSTakashi Iwai
2254d75faa0STakashi Iwai #endif /* __SOUND_HDA_REGMAP_H */
226