ALSA: hda - Handle get/set power verb symmetrically via regmap
[linux-2.6-block.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;
33f81940 194 int err;
4d75faa0
TI
195
196 if (!codec_is_running(codec))
197 return -EAGAIN;
198 reg |= (codec->addr << 28);
d313e0a8
TI
199 if (is_stereo_amp_verb(reg))
200 return hda_reg_read_stereo_amp(codec, reg, val);
33f81940
TI
201 err = snd_hdac_exec_verb(codec, reg, 0, val);
202 if (err < 0)
203 return err;
204 /* special handling for asymmetric reads */
205 if (get_verb(reg) == AC_VERB_GET_POWER_STATE) {
206 if (*val & AC_PWRST_ERROR)
207 *val = -1;
208 else /* take only the actual state */
209 *val = (*val >> 4) & 0x0f;
210 }
211 return 0;
4d75faa0
TI
212}
213
214static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
215{
216 struct hdac_device *codec = context;
217 unsigned int verb;
218 int i, bytes, err;
219
220 if (!codec_is_running(codec))
221 return codec->lazy_cache ? 0 : -EAGAIN;
222
223 reg &= ~0x00080000U; /* drop GET bit */
224 reg |= (codec->addr << 28);
4d75faa0 225
d313e0a8
TI
226 if (is_stereo_amp_verb(reg))
227 return hda_reg_write_stereo_amp(codec, reg, val);
228
229 verb = get_verb(reg);
4d75faa0
TI
230 switch (verb & 0xf00) {
231 case AC_VERB_SET_AMP_GAIN_MUTE:
232 verb = AC_VERB_SET_AMP_GAIN_MUTE;
233 if (reg & AC_AMP_GET_LEFT)
234 verb |= AC_AMP_SET_LEFT >> 8;
235 else
236 verb |= AC_AMP_SET_RIGHT >> 8;
237 if (reg & AC_AMP_GET_OUTPUT) {
238 verb |= AC_AMP_SET_OUTPUT >> 8;
239 } else {
240 verb |= AC_AMP_SET_INPUT >> 8;
241 verb |= reg & 0xf;
242 }
243 break;
244 }
245
246 switch (verb) {
247 case AC_VERB_SET_DIGI_CONVERT_1:
248 bytes = 2;
249 break;
250 case AC_VERB_SET_CONFIG_DEFAULT_BYTES_0:
251 bytes = 4;
252 break;
253 default:
254 bytes = 1;
255 break;
256 }
257
258 for (i = 0; i < bytes; i++) {
259 reg &= ~0xfffff;
260 reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);
261 err = snd_hdac_exec_verb(codec, reg, 0, NULL);
262 if (err < 0)
263 return err;
264 }
265
266 return 0;
267}
268
269static const struct regmap_config hda_regmap_cfg = {
270 .name = "hdaudio",
271 .reg_bits = 32,
272 .val_bits = 32,
273 .max_register = 0xfffffff,
274 .writeable_reg = hda_writeable_reg,
275 .readable_reg = hda_readable_reg,
276 .volatile_reg = hda_volatile_reg,
277 .cache_type = REGCACHE_RBTREE,
278 .reg_read = hda_reg_read,
279 .reg_write = hda_reg_write,
280};
281
282int snd_hdac_regmap_init(struct hdac_device *codec)
283{
284 struct regmap *regmap;
285
286 regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg);
287 if (IS_ERR(regmap))
288 return PTR_ERR(regmap);
289 codec->regmap = regmap;
5e56bcea 290 snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8);
4d75faa0
TI
291 return 0;
292}
293EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);
294
295void snd_hdac_regmap_exit(struct hdac_device *codec)
296{
297 if (codec->regmap) {
298 regmap_exit(codec->regmap);
299 codec->regmap = NULL;
5e56bcea 300 snd_array_free(&codec->vendor_verbs);
4d75faa0
TI
301 }
302}
303EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit);
304
5e56bcea
TI
305/**
306 * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap
307 * @codec: the codec object
308 * @verb: verb to allow accessing via regmap
309 *
310 * Returns zero for success or a negative error code.
311 */
312int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,
313 unsigned int verb)
314{
315 unsigned int *p = snd_array_new(&codec->vendor_verbs);
316
317 if (!p)
318 return -ENOMEM;
319 *p = verb;
320 return 0;
321}
322EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);
323
4d75faa0
TI
324/*
325 * helper functions
326 */
327
328/* write a pseudo-register value (w/o power sequence) */
329static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
330 unsigned int val)
331{
332 if (!codec->regmap)
333 return hda_reg_write(codec, reg, val);
334 else
335 return regmap_write(codec->regmap, reg, val);
336}
337
338/**
339 * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
340 * @codec: the codec object
341 * @reg: pseudo register
342 * @val: value to write
343 *
344 * Returns zero if successful or a negative error code.
345 */
346int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
347 unsigned int val)
348{
349 int err;
350
351 err = reg_raw_write(codec, reg, val);
352 if (err == -EAGAIN) {
353 snd_hdac_power_up(codec);
354 err = reg_raw_write(codec, reg, val);
355 snd_hdac_power_down(codec);
356 }
357 return err;
358}
359EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
360
361static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
362 unsigned int *val)
363{
364 if (!codec->regmap)
365 return hda_reg_read(codec, reg, val);
366 else
367 return regmap_read(codec->regmap, reg, val);
368}
369
370/**
371 * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt
372 * @codec: the codec object
373 * @reg: pseudo register
374 * @val: pointer to store the read value
375 *
376 * Returns zero if successful or a negative error code.
377 */
378int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,
379 unsigned int *val)
380{
381 int err;
382
383 err = reg_raw_read(codec, reg, val);
384 if (err == -EAGAIN) {
385 snd_hdac_power_up(codec);
386 err = reg_raw_read(codec, reg, val);
387 snd_hdac_power_down(codec);
388 }
389 return err;
390}
391EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw);
392
393/**
394 * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
395 * @codec: the codec object
396 * @reg: pseudo register
397 * @mask: bit mask to udpate
398 * @val: value to update
399 *
400 * Returns zero if successful or a negative error code.
401 */
402int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
403 unsigned int mask, unsigned int val)
404{
405 unsigned int orig;
406 int err;
407
408 val &= mask;
409 err = snd_hdac_regmap_read_raw(codec, reg, &orig);
410 if (err < 0)
411 return err;
412 val |= orig & ~mask;
413 if (val == orig)
414 return 0;
415 err = snd_hdac_regmap_write_raw(codec, reg, val);
416 if (err < 0)
417 return err;
418 return 1;
419}
420EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);