Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */
2 : : /*
3 : : * HD-audio regmap helpers
4 : : */
5 : :
6 : : #ifndef __SOUND_HDA_REGMAP_H
7 : : #define __SOUND_HDA_REGMAP_H
8 : :
9 : : #include <linux/regmap.h>
10 : : #include <sound/core.h>
11 : : #include <sound/hdaudio.h>
12 : :
13 : : #define AC_AMP_FAKE_MUTE 0x10 /* fake mute bit set to amp verbs */
14 : :
15 : : int snd_hdac_regmap_init(struct hdac_device *codec);
16 : : void snd_hdac_regmap_exit(struct hdac_device *codec);
17 : : int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
18 : : unsigned int verb);
19 : : int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
20 : : unsigned int *val);
21 : : int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec,
22 : : unsigned int reg, unsigned int *val);
23 : : int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
24 : : unsigned int val);
25 : : int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
26 : : unsigned int mask, unsigned int val);
27 : : int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg,
28 : : unsigned int mask, unsigned int val);
29 : : void snd_hdac_regmap_sync(struct hdac_device *codec);
30 : :
31 : : /**
32 : : * snd_hdac_regmap_encode_verb - encode the verb to a pseudo register
33 : : * @nid: widget NID
34 : : * @verb: codec verb
35 : : *
36 : : * Returns an encoded pseudo register.
37 : : */
38 : : #define snd_hdac_regmap_encode_verb(nid, verb) \
39 : : (((verb) << 8) | 0x80000 | ((unsigned int)(nid) << 20))
40 : :
41 : : /**
42 : : * snd_hdac_regmap_encode_amp - encode the AMP verb to a pseudo register
43 : : * @nid: widget NID
44 : : * @ch: channel (left = 0, right = 1)
45 : : * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
46 : : * @idx: input index value
47 : : *
48 : : * Returns an encoded pseudo register.
49 : : */
50 : : #define snd_hdac_regmap_encode_amp(nid, ch, dir, idx) \
51 : : (snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
52 : : ((ch) ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT) | \
53 : : ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
54 : : (idx))
55 : :
56 : : /**
57 : : * snd_hdac_regmap_encode_amp_stereo - encode a pseudo register for stereo AMPs
58 : : * @nid: widget NID
59 : : * @dir: direction (#HDA_INPUT, #HDA_OUTPUT)
60 : : * @idx: input index value
61 : : *
62 : : * Returns an encoded pseudo register.
63 : : */
64 : : #define snd_hdac_regmap_encode_amp_stereo(nid, dir, idx) \
65 : : (snd_hdac_regmap_encode_verb(nid, AC_VERB_GET_AMP_GAIN_MUTE) | \
66 : : AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT | /* both bits set! */ \
67 : : ((dir) == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT) | \
68 : : (idx))
69 : :
70 : : /**
71 : : * snd_hdac_regmap_write - Write a verb with caching
72 : : * @nid: codec NID
73 : : * @reg: verb to write
74 : : * @val: value to write
75 : : *
76 : : * For writing an amp value, use snd_hdac_regmap_update_amp().
77 : : */
78 : : static inline int
79 : 0 : snd_hdac_regmap_write(struct hdac_device *codec, hda_nid_t nid,
80 : : unsigned int verb, unsigned int val)
81 : : {
82 : 0 : unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
83 : :
84 : 0 : return snd_hdac_regmap_write_raw(codec, cmd, val);
85 : : }
86 : :
87 : : /**
88 : : * snd_hda_regmap_update - Update a verb value with caching
89 : : * @nid: codec NID
90 : : * @verb: verb to update
91 : : * @mask: bit mask to update
92 : : * @val: value to update
93 : : *
94 : : * For updating an amp value, use snd_hdac_regmap_update_amp().
95 : : */
96 : : static inline int
97 : 0 : snd_hdac_regmap_update(struct hdac_device *codec, hda_nid_t nid,
98 : : unsigned int verb, unsigned int mask,
99 : : unsigned int val)
100 : : {
101 : 0 : unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
102 : :
103 : 0 : return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
104 : : }
105 : :
106 : : /**
107 : : * snd_hda_regmap_read - Read a verb with caching
108 : : * @nid: codec NID
109 : : * @verb: verb to read
110 : : * @val: pointer to store the value
111 : : *
112 : : * For reading an amp value, use snd_hda_regmap_get_amp().
113 : : */
114 : : static inline int
115 : 0 : snd_hdac_regmap_read(struct hdac_device *codec, hda_nid_t nid,
116 : : unsigned int verb, unsigned int *val)
117 : : {
118 : 0 : unsigned int cmd = snd_hdac_regmap_encode_verb(nid, verb);
119 : :
120 : 0 : return snd_hdac_regmap_read_raw(codec, cmd, val);
121 : : }
122 : :
123 : : /**
124 : : * snd_hdac_regmap_get_amp - Read AMP value
125 : : * @codec: HD-audio codec
126 : : * @nid: NID to read the AMP value
127 : : * @ch: channel (left=0 or right=1)
128 : : * @direction: #HDA_INPUT or #HDA_OUTPUT
129 : : * @index: the index value (only for input direction)
130 : : * @val: the pointer to store the value
131 : : *
132 : : * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit.
133 : : * Returns the value or a negative error.
134 : : */
135 : : static inline int
136 : 0 : snd_hdac_regmap_get_amp(struct hdac_device *codec, hda_nid_t nid,
137 : : int ch, int dir, int idx)
138 : : {
139 [ # # # # ]: 0 : unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
140 : 0 : int err, val;
141 : :
142 : 0 : err = snd_hdac_regmap_read_raw(codec, cmd, &val);
143 [ # # ]: 0 : return err < 0 ? err : val;
144 : : }
145 : :
146 : : /**
147 : : * snd_hdac_regmap_update_amp - update the AMP value
148 : : * @codec: HD-audio codec
149 : : * @nid: NID to read the AMP value
150 : : * @ch: channel (left=0 or right=1)
151 : : * @direction: #HDA_INPUT or #HDA_OUTPUT
152 : : * @idx: the index value (only for input direction)
153 : : * @mask: bit mask to set
154 : : * @val: the bits value to set
155 : : *
156 : : * Update the AMP value with a bit mask.
157 : : * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
158 : : */
159 : : static inline int
160 : : snd_hdac_regmap_update_amp(struct hdac_device *codec, hda_nid_t nid,
161 : : int ch, int dir, int idx, int mask, int val)
162 : : {
163 : : unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
164 : :
165 : : return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
166 : : }
167 : :
168 : : /**
169 : : * snd_hdac_regmap_get_amp_stereo - Read stereo AMP values
170 : : * @codec: HD-audio codec
171 : : * @nid: NID to read the AMP value
172 : : * @ch: channel (left=0 or right=1)
173 : : * @direction: #HDA_INPUT or #HDA_OUTPUT
174 : : * @index: the index value (only for input direction)
175 : : * @val: the pointer to store the value
176 : : *
177 : : * Read stereo AMP values. The lower byte is left, the upper byte is right.
178 : : * Returns the value or a negative error.
179 : : */
180 : : static inline int
181 : : snd_hdac_regmap_get_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
182 : : int dir, int idx)
183 : : {
184 : : unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
185 : : int err, val;
186 : :
187 : : err = snd_hdac_regmap_read_raw(codec, cmd, &val);
188 : : return err < 0 ? err : val;
189 : : }
190 : :
191 : : /**
192 : : * snd_hdac_regmap_update_amp_stereo - update the stereo AMP value
193 : : * @codec: HD-audio codec
194 : : * @nid: NID to read the AMP value
195 : : * @direction: #HDA_INPUT or #HDA_OUTPUT
196 : : * @idx: the index value (only for input direction)
197 : : * @mask: bit mask to set
198 : : * @val: the bits value to set
199 : : *
200 : : * Update the stereo AMP value with a bit mask.
201 : : * The lower byte is left, the upper byte is right.
202 : : * Returns 0 if the value is unchanged, 1 if changed, or a negative error.
203 : : */
204 : : static inline int
205 : : snd_hdac_regmap_update_amp_stereo(struct hdac_device *codec, hda_nid_t nid,
206 : : int dir, int idx, int mask, int val)
207 : : {
208 : : unsigned int cmd = snd_hdac_regmap_encode_amp_stereo(nid, dir, idx);
209 : :
210 : : return snd_hdac_regmap_update_raw(codec, cmd, mask, val);
211 : : }
212 : :
213 : : /**
214 : : * snd_hdac_regmap_sync_node - sync the widget node attributes
215 : : * @codec: HD-audio codec
216 : : * @nid: NID to sync
217 : : */
218 : : static inline void
219 : : snd_hdac_regmap_sync_node(struct hdac_device *codec, hda_nid_t nid)
220 : : {
221 : : regcache_mark_dirty(codec->regmap);
222 : : regcache_sync_region(codec->regmap, nid << 20, ((nid + 1) << 20) - 1);
223 : : }
224 : :
225 : : #endif /* __SOUND_HDA_REGMAP_H */
|