Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 /*
0003  * HD-audio regmap helpers
0004  */
0005 
0006 #ifndef __SOUND_HDA_REGMAP_H
0007 #define __SOUND_HDA_REGMAP_H
0008 
0009 #include <linux/regmap.h>
0010 #include <sound/core.h>
0011 #include <sound/hdaudio.h>
0012 
0013 #define AC_AMP_FAKE_MUTE    0x10    /* fake mute bit set to amp verbs */
0014 
0015 int snd_hdac_regmap_init(struct hdac_device *codec);
0016 void snd_hdac_regmap_exit(struct hdac_device *codec);
0017 int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
0018                     unsigned int verb);
0019 int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
0020                  unsigned int *val);
0021 int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec,
0022                       unsigned int reg, unsigned int *val);
0023 int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
0024                   unsigned int val);
0025 int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
0026                    unsigned int mask, unsigned int val);
0027 int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg,
0028                     unsigned int mask, unsigned int val);
0029 void snd_hdac_regmap_sync(struct hdac_device *codec);
0030 
0031 /**
0032  * snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
0033  * @nid: widget NID
0034  * @verb: codec verb
0035  *
0036  * Returns an encoded pseudo register.
0037  */
0038 #define snd_hdac_regmap_encode_verb(nid, verb)      \
0039     (((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
0040 
0041 /**
0042  * snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
0043  * @nid: widget NID
0044  * @ch: channel (left = 0, right = 1)
0045  * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
0046  * @idx: input index value
0047  *
0048  * Returns an encoded pseudo register.
0049  */
0050 #define snd_hdac_regmap_encode_amp(nid, ch, dir, idx)           \
0051     (snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |  \
0052      ((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) |          \
0053      ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
0054      (idx))
0055 
0056 /**
0057  * snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
0058  * @nid: widget NID
0059  * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
0060  * @idx: input index value
0061  *
0062  * Returns an encoded pseudo register.
0063  */
0064 #define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx)        \
0065     (snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) |  \
0066      AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */  \
0067      ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
0068      (idx))
0069 
0070 /**
0071  * snd_hdac_regmap_write - Write a verb with caching
0072  * @nid: codec NID
0073  * @reg: verb to write
0074  * @val: value to write
0075  *
0076  * For writing an amp value, use snd_hdac_regmap_update_amp().
0077  */
0078 static inline int
0079 snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
0080               unsigned int verb, unsigned int val)
0081 {
0082     unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
0083 
0084     return snd_hdac_regmap_write_raw(codec, cmd, val);
0085 }
0086 
0087 /**
0088  * snd_hda_regmap_update - Update a verb value with caching
0089  * @nid: codec NID
0090  * @verb: verb to update
0091  * @mask: bit mask to update
0092  * @val: value to update
0093  *
0094  * For updating an amp value, use snd_hdac_regmap_update_amp().
0095  */
0096 static inline int
0097 snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
0098                unsigned int verb, unsigned int mask,
0099                unsigned int val)
0100 {
0101     unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
0102 
0103     return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
0104 }
0105 
0106 /**
0107  * snd_hda_regmap_read - Read a verb with caching
0108  * @nid: codec NID
0109  * @verb: verb to read
0110  * @val: pointer to store the value
0111  *
0112  * For reading an amp value, use snd_hda_regmap_get_amp().
0113  */
0114 static inline int
0115 snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
0116              unsigned int verb, unsigned int *val)
0117 {
0118     unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
0119 
0120     return snd_hdac_regmap_read_raw(codec, cmd, val);
0121 }
0122 
0123 /**
0124  * snd_hdac_regmap_get_amp - Read AMP value
0125  * @codec: HD-audio codec
0126  * @nid: NID to read the AMP value
0127  * @ch: channel (left=0 or right=1)
0128  * @direction: #HDA_INPUT or #HDA_OUTPUT
0129  * @index: the index value (only for input direction)
0130  * @val: the pointer to store the value
0131  *
0132  * Read AMP value.  The volume is between 0 to 0x7f, 0x80 = mute bit.
0133  * Returns the value or a negative error.
0134  */
0135 static inline int
0136 snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
0137             int ch, int dir, int idx)
0138 {
0139     unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
0140     int err, val;
0141 
0142     err = snd_hdac_regmap_read_raw(codec, cmd, &val);
0143     return err < 0 ? err : val;
0144 }
0145 
0146 /**
0147  * snd_hdac_regmap_update_amp - update the AMP value
0148  * @codec: HD-audio codec
0149  * @nid: NID to read the AMP value
0150  * @ch: channel (left=0 or right=1)
0151  * @direction: #HDA_INPUT or #HDA_OUTPUT
0152  * @idx: the index value (only for input direction)
0153  * @mask: bit mask to set
0154  * @val: the bits value to set
0155  *
0156  * Update the AMP value with a bit mask.
0157  * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
0158  */
0159 static inline int
0160 snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
0161                int ch, int dir, int idx, int mask, int val)
0162 {
0163     unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
0164 
0165     return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
0166 }
0167 
0168 /**
0169  * snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
0170  * @codec: HD-audio codec
0171  * @nid: NID to read the AMP value
0172  * @ch: channel (left=0 or right=1)
0173  * @direction: #HDA_INPUT or #HDA_OUTPUT
0174  * @index: the index value (only for input direction)
0175  * @val: the pointer to store the value
0176  *
0177  * Read stereo AMP values.  The lower byte is left, the upper byte is right.
0178  * Returns the value or a negative error.
0179  */
0180 static inline int
0181 snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
0182                    int dir, int idx)
0183 {
0184     unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
0185     int err, val;
0186 
0187     err = snd_hdac_regmap_read_raw(codec, cmd, &val);
0188     return err < 0 ? err : val;
0189 }
0190 
0191 /**
0192  * snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
0193  * @codec: HD-audio codec
0194  * @nid: NID to read the AMP value
0195  * @direction: #HDA_INPUT or #HDA_OUTPUT
0196  * @idx: the index value (only for input direction)
0197  * @mask: bit mask to set
0198  * @val: the bits value to set
0199  *
0200  * Update the stereo AMP value with a bit mask.
0201  * The lower byte is left, the upper byte is right.
0202  * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
0203  */
0204 static inline int
0205 snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
0206                   int dir, int idx, int mask, int val)
0207 {
0208     unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
0209 
0210     return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
0211 }
0212 
0213 /**
0214  * snd_hdac_regmap_sync_node - sync the widget node attributes
0215  * @codec: HD-audio codec
0216  * @nid: NID to sync
0217  */
0218 static inline void
0219 snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid)
0220 {
0221     regcache_mark_dirty(codec->regmap);
0222     regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1);
0223 }
0224 
0225 #endif /* __SOUND_HDA_REGMAP_H */