brintos

brintos / linux-shallow public Read only

0
0
Text · 15.1 KiB · 97cee09 Raw
602 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Regmap support for HD-audio verbs4 *5 * A virtual register is translated to one or more hda verbs for write,6 * vice versa for read.7 *8 * A few limitations: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,12 *   so can't handle asymmetric verbs for read and write13 */14 15#include <linux/slab.h>16#include <linux/device.h>17#include <linux/regmap.h>18#include <linux/export.h>19#include <linux/pm.h>20#include <sound/core.h>21#include <sound/hdaudio.h>22#include <sound/hda_regmap.h>23#include "local.h"24 25static int codec_pm_lock(struct hdac_device *codec)26{27	return snd_hdac_keep_power_up(codec);28}29 30static void codec_pm_unlock(struct hdac_device *codec, int lock)31{32	if (lock == 1)33		snd_hdac_power_down_pm(codec);34}35 36#define get_verb(reg)	(((reg) >> 8) & 0xfff)37 38static bool hda_volatile_reg(struct device *dev, unsigned int reg)39{40	struct hdac_device *codec = dev_to_hdac_dev(dev);41	unsigned int verb = get_verb(reg);42 43	switch (verb) {44	case AC_VERB_GET_PROC_COEF:45		return !codec->cache_coef;46	case AC_VERB_GET_COEF_INDEX:47	case AC_VERB_GET_PROC_STATE:48	case AC_VERB_GET_POWER_STATE:49	case AC_VERB_GET_PIN_SENSE:50	case AC_VERB_GET_HDMI_DIP_SIZE:51	case AC_VERB_GET_HDMI_ELDD:52	case AC_VERB_GET_HDMI_DIP_INDEX:53	case AC_VERB_GET_HDMI_DIP_DATA:54	case AC_VERB_GET_HDMI_DIP_XMIT:55	case AC_VERB_GET_HDMI_CP_CTRL:56	case AC_VERB_GET_HDMI_CHAN_SLOT:57	case AC_VERB_GET_DEVICE_SEL:58	case AC_VERB_GET_DEVICE_LIST:	/* read-only volatile */59		return true;60	}61 62	return false;63}64 65static bool hda_writeable_reg(struct device *dev, unsigned int reg)66{67	struct hdac_device *codec = dev_to_hdac_dev(dev);68	unsigned int verb = get_verb(reg);69	const unsigned int *v;70	int i;71 72	snd_array_for_each(&codec->vendor_verbs, i, v) {73		if (verb == *v)74			return true;75	}76 77	if (codec->caps_overwriting)78		return true;79 80	switch (verb & 0xf00) {81	case AC_VERB_GET_STREAM_FORMAT:82	case AC_VERB_GET_AMP_GAIN_MUTE:83		return true;84	case AC_VERB_GET_PROC_COEF:85		return codec->cache_coef;86	case 0xf00:87		break;88	default:89		return false;90	}91 92	switch (verb) {93	case AC_VERB_GET_CONNECT_SEL:94	case AC_VERB_GET_SDI_SELECT:95	case AC_VERB_GET_PIN_WIDGET_CONTROL:96	case AC_VERB_GET_UNSOLICITED_RESPONSE: /* only as SET_UNSOLICITED_ENABLE */97	case AC_VERB_GET_BEEP_CONTROL:98	case AC_VERB_GET_EAPD_BTLENABLE:99	case AC_VERB_GET_DIGI_CONVERT_1:100	case AC_VERB_GET_DIGI_CONVERT_2: /* only for beep control */101	case AC_VERB_GET_VOLUME_KNOB_CONTROL:102	case AC_VERB_GET_GPIO_MASK:103	case AC_VERB_GET_GPIO_DIRECTION:104	case AC_VERB_GET_GPIO_DATA: /* not for volatile read */105	case AC_VERB_GET_GPIO_WAKE_MASK:106	case AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK:107	case AC_VERB_GET_GPIO_STICKY_MASK:108		return true;109	}110 111	return false;112}113 114static bool hda_readable_reg(struct device *dev, unsigned int reg)115{116	struct hdac_device *codec = dev_to_hdac_dev(dev);117	unsigned int verb = get_verb(reg);118 119	if (codec->caps_overwriting)120		return true;121 122	switch (verb) {123	case AC_VERB_PARAMETERS:124	case AC_VERB_GET_CONNECT_LIST:125	case AC_VERB_GET_SUBSYSTEM_ID:126		return true;127	/* below are basically writable, but disabled for reducing unnecessary128	 * writes at sync129	 */130	case AC_VERB_GET_CONFIG_DEFAULT: /* usually just read */131	case AC_VERB_GET_CONV: /* managed in PCM code */132	case AC_VERB_GET_CVT_CHAN_COUNT: /* managed in HDMI CA code */133		return true;134	}135 136	return hda_writeable_reg(dev, reg);137}138 139/*140 * Stereo amp pseudo register:141 * for making easier to handle the stereo volume control, we provide a142 * fake register to deal both left and right channels by a single143 * (pseudo) register access.  A verb consisting of SET_AMP_GAIN with144 * *both* SET_LEFT and SET_RIGHT bits takes a 16bit value, the lower 8bit145 * for the left and the upper 8bit for the right channel.146 */147static bool is_stereo_amp_verb(unsigned int reg)148{149	if (((reg >> 8) & 0x700) != AC_VERB_SET_AMP_GAIN_MUTE)150		return false;151	return (reg & (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT)) ==152		(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);153}154 155/* read a pseudo stereo amp register (16bit left+right) */156static int hda_reg_read_stereo_amp(struct hdac_device *codec,157				   unsigned int reg, unsigned int *val)158{159	unsigned int left, right;160	int err;161 162	reg &= ~(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT);163	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_LEFT, 0, &left);164	if (err < 0)165		return err;166	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_RIGHT, 0, &right);167	if (err < 0)168		return err;169	*val = left | (right << 8);170	return 0;171}172 173/* write a pseudo stereo amp register (16bit left+right) */174static int hda_reg_write_stereo_amp(struct hdac_device *codec,175				    unsigned int reg, unsigned int val)176{177	int err;178	unsigned int verb, left, right;179 180	verb = AC_VERB_SET_AMP_GAIN_MUTE << 8;181	if (reg & AC_AMP_GET_OUTPUT)182		verb |= AC_AMP_SET_OUTPUT;183	else184		verb |= AC_AMP_SET_INPUT | ((reg & 0xf) << 8);185	reg = (reg & ~0xfffff) | verb;186 187	left = val & 0xff;188	right = (val >> 8) & 0xff;189	if (left == right) {190		reg |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT;191		return snd_hdac_exec_verb(codec, reg | left, 0, NULL);192	}193 194	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_LEFT | left, 0, NULL);195	if (err < 0)196		return err;197	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_RIGHT | right, 0, NULL);198	if (err < 0)199		return err;200	return 0;201}202 203/* read a pseudo coef register (16bit) */204static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg,205			     unsigned int *val)206{207	unsigned int verb;208	int err;209 210	if (!codec->cache_coef)211		return -EINVAL;212	/* LSB 8bit = coef index */213	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);214	err = snd_hdac_exec_verb(codec, verb, 0, NULL);215	if (err < 0)216		return err;217	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8);218	return snd_hdac_exec_verb(codec, verb, 0, val);219}220 221/* write a pseudo coef register (16bit) */222static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg,223			      unsigned int val)224{225	unsigned int verb;226	int err;227 228	if (!codec->cache_coef)229		return -EINVAL;230	/* LSB 8bit = coef index */231	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8);232	err = snd_hdac_exec_verb(codec, verb, 0, NULL);233	if (err < 0)234		return err;235	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) |236		(val & 0xffff);237	return snd_hdac_exec_verb(codec, verb, 0, NULL);238}239 240static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)241{242	struct hdac_device *codec = context;243	int verb = get_verb(reg);244	int err;245	int pm_lock = 0;246 247	if (verb != AC_VERB_GET_POWER_STATE) {248		pm_lock = codec_pm_lock(codec);249		if (pm_lock < 0)250			return -EAGAIN;251	}252	reg |= (codec->addr << 28);253	if (is_stereo_amp_verb(reg)) {254		err = hda_reg_read_stereo_amp(codec, reg, val);255		goto out;256	}257	if (verb == AC_VERB_GET_PROC_COEF) {258		err = hda_reg_read_coef(codec, reg, val);259		goto out;260	}261	if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE)262		reg &= ~AC_AMP_FAKE_MUTE;263 264	err = snd_hdac_exec_verb(codec, reg, 0, val);265	if (err < 0)266		goto out;267	/* special handling for asymmetric reads */268	if (verb == AC_VERB_GET_POWER_STATE) {269		if (*val & AC_PWRST_ERROR)270			*val = -1;271		else /* take only the actual state */272			*val = (*val >> 4) & 0x0f;273	}274 out:275	codec_pm_unlock(codec, pm_lock);276	return err;277}278 279static int hda_reg_write(void *context, unsigned int reg, unsigned int val)280{281	struct hdac_device *codec = context;282	unsigned int verb;283	int i, bytes, err;284	int pm_lock = 0;285 286	if (codec->caps_overwriting)287		return 0;288 289	reg &= ~0x00080000U; /* drop GET bit */290	reg |= (codec->addr << 28);291	verb = get_verb(reg);292 293	if (verb != AC_VERB_SET_POWER_STATE) {294		pm_lock = codec_pm_lock(codec);295		if (pm_lock < 0)296			return codec->lazy_cache ? 0 : -EAGAIN;297	}298 299	if (is_stereo_amp_verb(reg)) {300		err = hda_reg_write_stereo_amp(codec, reg, val);301		goto out;302	}303 304	if (verb == AC_VERB_SET_PROC_COEF) {305		err = hda_reg_write_coef(codec, reg, val);306		goto out;307	}308 309	switch (verb & 0xf00) {310	case AC_VERB_SET_AMP_GAIN_MUTE:311		if ((reg & AC_AMP_FAKE_MUTE) && (val & AC_AMP_MUTE))312			val = 0;313		verb = AC_VERB_SET_AMP_GAIN_MUTE;314		if (reg & AC_AMP_GET_LEFT)315			verb |= AC_AMP_SET_LEFT >> 8;316		else317			verb |= AC_AMP_SET_RIGHT >> 8;318		if (reg & AC_AMP_GET_OUTPUT) {319			verb |= AC_AMP_SET_OUTPUT >> 8;320		} else {321			verb |= AC_AMP_SET_INPUT >> 8;322			verb |= reg & 0xf;323		}324		break;325	}326 327	switch (verb) {328	case AC_VERB_SET_DIGI_CONVERT_1:329		bytes = 2;330		break;331	case AC_VERB_SET_CONFIG_DEFAULT_BYTES_0:332		bytes = 4;333		break;334	default:335		bytes = 1;336		break;337	}338 339	for (i = 0; i < bytes; i++) {340		reg &= ~0xfffff;341		reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);342		err = snd_hdac_exec_verb(codec, reg, 0, NULL);343		if (err < 0)344			goto out;345	}346 347 out:348	codec_pm_unlock(codec, pm_lock);349	return err;350}351 352static const struct regmap_config hda_regmap_cfg = {353	.name = "hdaudio",354	.reg_bits = 32,355	.val_bits = 32,356	.max_register = 0xfffffff,357	.writeable_reg = hda_writeable_reg,358	.readable_reg = hda_readable_reg,359	.volatile_reg = hda_volatile_reg,360	.cache_type = REGCACHE_MAPLE,361	.reg_read = hda_reg_read,362	.reg_write = hda_reg_write,363	.use_single_read = true,364	.use_single_write = true,365	.disable_locking = true,366};367 368/**369 * snd_hdac_regmap_init - Initialize regmap for HDA register accesses370 * @codec: the codec object371 *372 * Returns zero for success or a negative error code.373 */374int snd_hdac_regmap_init(struct hdac_device *codec)375{376	struct regmap *regmap;377 378	regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg);379	if (IS_ERR(regmap))380		return PTR_ERR(regmap);381	codec->regmap = regmap;382	snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8);383	return 0;384}385EXPORT_SYMBOL_GPL(snd_hdac_regmap_init);386 387/**388 * snd_hdac_regmap_exit - Release the regmap from HDA codec389 * @codec: the codec object390 */391void snd_hdac_regmap_exit(struct hdac_device *codec)392{393	if (codec->regmap) {394		regmap_exit(codec->regmap);395		codec->regmap = NULL;396		snd_array_free(&codec->vendor_verbs);397	}398}399EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit);400 401/**402 * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap403 * @codec: the codec object404 * @verb: verb to allow accessing via regmap405 *406 * Returns zero for success or a negative error code.407 */408int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec,409				    unsigned int verb)410{411	unsigned int *p = snd_array_new(&codec->vendor_verbs);412 413	if (!p)414		return -ENOMEM;415	*p = verb | 0x800; /* set GET bit */416	return 0;417}418EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb);419 420/*421 * helper functions422 */423 424/* write a pseudo-register value (w/o power sequence) */425static int reg_raw_write(struct hdac_device *codec, unsigned int reg,426			 unsigned int val)427{428	int err;429 430	mutex_lock(&codec->regmap_lock);431	if (!codec->regmap)432		err = hda_reg_write(codec, reg, val);433	else434		err = regmap_write(codec->regmap, reg, val);435	mutex_unlock(&codec->regmap_lock);436	return err;437}438 439/* a helper macro to call @func_call; retry with power-up if failed */440#define CALL_RAW_FUNC(codec, func_call)				\441	({							\442		int _err = func_call;				\443		if (_err == -EAGAIN) {				\444			_err = snd_hdac_power_up_pm(codec);	\445			if (_err >= 0)				\446				_err = func_call;		\447			snd_hdac_power_down_pm(codec);		\448		}						\449		_err;})450 451/**452 * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt453 * @codec: the codec object454 * @reg: pseudo register455 * @val: value to write456 *457 * Returns zero if successful or a negative error code.458 */459int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,460			      unsigned int val)461{462	return CALL_RAW_FUNC(codec, reg_raw_write(codec, reg, val));463}464EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);465 466static int reg_raw_read(struct hdac_device *codec, unsigned int reg,467			unsigned int *val, bool uncached)468{469	int err;470 471	mutex_lock(&codec->regmap_lock);472	if (uncached || !codec->regmap)473		err = hda_reg_read(codec, reg, val);474	else475		err = regmap_read(codec->regmap, reg, val);476	mutex_unlock(&codec->regmap_lock);477	return err;478}479 480static int __snd_hdac_regmap_read_raw(struct hdac_device *codec,481				      unsigned int reg, unsigned int *val,482				      bool uncached)483{484	return CALL_RAW_FUNC(codec, reg_raw_read(codec, reg, val, uncached));485}486 487/**488 * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt489 * @codec: the codec object490 * @reg: pseudo register491 * @val: pointer to store the read value492 *493 * Returns zero if successful or a negative error code.494 */495int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg,496			     unsigned int *val)497{498	return __snd_hdac_regmap_read_raw(codec, reg, val, false);499}500EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw);501 502/* Works like snd_hdac_regmap_read_raw(), but this doesn't read from the503 * cache but always via hda verbs.504 */505int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec,506				      unsigned int reg, unsigned int *val)507{508	return __snd_hdac_regmap_read_raw(codec, reg, val, true);509}510 511static int reg_raw_update(struct hdac_device *codec, unsigned int reg,512			  unsigned int mask, unsigned int val)513{514	unsigned int orig;515	bool change;516	int err;517 518	mutex_lock(&codec->regmap_lock);519	if (codec->regmap) {520		err = regmap_update_bits_check(codec->regmap, reg, mask, val,521					       &change);522		if (!err)523			err = change ? 1 : 0;524	} else {525		err = hda_reg_read(codec, reg, &orig);526		if (!err) {527			val &= mask;528			val |= orig & ~mask;529			if (val != orig) {530				err = hda_reg_write(codec, reg, val);531				if (!err)532					err = 1;533			}534		}535	}536	mutex_unlock(&codec->regmap_lock);537	return err;538}539 540/**541 * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt542 * @codec: the codec object543 * @reg: pseudo register544 * @mask: bit mask to update545 * @val: value to update546 *547 * Returns zero if successful or a negative error code.548 */549int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,550			       unsigned int mask, unsigned int val)551{552	return CALL_RAW_FUNC(codec, reg_raw_update(codec, reg, mask, val));553}554EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);555 556static int reg_raw_update_once(struct hdac_device *codec, unsigned int reg,557			       unsigned int mask, unsigned int val)558{559	int err = 0;560 561	if (!codec->regmap)562		return reg_raw_update(codec, reg, mask, val);563 564	mutex_lock(&codec->regmap_lock);565	/* Discard any updates to already initialised registers. */566	if (!regcache_reg_cached(codec->regmap, reg))567		err = regmap_update_bits(codec->regmap, reg, mask, val);568	mutex_unlock(&codec->regmap_lock);569	return err;570}571 572/**573 * snd_hdac_regmap_update_raw_once - initialize the register value only once574 * @codec: the codec object575 * @reg: pseudo register576 * @mask: bit mask to update577 * @val: value to update578 *579 * Performs the update of the register bits only once when the register580 * hasn't been initialized yet.  Used in HD-audio legacy driver.581 * Returns zero if successful or a negative error code582 */583int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg,584				    unsigned int mask, unsigned int val)585{586	return CALL_RAW_FUNC(codec, reg_raw_update_once(codec, reg, mask, val));587}588EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw_once);589 590/**591 * snd_hdac_regmap_sync - sync out the cached values for PM resume592 * @codec: the codec object593 */594void snd_hdac_regmap_sync(struct hdac_device *codec)595{596	mutex_lock(&codec->regmap_lock);597	if (codec->regmap)598		regcache_sync(codec->regmap);599	mutex_unlock(&codec->regmap_lock);600}601EXPORT_SYMBOL_GPL(snd_hdac_regmap_sync);602