root/sound/hda/hdac_regmap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. codec_pm_lock
  2. codec_pm_unlock
  3. hda_volatile_reg
  4. hda_writeable_reg
  5. hda_readable_reg
  6. is_stereo_amp_verb
  7. hda_reg_read_stereo_amp
  8. hda_reg_write_stereo_amp
  9. hda_reg_read_coef
  10. hda_reg_write_coef
  11. hda_reg_read
  12. hda_reg_write
  13. snd_hdac_regmap_init
  14. snd_hdac_regmap_exit
  15. snd_hdac_regmap_add_vendor_verb
  16. reg_raw_write
  17. snd_hdac_regmap_write_raw
  18. reg_raw_read
  19. __snd_hdac_regmap_read_raw
  20. snd_hdac_regmap_read_raw
  21. snd_hdac_regmap_read_raw_uncached
  22. reg_raw_update
  23. snd_hdac_regmap_update_raw
  24. reg_raw_update_once
  25. snd_hdac_regmap_update_raw_once
  26. snd_hdac_regmap_sync

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

/* [<][>][^][v][top][bottom][index][help] */