Lines Matching +full:codec +full:- +full:0

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Regmap support for HD-audio verbs
9 * - Provided for not all verbs but only subset standard non-volatile verbs.
10 * - For reading, only AC_VERB_GET_* variants can be used.
11 * - For writing, mapped to the *corresponding* AC_VERB_SET_* variants,
25 static int codec_pm_lock(struct hdac_device *codec) in codec_pm_lock() argument
27 return snd_hdac_keep_power_up(codec); in codec_pm_lock()
30 static void codec_pm_unlock(struct hdac_device *codec, int lock) in codec_pm_unlock() argument
33 snd_hdac_power_down_pm(codec); in codec_pm_unlock()
36 #define get_verb(reg) (((reg) >> 8) & 0xfff)
40 struct hdac_device *codec = dev_to_hdac_dev(dev); in hda_volatile_reg() local
45 return !codec->cache_coef; in hda_volatile_reg()
58 case AC_VERB_GET_DEVICE_LIST: /* read-only volatile */ in hda_volatile_reg()
67 struct hdac_device *codec = dev_to_hdac_dev(dev); in hda_writeable_reg() local
72 snd_array_for_each(&codec->vendor_verbs, i, v) { in hda_writeable_reg()
77 if (codec->caps_overwriting) in hda_writeable_reg()
80 switch (verb & 0xf00) { in hda_writeable_reg()
85 return codec->cache_coef; in hda_writeable_reg()
86 case 0xf00: in hda_writeable_reg()
116 struct hdac_device *codec = dev_to_hdac_dev(dev); in hda_readable_reg() local
119 if (codec->caps_overwriting) in hda_readable_reg()
149 if (((reg >> 8) & 0x700) != AC_VERB_SET_AMP_GAIN_MUTE) in is_stereo_amp_verb()
156 static int hda_reg_read_stereo_amp(struct hdac_device *codec, in hda_reg_read_stereo_amp() argument
163 err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_LEFT, 0, &left); in hda_reg_read_stereo_amp()
164 if (err < 0) in hda_reg_read_stereo_amp()
166 err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_RIGHT, 0, &right); in hda_reg_read_stereo_amp()
167 if (err < 0) in hda_reg_read_stereo_amp()
170 return 0; in hda_reg_read_stereo_amp()
174 static int hda_reg_write_stereo_amp(struct hdac_device *codec, in hda_reg_write_stereo_amp() argument
184 verb |= AC_AMP_SET_INPUT | ((reg & 0xf) << 8); in hda_reg_write_stereo_amp()
185 reg = (reg & ~0xfffff) | verb; in hda_reg_write_stereo_amp()
187 left = val & 0xff; in hda_reg_write_stereo_amp()
188 right = (val >> 8) & 0xff; in hda_reg_write_stereo_amp()
191 return snd_hdac_exec_verb(codec, reg | left, 0, NULL); in hda_reg_write_stereo_amp()
194 err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_LEFT | left, 0, NULL); in hda_reg_write_stereo_amp()
195 if (err < 0) in hda_reg_write_stereo_amp()
197 err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_RIGHT | right, 0, NULL); in hda_reg_write_stereo_amp()
198 if (err < 0) in hda_reg_write_stereo_amp()
200 return 0; in hda_reg_write_stereo_amp()
204 static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg, in hda_reg_read_coef() argument
210 if (!codec->cache_coef) in hda_reg_read_coef()
211 return -EINVAL; in hda_reg_read_coef()
213 verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8); in hda_reg_read_coef()
214 err = snd_hdac_exec_verb(codec, verb, 0, NULL); in hda_reg_read_coef()
215 if (err < 0) in hda_reg_read_coef()
217 verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8); in hda_reg_read_coef()
218 return snd_hdac_exec_verb(codec, verb, 0, val); in hda_reg_read_coef()
222 static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg, in hda_reg_write_coef() argument
228 if (!codec->cache_coef) in hda_reg_write_coef()
229 return -EINVAL; in hda_reg_write_coef()
231 verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8); in hda_reg_write_coef()
232 err = snd_hdac_exec_verb(codec, verb, 0, NULL); in hda_reg_write_coef()
233 if (err < 0) in hda_reg_write_coef()
235 verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) | in hda_reg_write_coef()
236 (val & 0xffff); in hda_reg_write_coef()
237 return snd_hdac_exec_verb(codec, verb, 0, NULL); in hda_reg_write_coef()
242 struct hdac_device *codec = context; in hda_reg_read() local
245 int pm_lock = 0; in hda_reg_read()
248 pm_lock = codec_pm_lock(codec); in hda_reg_read()
249 if (pm_lock < 0) in hda_reg_read()
250 return -EAGAIN; in hda_reg_read()
252 reg |= (codec->addr << 28); in hda_reg_read()
254 err = hda_reg_read_stereo_amp(codec, reg, val); in hda_reg_read()
258 err = hda_reg_read_coef(codec, reg, val); in hda_reg_read()
261 if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE) in hda_reg_read()
264 err = snd_hdac_exec_verb(codec, reg, 0, val); in hda_reg_read()
265 if (err < 0) in hda_reg_read()
270 *val = -1; in hda_reg_read()
272 *val = (*val >> 4) & 0x0f; in hda_reg_read()
275 codec_pm_unlock(codec, pm_lock); in hda_reg_read()
281 struct hdac_device *codec = context; in hda_reg_write() local
284 int pm_lock = 0; in hda_reg_write()
286 if (codec->caps_overwriting) in hda_reg_write()
287 return 0; in hda_reg_write()
289 reg &= ~0x00080000U; /* drop GET bit */ in hda_reg_write()
290 reg |= (codec->addr << 28); in hda_reg_write()
294 pm_lock = codec_pm_lock(codec); in hda_reg_write()
295 if (pm_lock < 0) in hda_reg_write()
296 return codec->lazy_cache ? 0 : -EAGAIN; in hda_reg_write()
300 err = hda_reg_write_stereo_amp(codec, reg, val); in hda_reg_write()
305 err = hda_reg_write_coef(codec, reg, val); in hda_reg_write()
309 switch (verb & 0xf00) { in hda_reg_write()
312 val = 0; in hda_reg_write()
322 verb |= reg & 0xf; in hda_reg_write()
339 for (i = 0; i < bytes; i++) { in hda_reg_write()
340 reg &= ~0xfffff; in hda_reg_write()
341 reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff); in hda_reg_write()
342 err = snd_hdac_exec_verb(codec, reg, 0, NULL); in hda_reg_write()
343 if (err < 0) in hda_reg_write()
348 codec_pm_unlock(codec, pm_lock); in hda_reg_write()
356 .max_register = 0xfffffff,
369 * snd_hdac_regmap_init - Initialize regmap for HDA register accesses
370 * @codec: the codec object
374 int snd_hdac_regmap_init(struct hdac_device *codec) in snd_hdac_regmap_init() argument
378 regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg); in snd_hdac_regmap_init()
381 codec->regmap = regmap; in snd_hdac_regmap_init()
382 snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8); in snd_hdac_regmap_init()
383 return 0; in snd_hdac_regmap_init()
388 * snd_hdac_regmap_exit - Release the regmap from HDA codec
389 * @codec: the codec object
391 void snd_hdac_regmap_exit(struct hdac_device *codec) in snd_hdac_regmap_exit() argument
393 if (codec->regmap) { in snd_hdac_regmap_exit()
394 regmap_exit(codec->regmap); in snd_hdac_regmap_exit()
395 codec->regmap = NULL; in snd_hdac_regmap_exit()
396 snd_array_free(&codec->vendor_verbs); in snd_hdac_regmap_exit()
402 * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap
403 * @codec: the codec object
408 int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec, in snd_hdac_regmap_add_vendor_verb() argument
411 unsigned int *p = snd_array_new(&codec->vendor_verbs); in snd_hdac_regmap_add_vendor_verb()
414 return -ENOMEM; in snd_hdac_regmap_add_vendor_verb()
415 *p = verb | 0x800; /* set GET bit */ in snd_hdac_regmap_add_vendor_verb()
416 return 0; in snd_hdac_regmap_add_vendor_verb()
424 /* write a pseudo-register value (w/o power sequence) */
425 static int reg_raw_write(struct hdac_device *codec, unsigned int reg, in reg_raw_write() argument
430 mutex_lock(&codec->regmap_lock); in reg_raw_write()
431 if (!codec->regmap) in reg_raw_write()
432 err = hda_reg_write(codec, reg, val); in reg_raw_write()
434 err = regmap_write(codec->regmap, reg, val); in reg_raw_write()
435 mutex_unlock(&codec->regmap_lock); in reg_raw_write()
439 /* a helper macro to call @func_call; retry with power-up if failed */
440 #define CALL_RAW_FUNC(codec, func_call) \ argument
443 if (_err == -EAGAIN) { \
444 _err = snd_hdac_power_up_pm(codec); \
445 if (_err >= 0) \
447 snd_hdac_power_down_pm(codec); \
452 * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
453 * @codec: the codec object
459 int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, in snd_hdac_regmap_write_raw() argument
462 return CALL_RAW_FUNC(codec, reg_raw_write(codec, reg, val)); in snd_hdac_regmap_write_raw()
466 static int reg_raw_read(struct hdac_device *codec, unsigned int reg, in reg_raw_read() argument
471 mutex_lock(&codec->regmap_lock); in reg_raw_read()
472 if (uncached || !codec->regmap) in reg_raw_read()
473 err = hda_reg_read(codec, reg, val); in reg_raw_read()
475 err = regmap_read(codec->regmap, reg, val); in reg_raw_read()
476 mutex_unlock(&codec->regmap_lock); in reg_raw_read()
480 static int __snd_hdac_regmap_read_raw(struct hdac_device *codec, in __snd_hdac_regmap_read_raw() argument
484 return CALL_RAW_FUNC(codec, reg_raw_read(codec, reg, val, uncached)); in __snd_hdac_regmap_read_raw()
488 * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt
489 * @codec: the codec object
495 int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, in snd_hdac_regmap_read_raw() argument
498 return __snd_hdac_regmap_read_raw(codec, reg, val, false); in snd_hdac_regmap_read_raw()
505 int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec, in snd_hdac_regmap_read_raw_uncached() argument
508 return __snd_hdac_regmap_read_raw(codec, reg, val, true); in snd_hdac_regmap_read_raw_uncached()
511 static int reg_raw_update(struct hdac_device *codec, unsigned int reg, in reg_raw_update() argument
518 mutex_lock(&codec->regmap_lock); in reg_raw_update()
519 if (codec->regmap) { in reg_raw_update()
520 err = regmap_update_bits_check(codec->regmap, reg, mask, val, in reg_raw_update()
523 err = change ? 1 : 0; in reg_raw_update()
525 err = hda_reg_read(codec, reg, &orig); in reg_raw_update()
530 err = hda_reg_write(codec, reg, val); in reg_raw_update()
536 mutex_unlock(&codec->regmap_lock); in reg_raw_update()
541 * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
542 * @codec: the codec object
549 int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg, in snd_hdac_regmap_update_raw() argument
552 return CALL_RAW_FUNC(codec, reg_raw_update(codec, reg, mask, val)); in snd_hdac_regmap_update_raw()
556 static int reg_raw_update_once(struct hdac_device *codec, unsigned int reg, in reg_raw_update_once() argument
559 int err = 0; in reg_raw_update_once()
561 if (!codec->regmap) in reg_raw_update_once()
562 return reg_raw_update(codec, reg, mask, val); in reg_raw_update_once()
564 mutex_lock(&codec->regmap_lock); in reg_raw_update_once()
566 if (!regcache_reg_cached(codec->regmap, reg)) in reg_raw_update_once()
567 err = regmap_update_bits(codec->regmap, reg, mask, val); in reg_raw_update_once()
568 mutex_unlock(&codec->regmap_lock); in reg_raw_update_once()
573 * snd_hdac_regmap_update_raw_once - initialize the register value only once
574 * @codec: the codec object
580 * hasn't been initialized yet. Used in HD-audio legacy driver.
583 int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg, in snd_hdac_regmap_update_raw_once() argument
586 return CALL_RAW_FUNC(codec, reg_raw_update_once(codec, reg, mask, val)); in snd_hdac_regmap_update_raw_once()
591 * snd_hdac_regmap_sync - sync out the cached values for PM resume
592 * @codec: the codec object
594 void snd_hdac_regmap_sync(struct hdac_device *codec) in snd_hdac_regmap_sync() argument
596 mutex_lock(&codec->regmap_lock); in snd_hdac_regmap_sync()
597 if (codec->regmap) in snd_hdac_regmap_sync()
598 regcache_sync(codec->regmap); in snd_hdac_regmap_sync()
599 mutex_unlock(&codec->regmap_lock); in snd_hdac_regmap_sync()