]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - sound/hda/hdac_regmap.c
ALSA: hda - Add a fake stereo amp register support
[mirror_ubuntu-artful-kernel.git] / sound / hda / hdac_regmap.c
CommitLineData
4d75faa0
TI
1/*
2 * Regmap support for HD-audio verbs
3 *
4 * A virtual register is translated to one or more hda verbs for write,
5 * vice versa for read.
6 *
7 * A few limitations:
8 * - Provided for not all verbs but only subset standard non-volatile verbs.
9 * - For reading, only AC_VERB_GET_* variants can be used.
10 * - For writing, mapped to the *corresponding* AC_VERB_SET_* variants,
11 * so can't handle asymmetric verbs for read and write
12 */
13
14#include <linux/slab.h>
15#include <linux/device.h>
16#include <linux/regmap.h>
17#include <linux/export.h>
18#include <linux/pm.h>
19#include <linux/pm_runtime.h>
20#include <sound/core.h>
21#include <sound/hdaudio.h>
22#include <sound/hda_regmap.h>
23
24#ifdef CONFIG_PM
25#define codec_is_running(codec) \
26 (atomic_read(&(codec)->in_pm) || \
27 !pm_runtime_suspended(&(codec)->dev))
28#else
29#define codec_is_running(codec) true
30#endif
31
32#define get_verb(reg) (((reg) >> 8) & 0xfff)
33
34static bool hda_volatile_reg(struct device *dev, unsigned int reg)
35{
36 unsigned int verb = get_verb(reg);
37
38 switch (verb) {
39 case AC_VERB_GET_PROC_COEF:
40 case AC_VERB_GET_COEF_INDEX:
41 case AC_VERB_GET_PROC_STATE:
42 case AC_VERB_GET_POWER_STATE:
43 case AC_VERB_GET_PIN_SENSE:
44 case AC_VERB_GET_HDMI_DIP_SIZE:
45 case AC_VERB_GET_HDMI_ELDD:
46 case AC_VERB_GET_HDMI_DIP_INDEX:
47 case AC_VERB_GET_HDMI_DIP_DATA:
48 case AC_VERB_GET_HDMI_DIP_XMIT:
49 case AC_VERB_GET_HDMI_CP_CTRL:
50 case AC_VERB_GET_HDMI_CHAN_SLOT:
51 case AC_VERB_GET_DEVICE_SEL:
52 case AC_VERB_GET_DEVICE_LIST: /* read-only volatile */
53 return true;
54 }
55
56 return false;
57}
58
59static bool hda_writeable_reg(struct device *dev, unsigned int reg)
60{
faa75f8a 61 struct hdac_device *codec = dev_to_hdac_dev(dev);
4d75faa0 62 unsigned int verb = get_verb(reg);
5e56bcea
TI
63 int i;
64
65 for (i = 0; i < codec->vendor_verbs.used; i++) {
66 unsigned int *v = snd_array_elem(&codec->vendor_verbs, i);
67 if (verb == *v)
68 return true;
69 }
4d75faa0 70
faa75f8a
TI
71 if (codec->caps_overwriting)
72 return true;
73
4d75faa0
TI
74 switch (verb & 0xf00) {
75 case AC_VERB_GET_STREAM_FORMAT:
76 case AC_VERB_GET_AMP_GAIN_MUTE:
77 return true;
78 case 0xf00:
79 break;
80 default:
81 return false;
82 }
83
84 switch (verb) {
85 case AC_VERB_GET_CONNECT_SEL:
86 case AC_VERB_GET_SDI_SELECT:
87 case AC_VERB_GET_CONV:
88 case AC_VERB_GET_PIN_WIDGET_CONTROL:
89 case AC_VERB_GET_UNSOLICITED_RESPONSE: /* only as SET_UNSOLICITED_ENABLE */
90 case AC_VERB_GET_BEEP_CONTROL:
91 case AC_VERB_GET_EAPD_BTLENABLE:
92 case AC_VERB_GET_DIGI_CONVERT_1:
93 case AC_VERB_GET_DIGI_CONVERT_2: /* only for beep control */
94 case AC_VERB_GET_VOLUME_KNOB_CONTROL:
95 case AC_VERB_GET_CONFIG_DEFAULT:
96 case AC_VERB_GET_GPIO_MASK:
97 case AC_VERB_GET_GPIO_DIRECTION:
98 case AC_VERB_GET_GPIO_DATA: /* not for volatile read */
99 case AC_VERB_GET_GPIO_WAKE_MASK:
100 case AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK:
101 case AC_VERB_GET_GPIO_STICKY_MASK:
102 case AC_VERB_GET_CVT_CHAN_COUNT:
103 return true;
104 }
105
106 return false;
107}
108
109static bool hda_readable_reg(struct device *dev, unsigned int reg)
110{
faa75f8a 111 struct hdac_device *codec = dev_to_hdac_dev(dev);
4d75faa0
TI
112 unsigned int verb = get_verb(reg);
113
faa75f8a
TI
114 if (codec->caps_overwriting)
115 return true;
116
4d75faa0
TI
117 switch (verb) {
118 case AC_VERB_PARAMETERS:
119 case AC_VERB_GET_CONNECT_LIST:
120 case AC_VERB_GET_SUBSYSTEM_ID:
121 return true;
122 }
123
124 return hda_writeable_reg(dev, reg);
125}
126
d313e0a8
TI
127/*
128 * Stereo amp pseudo register:
129 * for making easier to handle the stereo volume control, we provide a
130 * fake register to deal both left and right channels by a single
131 * (pseudo) register access. A verb consisting of SET_AMP_GAIN with
132 * *both* SET_LEFT and SET_RIGHT bits takes a 16bit value, the lower 8bit
133 * for the left and the upper 8bit for the right channel.
134 */
135static bool is_stereo_amp_verb(unsigned int reg)
136{
137 if (((reg >> 8) & 0x700) != AC_VERB_SET_AMP_GAIN_MUTE)
138 return false;
139 return (reg & (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT)) ==
140 (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
141}
142
143/* read a pseudo stereo amp register (16bit left+right) */
144static int hda_reg_read_stereo_amp(struct hdac_device *codec,
145 unsigned int reg, unsigned int *val)
146{
147 unsigned int left, right;
148 int err;
149
150 reg &= ~(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);
151 err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_LEFT, 0, &left);
152 if (err < 0)
153 return err;
154 err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_RIGHT, 0, &right);
155 if (err < 0)
156 return err;
157 *val = left | (right << 8);
158 return 0;
159}
160
161/* write a pseudo stereo amp register (16bit left+right) */
162static int hda_reg_write_stereo_amp(struct hdac_device *codec,
163 unsigned int reg, unsigned int val)
164{
165 int err;
166 unsigned int verb, left, right;
167
168 verb = AC_VERB_SET_AMP_GAIN_MUTE << 8;
169 if (reg & AC_AMP_GET_OUTPUT)
170 verb |= AC_AMP_SET_OUTPUT;
171 else
172 verb |= AC_AMP_SET_INPUT | ((reg & 0xf) << 8);
173 reg = (reg & ~0xfffff) | verb;
174
175 left = val & 0xff;
176 right = (val >> 8) & 0xff;
177 if (left == right) {
178 reg |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;
179 return snd_hdac_exec_verb(codec, reg | left, 0, NULL);
180 }
181
182 err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_LEFT | left, 0, NULL);
183 if (err < 0)
184 return err;
185 err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_RIGHT | right, 0, NULL);
186 if (err < 0)
187 return err;
188 return 0;
189}
190
4d75faa0
TI
191static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
192{
193 struct hdac_device *codec = context;
194
195 if (!codec_is_running(codec))
196 return -EAGAIN;
197 reg |= (codec->addr << 28);
d313e0a8
TI
198 if (is_stereo_amp_verb(reg))
199 return hda_reg_read_stereo_amp(codec, reg, val);
4d75faa0
TI
200 return snd_hdac_exec_verb(codec, reg, 0, val);
201}
202
203static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
204{
205 struct hdac_device *codec = context;
206 unsigned int verb;
207 int i, bytes, err;
208
209 if (!codec_is_running(codec))
210 return codec->lazy_cache ? 0 : -EAGAIN;
211
212 reg &= ~0x00080000U; /* drop GET bit */
213 reg |= (codec->addr << 28);
4d75faa0 214
d313e0a8
TI
215 if (is_stereo_amp_verb(reg))
216 return hda_reg_write_stereo_amp(codec, reg, val);
217
218 verb = get_verb(reg);
4d75faa0
TI
219 switch (verb & 0xf00) {
220 case AC_VERB_SET_AMP_GAIN_MUTE:
221 verb = AC_VERB_SET_AMP_GAIN_MUTE;
222 if (reg & AC_AMP_GET_LEFT)
223 verb |= AC_AMP_SET_LEFT >> 8;
224 else
225 verb |= AC_AMP_SET_RIGHT >> 8;
226 if (reg & AC_AMP_GET_OUTPUT) {
227 verb |= AC_AMP_SET_OUTPUT >> 8;
228 } else {
229 verb |= AC_AMP_SET_INPUT >> 8;
230 verb |= reg & 0xf;
231 }
232 break;
233 }
234
235 switch (verb) {
236 case AC_VERB_SET_DIGI_CONVERT_1:
237 bytes = 2;
238 break;
239 case AC_VERB_SET_CONFIG_DEFAULT_BYTES_0:
240 bytes = 4;
241 break;
242 default:
243 bytes = 1;
244 break;
245 }
246
247 for (i = 0; i < bytes; i++) {
248 reg &= ~0xfffff;
249 reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);
250 err = snd_hdac_exec_verb(codec, reg, 0, NULL);
251 if (err < 0)
252 return err;
253 }
254
255 return 0;
256}
257
258static const struct regmap_config hda_regmap_cfg = {
259 .name = "hdaudio",
260 .reg_bits = 32,
261 .val_bits = 32,
262 .max_register = 0xfffffff,
263 .writeable_reg = hda_writeable_reg,
264 .readable_reg = hda_readable_reg,
265 .volatile_reg = hda_volatile_reg,
266 .cache_type = REGCACHE_RBTREE,
267 .reg_read = hda_reg_read,
268 .reg_write = hda_reg_write,
269};
270
271int snd_hdac_regmap_init(struct hdac_device *codec)
272{
273 struct regmap *regmap;
274
275 regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg);
276 if (IS_ERR(regmap))
277 return PTR_ERR(regmap);
278 codec->regmap = regmap;
5e56bcea 279 snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8);
4d75faa0
TI
280 return 0;
281}
282EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);
283
284void snd_hdac_regmap_exit(struct hdac_device *codec)
285{
286 if (codec->regmap) {
287 regmap_exit(codec->regmap);
288 codec->regmap = NULL;
5e56bcea 289 snd_array_free(&codec->vendor_verbs);
4d75faa0
TI
290 }
291}
292EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit);
293
5e56bcea
TI
294/**
295 * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap
296 * @codec: the codec object
297 * @verb: verb to allow accessing via regmap
298 *
299 * Returns zero for success or a negative error code.
300 */
301int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
302 unsigned int verb)
303{
304 unsigned int *p = snd_array_new(&codec->vendor_verbs);
305
306 if (!p)
307 return -ENOMEM;
308 *p = verb;
309 return 0;
310}
311EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
312
4d75faa0
TI
313/*
314 * helper functions
315 */
316
317/* write a pseudo-register value (w/o power sequence) */
318static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
319 unsigned int val)
320{
321 if (!codec->regmap)
322 return hda_reg_write(codec, reg, val);
323 else
324 return regmap_write(codec->regmap, reg, val);
325}
326
327/**
328 * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
329 * @codec: the codec object
330 * @reg: pseudo register
331 * @val: value to write
332 *
333 * Returns zero if successful or a negative error code.
334 */
335int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
336 unsigned int val)
337{
338 int err;
339
340 err = reg_raw_write(codec, reg, val);
341 if (err == -EAGAIN) {
342 snd_hdac_power_up(codec);
343 err = reg_raw_write(codec, reg, val);
344 snd_hdac_power_down(codec);
345 }
346 return err;
347}
348EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
349
350static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
351 unsigned int *val)
352{
353 if (!codec->regmap)
354 return hda_reg_read(codec, reg, val);
355 else
356 return regmap_read(codec->regmap, reg, val);
357}
358
359/**
360 * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt
361 * @codec: the codec object
362 * @reg: pseudo register
363 * @val: pointer to store the read value
364 *
365 * Returns zero if successful or a negative error code.
366 */
367int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
368 unsigned int *val)
369{
370 int err;
371
372 err = reg_raw_read(codec, reg, val);
373 if (err == -EAGAIN) {
374 snd_hdac_power_up(codec);
375 err = reg_raw_read(codec, reg, val);
376 snd_hdac_power_down(codec);
377 }
378 return err;
379}
380EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw);
381
382/**
383 * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
384 * @codec: the codec object
385 * @reg: pseudo register
386 * @mask: bit mask to udpate
387 * @val: value to update
388 *
389 * Returns zero if successful or a negative error code.
390 */
391int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
392 unsigned int mask, unsigned int val)
393{
394 unsigned int orig;
395 int err;
396
397 val &= mask;
398 err = snd_hdac_regmap_read_raw(codec, reg, &orig);
399 if (err < 0)
400 return err;
401 val |= orig & ~mask;
402 if (val == orig)
403 return 0;
404 err = snd_hdac_regmap_write_raw(codec, reg, val);
405 if (err < 0)
406 return err;
407 return 1;
408}
409EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);