| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 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 | static int codec_pm_lock(struct hdac_device *codec) | 
 | 25 | { | 
 | 26 | 	return snd_hdac_keep_power_up(codec); | 
 | 27 | } | 
 | 28 |  | 
 | 29 | static void codec_pm_unlock(struct hdac_device *codec, int lock) | 
 | 30 | { | 
 | 31 | 	if (lock == 1) | 
 | 32 | 		snd_hdac_power_down_pm(codec); | 
 | 33 | } | 
 | 34 |  | 
 | 35 | #define get_verb(reg)	(((reg) >> 8) & 0xfff) | 
 | 36 |  | 
 | 37 | static bool hda_volatile_reg(struct device *dev, unsigned int reg) | 
 | 38 | { | 
 | 39 | 	struct hdac_device *codec = dev_to_hdac_dev(dev); | 
 | 40 | 	unsigned int verb = get_verb(reg); | 
 | 41 |  | 
 | 42 | 	switch (verb) { | 
 | 43 | 	case AC_VERB_GET_PROC_COEF: | 
 | 44 | 		return !codec->cache_coef; | 
 | 45 | 	case AC_VERB_GET_COEF_INDEX: | 
 | 46 | 	case AC_VERB_GET_PROC_STATE: | 
 | 47 | 	case AC_VERB_GET_POWER_STATE: | 
 | 48 | 	case AC_VERB_GET_PIN_SENSE: | 
 | 49 | 	case AC_VERB_GET_HDMI_DIP_SIZE: | 
 | 50 | 	case AC_VERB_GET_HDMI_ELDD: | 
 | 51 | 	case AC_VERB_GET_HDMI_DIP_INDEX: | 
 | 52 | 	case AC_VERB_GET_HDMI_DIP_DATA: | 
 | 53 | 	case AC_VERB_GET_HDMI_DIP_XMIT: | 
 | 54 | 	case AC_VERB_GET_HDMI_CP_CTRL: | 
 | 55 | 	case AC_VERB_GET_HDMI_CHAN_SLOT: | 
 | 56 | 	case AC_VERB_GET_DEVICE_SEL: | 
 | 57 | 	case AC_VERB_GET_DEVICE_LIST:	/* read-only volatile */ | 
 | 58 | 		return true; | 
 | 59 | 	} | 
 | 60 |  | 
 | 61 | 	return false; | 
 | 62 | } | 
 | 63 |  | 
 | 64 | static bool hda_writeable_reg(struct device *dev, unsigned int reg) | 
 | 65 | { | 
 | 66 | 	struct hdac_device *codec = dev_to_hdac_dev(dev); | 
 | 67 | 	unsigned int verb = get_verb(reg); | 
 | 68 | 	const unsigned int *v; | 
 | 69 | 	int i; | 
 | 70 |  | 
 | 71 | 	snd_array_for_each(&codec->vendor_verbs, i, v) { | 
 | 72 | 		if (verb == *v) | 
 | 73 | 			return true; | 
 | 74 | 	} | 
 | 75 |  | 
 | 76 | 	if (codec->caps_overwriting) | 
 | 77 | 		return true; | 
 | 78 |  | 
 | 79 | 	switch (verb & 0xf00) { | 
 | 80 | 	case AC_VERB_GET_STREAM_FORMAT: | 
 | 81 | 	case AC_VERB_GET_AMP_GAIN_MUTE: | 
 | 82 | 		return true; | 
 | 83 | 	case AC_VERB_GET_PROC_COEF: | 
 | 84 | 		return codec->cache_coef; | 
 | 85 | 	case 0xf00: | 
 | 86 | 		break; | 
 | 87 | 	default: | 
 | 88 | 		return false; | 
 | 89 | 	} | 
 | 90 |  | 
 | 91 | 	switch (verb) { | 
 | 92 | 	case AC_VERB_GET_CONNECT_SEL: | 
 | 93 | 	case AC_VERB_GET_SDI_SELECT: | 
 | 94 | 	case AC_VERB_GET_PIN_WIDGET_CONTROL: | 
 | 95 | 	case AC_VERB_GET_UNSOLICITED_RESPONSE: /* only as SET_UNSOLICITED_ENABLE */ | 
 | 96 | 	case AC_VERB_GET_BEEP_CONTROL: | 
 | 97 | 	case AC_VERB_GET_EAPD_BTLENABLE: | 
 | 98 | 	case AC_VERB_GET_DIGI_CONVERT_1: | 
 | 99 | 	case AC_VERB_GET_DIGI_CONVERT_2: /* only for beep control */ | 
 | 100 | 	case AC_VERB_GET_VOLUME_KNOB_CONTROL: | 
 | 101 | 	case AC_VERB_GET_GPIO_MASK: | 
 | 102 | 	case AC_VERB_GET_GPIO_DIRECTION: | 
 | 103 | 	case AC_VERB_GET_GPIO_DATA: /* not for volatile read */ | 
 | 104 | 	case AC_VERB_GET_GPIO_WAKE_MASK: | 
 | 105 | 	case AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK: | 
 | 106 | 	case AC_VERB_GET_GPIO_STICKY_MASK: | 
 | 107 | 		return true; | 
 | 108 | 	} | 
 | 109 |  | 
 | 110 | 	return false; | 
 | 111 | } | 
 | 112 |  | 
 | 113 | static bool hda_readable_reg(struct device *dev, unsigned int reg) | 
 | 114 | { | 
 | 115 | 	struct hdac_device *codec = dev_to_hdac_dev(dev); | 
 | 116 | 	unsigned int verb = get_verb(reg); | 
 | 117 |  | 
 | 118 | 	if (codec->caps_overwriting) | 
 | 119 | 		return true; | 
 | 120 |  | 
 | 121 | 	switch (verb) { | 
 | 122 | 	case AC_VERB_PARAMETERS: | 
 | 123 | 	case AC_VERB_GET_CONNECT_LIST: | 
 | 124 | 	case AC_VERB_GET_SUBSYSTEM_ID: | 
 | 125 | 		return true; | 
 | 126 | 	/* below are basically writable, but disabled for reducing unnecessary | 
 | 127 | 	 * writes at sync | 
 | 128 | 	 */ | 
 | 129 | 	case AC_VERB_GET_CONFIG_DEFAULT: /* usually just read */ | 
 | 130 | 	case AC_VERB_GET_CONV: /* managed in PCM code */ | 
 | 131 | 	case AC_VERB_GET_CVT_CHAN_COUNT: /* managed in HDMI CA code */ | 
 | 132 | 		return true; | 
 | 133 | 	} | 
 | 134 |  | 
 | 135 | 	return hda_writeable_reg(dev, reg); | 
 | 136 | } | 
 | 137 |  | 
 | 138 | /* | 
 | 139 |  * Stereo amp pseudo register: | 
 | 140 |  * for making easier to handle the stereo volume control, we provide a | 
 | 141 |  * fake register to deal both left and right channels by a single | 
 | 142 |  * (pseudo) register access.  A verb consisting of SET_AMP_GAIN with | 
 | 143 |  * *both* SET_LEFT and SET_RIGHT bits takes a 16bit value, the lower 8bit | 
 | 144 |  * for the left and the upper 8bit for the right channel. | 
 | 145 |  */ | 
 | 146 | static bool is_stereo_amp_verb(unsigned int reg) | 
 | 147 | { | 
 | 148 | 	if (((reg >> 8) & 0x700) != AC_VERB_SET_AMP_GAIN_MUTE) | 
 | 149 | 		return false; | 
 | 150 | 	return (reg & (AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT)) == | 
 | 151 | 		(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT); | 
 | 152 | } | 
 | 153 |  | 
 | 154 | /* read a pseudo stereo amp register (16bit left+right) */ | 
 | 155 | static int hda_reg_read_stereo_amp(struct hdac_device *codec, | 
 | 156 | 				   unsigned int reg, unsigned int *val) | 
 | 157 | { | 
 | 158 | 	unsigned int left, right; | 
 | 159 | 	int err; | 
 | 160 |  | 
 | 161 | 	reg &= ~(AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT); | 
 | 162 | 	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_LEFT, 0, &left); | 
 | 163 | 	if (err < 0) | 
 | 164 | 		return err; | 
 | 165 | 	err = snd_hdac_exec_verb(codec, reg | AC_AMP_GET_RIGHT, 0, &right); | 
 | 166 | 	if (err < 0) | 
 | 167 | 		return err; | 
 | 168 | 	*val = left | (right << 8); | 
 | 169 | 	return 0; | 
 | 170 | } | 
 | 171 |  | 
 | 172 | /* write a pseudo stereo amp register (16bit left+right) */ | 
 | 173 | static int hda_reg_write_stereo_amp(struct hdac_device *codec, | 
 | 174 | 				    unsigned int reg, unsigned int val) | 
 | 175 | { | 
 | 176 | 	int err; | 
 | 177 | 	unsigned int verb, left, right; | 
 | 178 |  | 
 | 179 | 	verb = AC_VERB_SET_AMP_GAIN_MUTE << 8; | 
 | 180 | 	if (reg & AC_AMP_GET_OUTPUT) | 
 | 181 | 		verb |= AC_AMP_SET_OUTPUT; | 
 | 182 | 	else | 
 | 183 | 		verb |= AC_AMP_SET_INPUT | ((reg & 0xf) << 8); | 
 | 184 | 	reg = (reg & ~0xfffff) | verb; | 
 | 185 |  | 
 | 186 | 	left = val & 0xff; | 
 | 187 | 	right = (val >> 8) & 0xff; | 
 | 188 | 	if (left == right) { | 
 | 189 | 		reg |= AC_AMP_SET_LEFT | AC_AMP_SET_RIGHT; | 
 | 190 | 		return snd_hdac_exec_verb(codec, reg | left, 0, NULL); | 
 | 191 | 	} | 
 | 192 |  | 
 | 193 | 	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_LEFT | left, 0, NULL); | 
 | 194 | 	if (err < 0) | 
 | 195 | 		return err; | 
 | 196 | 	err = snd_hdac_exec_verb(codec, reg | AC_AMP_SET_RIGHT | right, 0, NULL); | 
 | 197 | 	if (err < 0) | 
 | 198 | 		return err; | 
 | 199 | 	return 0; | 
 | 200 | } | 
 | 201 |  | 
 | 202 | /* read a pseudo coef register (16bit) */ | 
 | 203 | static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg, | 
 | 204 | 			     unsigned int *val) | 
 | 205 | { | 
 | 206 | 	unsigned int verb; | 
 | 207 | 	int err; | 
 | 208 |  | 
 | 209 | 	if (!codec->cache_coef) | 
 | 210 | 		return -EINVAL; | 
 | 211 | 	/* LSB 8bit = coef index */ | 
 | 212 | 	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8); | 
 | 213 | 	err = snd_hdac_exec_verb(codec, verb, 0, NULL); | 
 | 214 | 	if (err < 0) | 
 | 215 | 		return err; | 
 | 216 | 	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8); | 
 | 217 | 	return snd_hdac_exec_verb(codec, verb, 0, val); | 
 | 218 | } | 
 | 219 |  | 
 | 220 | /* write a pseudo coef register (16bit) */ | 
 | 221 | static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg, | 
 | 222 | 			      unsigned int val) | 
 | 223 | { | 
 | 224 | 	unsigned int verb; | 
 | 225 | 	int err; | 
 | 226 |  | 
 | 227 | 	if (!codec->cache_coef) | 
 | 228 | 		return -EINVAL; | 
 | 229 | 	/* LSB 8bit = coef index */ | 
 | 230 | 	verb = (reg & ~0xfff00) | (AC_VERB_SET_COEF_INDEX << 8); | 
 | 231 | 	err = snd_hdac_exec_verb(codec, verb, 0, NULL); | 
 | 232 | 	if (err < 0) | 
 | 233 | 		return err; | 
 | 234 | 	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) | | 
 | 235 | 		(val & 0xffff); | 
 | 236 | 	return snd_hdac_exec_verb(codec, verb, 0, NULL); | 
 | 237 | } | 
 | 238 |  | 
 | 239 | static int hda_reg_read(void *context, unsigned int reg, unsigned int *val) | 
 | 240 | { | 
 | 241 | 	struct hdac_device *codec = context; | 
 | 242 | 	int verb = get_verb(reg); | 
 | 243 | 	int err; | 
 | 244 | 	int pm_lock = 0; | 
 | 245 |  | 
 | 246 | 	if (verb != AC_VERB_GET_POWER_STATE) { | 
 | 247 | 		pm_lock = codec_pm_lock(codec); | 
 | 248 | 		if (pm_lock < 0) | 
 | 249 | 			return -EAGAIN; | 
 | 250 | 	} | 
 | 251 | 	reg |= (codec->addr << 28); | 
 | 252 | 	if (is_stereo_amp_verb(reg)) { | 
 | 253 | 		err = hda_reg_read_stereo_amp(codec, reg, val); | 
 | 254 | 		goto out; | 
 | 255 | 	} | 
 | 256 | 	if (verb == AC_VERB_GET_PROC_COEF) { | 
 | 257 | 		err = hda_reg_read_coef(codec, reg, val); | 
 | 258 | 		goto out; | 
 | 259 | 	} | 
 | 260 | 	if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE) | 
 | 261 | 		reg &= ~AC_AMP_FAKE_MUTE; | 
 | 262 |  | 
 | 263 | 	err = snd_hdac_exec_verb(codec, reg, 0, val); | 
 | 264 | 	if (err < 0) | 
 | 265 | 		goto out; | 
 | 266 | 	/* special handling for asymmetric reads */ | 
 | 267 | 	if (verb == AC_VERB_GET_POWER_STATE) { | 
 | 268 | 		if (*val & AC_PWRST_ERROR) | 
 | 269 | 			*val = -1; | 
 | 270 | 		else /* take only the actual state */ | 
 | 271 | 			*val = (*val >> 4) & 0x0f; | 
 | 272 | 	} | 
 | 273 |  out: | 
 | 274 | 	codec_pm_unlock(codec, pm_lock); | 
 | 275 | 	return err; | 
 | 276 | } | 
 | 277 |  | 
 | 278 | static int hda_reg_write(void *context, unsigned int reg, unsigned int val) | 
 | 279 | { | 
 | 280 | 	struct hdac_device *codec = context; | 
 | 281 | 	unsigned int verb; | 
 | 282 | 	int i, bytes, err; | 
 | 283 | 	int pm_lock = 0; | 
 | 284 |  | 
 | 285 | 	if (codec->caps_overwriting) | 
 | 286 | 		return 0; | 
 | 287 |  | 
 | 288 | 	reg &= ~0x00080000U; /* drop GET bit */ | 
 | 289 | 	reg |= (codec->addr << 28); | 
 | 290 | 	verb = get_verb(reg); | 
 | 291 |  | 
 | 292 | 	if (verb != AC_VERB_SET_POWER_STATE) { | 
 | 293 | 		pm_lock = codec_pm_lock(codec); | 
 | 294 | 		if (pm_lock < 0) | 
 | 295 | 			return codec->lazy_cache ? 0 : -EAGAIN; | 
 | 296 | 	} | 
 | 297 |  | 
 | 298 | 	if (is_stereo_amp_verb(reg)) { | 
 | 299 | 		err = hda_reg_write_stereo_amp(codec, reg, val); | 
 | 300 | 		goto out; | 
 | 301 | 	} | 
 | 302 |  | 
 | 303 | 	if (verb == AC_VERB_SET_PROC_COEF) { | 
 | 304 | 		err = hda_reg_write_coef(codec, reg, val); | 
 | 305 | 		goto out; | 
 | 306 | 	} | 
 | 307 |  | 
 | 308 | 	switch (verb & 0xf00) { | 
 | 309 | 	case AC_VERB_SET_AMP_GAIN_MUTE: | 
 | 310 | 		if ((reg & AC_AMP_FAKE_MUTE) && (val & AC_AMP_MUTE)) | 
 | 311 | 			val = 0; | 
 | 312 | 		verb = AC_VERB_SET_AMP_GAIN_MUTE; | 
 | 313 | 		if (reg & AC_AMP_GET_LEFT) | 
 | 314 | 			verb |= AC_AMP_SET_LEFT >> 8; | 
 | 315 | 		else | 
 | 316 | 			verb |= AC_AMP_SET_RIGHT >> 8; | 
 | 317 | 		if (reg & AC_AMP_GET_OUTPUT) { | 
 | 318 | 			verb |= AC_AMP_SET_OUTPUT >> 8; | 
 | 319 | 		} else { | 
 | 320 | 			verb |= AC_AMP_SET_INPUT >> 8; | 
 | 321 | 			verb |= reg & 0xf; | 
 | 322 | 		} | 
 | 323 | 		break; | 
 | 324 | 	} | 
 | 325 |  | 
 | 326 | 	switch (verb) { | 
 | 327 | 	case AC_VERB_SET_DIGI_CONVERT_1: | 
 | 328 | 		bytes = 2; | 
 | 329 | 		break; | 
 | 330 | 	case AC_VERB_SET_CONFIG_DEFAULT_BYTES_0: | 
 | 331 | 		bytes = 4; | 
 | 332 | 		break; | 
 | 333 | 	default: | 
 | 334 | 		bytes = 1; | 
 | 335 | 		break; | 
 | 336 | 	} | 
 | 337 |  | 
 | 338 | 	for (i = 0; i < bytes; i++) { | 
 | 339 | 		reg &= ~0xfffff; | 
 | 340 | 		reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff); | 
 | 341 | 		err = snd_hdac_exec_verb(codec, reg, 0, NULL); | 
 | 342 | 		if (err < 0) | 
 | 343 | 			goto out; | 
 | 344 | 	} | 
 | 345 |  | 
 | 346 |  out: | 
 | 347 | 	codec_pm_unlock(codec, pm_lock); | 
 | 348 | 	return err; | 
 | 349 | } | 
 | 350 |  | 
 | 351 | static const struct regmap_config hda_regmap_cfg = { | 
 | 352 | 	.name = "hdaudio", | 
 | 353 | 	.reg_bits = 32, | 
 | 354 | 	.val_bits = 32, | 
 | 355 | 	.max_register = 0xfffffff, | 
 | 356 | 	.writeable_reg = hda_writeable_reg, | 
 | 357 | 	.readable_reg = hda_readable_reg, | 
 | 358 | 	.volatile_reg = hda_volatile_reg, | 
 | 359 | 	.cache_type = REGCACHE_RBTREE, | 
 | 360 | 	.reg_read = hda_reg_read, | 
 | 361 | 	.reg_write = hda_reg_write, | 
 | 362 | 	.use_single_rw = true, | 
 | 363 | }; | 
 | 364 |  | 
 | 365 | /** | 
 | 366 |  * snd_hdac_regmap_init - Initialize regmap for HDA register accesses | 
 | 367 |  * @codec: the codec object | 
 | 368 |  * | 
 | 369 |  * Returns zero for success or a negative error code. | 
 | 370 |  */ | 
 | 371 | int snd_hdac_regmap_init(struct hdac_device *codec) | 
 | 372 | { | 
 | 373 | 	struct regmap *regmap; | 
 | 374 |  | 
 | 375 | 	regmap = regmap_init(&codec->dev, NULL, codec, &hda_regmap_cfg); | 
 | 376 | 	if (IS_ERR(regmap)) | 
 | 377 | 		return PTR_ERR(regmap); | 
 | 378 | 	codec->regmap = regmap; | 
 | 379 | 	snd_array_init(&codec->vendor_verbs, sizeof(unsigned int), 8); | 
 | 380 | 	return 0; | 
 | 381 | } | 
 | 382 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_init); | 
 | 383 |  | 
 | 384 | /** | 
 | 385 |  * snd_hdac_regmap_init - Release the regmap from HDA codec | 
 | 386 |  * @codec: the codec object | 
 | 387 |  */ | 
 | 388 | void snd_hdac_regmap_exit(struct hdac_device *codec) | 
 | 389 | { | 
 | 390 | 	if (codec->regmap) { | 
 | 391 | 		regmap_exit(codec->regmap); | 
 | 392 | 		codec->regmap = NULL; | 
 | 393 | 		snd_array_free(&codec->vendor_verbs); | 
 | 394 | 	} | 
 | 395 | } | 
 | 396 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_exit); | 
 | 397 |  | 
 | 398 | /** | 
 | 399 |  * snd_hdac_regmap_add_vendor_verb - add a vendor-specific verb to regmap | 
 | 400 |  * @codec: the codec object | 
 | 401 |  * @verb: verb to allow accessing via regmap | 
 | 402 |  * | 
 | 403 |  * Returns zero for success or a negative error code. | 
 | 404 |  */ | 
 | 405 | int snd_hdac_regmap_add_vendor_verb(struct hdac_device *codec, | 
 | 406 | 				    unsigned int verb) | 
 | 407 | { | 
 | 408 | 	unsigned int *p = snd_array_new(&codec->vendor_verbs); | 
 | 409 |  | 
 | 410 | 	if (!p) | 
 | 411 | 		return -ENOMEM; | 
 | 412 | 	*p = verb | 0x800; /* set GET bit */ | 
 | 413 | 	return 0; | 
 | 414 | } | 
 | 415 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_add_vendor_verb); | 
 | 416 |  | 
 | 417 | /* | 
 | 418 |  * helper functions | 
 | 419 |  */ | 
 | 420 |  | 
 | 421 | /* write a pseudo-register value (w/o power sequence) */ | 
 | 422 | static int reg_raw_write(struct hdac_device *codec, unsigned int reg, | 
 | 423 | 			 unsigned int val) | 
 | 424 | { | 
 | 425 | 	if (!codec->regmap) | 
 | 426 | 		return hda_reg_write(codec, reg, val); | 
 | 427 | 	else | 
 | 428 | 		return regmap_write(codec->regmap, reg, val); | 
 | 429 | } | 
 | 430 |  | 
 | 431 | /** | 
 | 432 |  * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt | 
 | 433 |  * @codec: the codec object | 
 | 434 |  * @reg: pseudo register | 
 | 435 |  * @val: value to write | 
 | 436 |  * | 
 | 437 |  * Returns zero if successful or a negative error code. | 
 | 438 |  */ | 
 | 439 | int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, | 
 | 440 | 			      unsigned int val) | 
 | 441 | { | 
 | 442 | 	int err; | 
 | 443 |  | 
 | 444 | 	err = reg_raw_write(codec, reg, val); | 
 | 445 | 	if (err == -EAGAIN) { | 
 | 446 | 		err = snd_hdac_power_up_pm(codec); | 
 | 447 | 		if (err >= 0) | 
 | 448 | 			err = reg_raw_write(codec, reg, val); | 
 | 449 | 		snd_hdac_power_down_pm(codec); | 
 | 450 | 	} | 
 | 451 | 	return err; | 
 | 452 | } | 
 | 453 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw); | 
 | 454 |  | 
 | 455 | static int reg_raw_read(struct hdac_device *codec, unsigned int reg, | 
 | 456 | 			unsigned int *val, bool uncached) | 
 | 457 | { | 
 | 458 | 	if (uncached || !codec->regmap) | 
 | 459 | 		return hda_reg_read(codec, reg, val); | 
 | 460 | 	else | 
 | 461 | 		return regmap_read(codec->regmap, reg, val); | 
 | 462 | } | 
 | 463 |  | 
 | 464 | static int __snd_hdac_regmap_read_raw(struct hdac_device *codec, | 
 | 465 | 				      unsigned int reg, unsigned int *val, | 
 | 466 | 				      bool uncached) | 
 | 467 | { | 
 | 468 | 	int err; | 
 | 469 |  | 
 | 470 | 	err = reg_raw_read(codec, reg, val, uncached); | 
 | 471 | 	if (err == -EAGAIN) { | 
 | 472 | 		err = snd_hdac_power_up_pm(codec); | 
 | 473 | 		if (err >= 0) | 
 | 474 | 			err = reg_raw_read(codec, reg, val, uncached); | 
 | 475 | 		snd_hdac_power_down_pm(codec); | 
 | 476 | 	} | 
 | 477 | 	return err; | 
 | 478 | } | 
 | 479 |  | 
 | 480 | /** | 
 | 481 |  * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt | 
 | 482 |  * @codec: the codec object | 
 | 483 |  * @reg: pseudo register | 
 | 484 |  * @val: pointer to store the read value | 
 | 485 |  * | 
 | 486 |  * Returns zero if successful or a negative error code. | 
 | 487 |  */ | 
 | 488 | int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, | 
 | 489 | 			     unsigned int *val) | 
 | 490 | { | 
 | 491 | 	return __snd_hdac_regmap_read_raw(codec, reg, val, false); | 
 | 492 | } | 
 | 493 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw); | 
 | 494 |  | 
 | 495 | /* Works like snd_hdac_regmap_read_raw(), but this doesn't read from the | 
 | 496 |  * cache but always via hda verbs. | 
 | 497 |  */ | 
 | 498 | int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec, | 
 | 499 | 				      unsigned int reg, unsigned int *val) | 
 | 500 | { | 
 | 501 | 	return __snd_hdac_regmap_read_raw(codec, reg, val, true); | 
 | 502 | } | 
 | 503 |  | 
 | 504 | /** | 
 | 505 |  * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt | 
 | 506 |  * @codec: the codec object | 
 | 507 |  * @reg: pseudo register | 
 | 508 |  * @mask: bit mask to udpate | 
 | 509 |  * @val: value to update | 
 | 510 |  * | 
 | 511 |  * Returns zero if successful or a negative error code. | 
 | 512 |  */ | 
 | 513 | int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg, | 
 | 514 | 			       unsigned int mask, unsigned int val) | 
 | 515 | { | 
 | 516 | 	unsigned int orig; | 
 | 517 | 	int err; | 
 | 518 |  | 
 | 519 | 	val &= mask; | 
 | 520 | 	err = snd_hdac_regmap_read_raw(codec, reg, &orig); | 
 | 521 | 	if (err < 0) | 
 | 522 | 		return err; | 
 | 523 | 	val |= orig & ~mask; | 
 | 524 | 	if (val == orig) | 
 | 525 | 		return 0; | 
 | 526 | 	err = snd_hdac_regmap_write_raw(codec, reg, val); | 
 | 527 | 	if (err < 0) | 
 | 528 | 		return err; | 
 | 529 | 	return 1; | 
 | 530 | } | 
 | 531 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw); |