.reg_write = hda_reg_write,
        .use_single_read = true,
        .use_single_write = true,
+       .disable_locking = true,
 };
 
 /**
 static int reg_raw_write(struct hdac_device *codec, unsigned int reg,
                         unsigned int val)
 {
+       int err;
+
+       mutex_lock(&codec->regmap_lock);
        if (!codec->regmap)
-               return hda_reg_write(codec, reg, val);
+               err = hda_reg_write(codec, reg, val);
        else
-               return regmap_write(codec->regmap, reg, val);
+               err = regmap_write(codec->regmap, reg, val);
+       mutex_unlock(&codec->regmap_lock);
+       return err;
 }
 
+/* a helper macro to call @func_call; retry with power-up if failed */
+#define CALL_RAW_FUNC(codec, func_call)                                \
+       ({                                                      \
+               int _err = func_call;                           \
+               if (_err == -EAGAIN) {                          \
+                       _err = snd_hdac_power_up_pm(codec);     \
+                       if (_err >= 0)                          \
+                               _err = func_call;               \
+                       snd_hdac_power_down_pm(codec);          \
+               }                                               \
+               _err;})
+
 /**
  * snd_hdac_regmap_write_raw - write a pseudo register with power mgmt
  * @codec: the codec object
 int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg,
                              unsigned int val)
 {
-       int err;
-
-       err = reg_raw_write(codec, reg, val);
-       if (err == -EAGAIN) {
-               err = snd_hdac_power_up_pm(codec);
-               if (err >= 0)
-                       err = reg_raw_write(codec, reg, val);
-               snd_hdac_power_down_pm(codec);
-       }
-       return err;
+       return CALL_RAW_FUNC(codec, reg_raw_write(codec, reg, val));
 }
 EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw);
 
 static int reg_raw_read(struct hdac_device *codec, unsigned int reg,
                        unsigned int *val, bool uncached)
 {
+       int err;
+
+       mutex_lock(&codec->regmap_lock);
        if (uncached || !codec->regmap)
-               return hda_reg_read(codec, reg, val);
+               err = hda_reg_read(codec, reg, val);
        else
-               return regmap_read(codec->regmap, reg, val);
+               err = regmap_read(codec->regmap, reg, val);
+       mutex_unlock(&codec->regmap_lock);
+       return err;
 }
 
 static int __snd_hdac_regmap_read_raw(struct hdac_device *codec,
                                      unsigned int reg, unsigned int *val,
                                      bool uncached)
 {
-       int err;
-
-       err = reg_raw_read(codec, reg, val, uncached);
-       if (err == -EAGAIN) {
-               err = snd_hdac_power_up_pm(codec);
-               if (err >= 0)
-                       err = reg_raw_read(codec, reg, val, uncached);
-               snd_hdac_power_down_pm(codec);
-       }
-       return err;
+       return CALL_RAW_FUNC(codec, reg_raw_read(codec, reg, val, uncached));
 }
 
 /**
        return __snd_hdac_regmap_read_raw(codec, reg, val, true);
 }
 
+static int reg_raw_update(struct hdac_device *codec, unsigned int reg,
+                         unsigned int mask, unsigned int val)
+{
+       unsigned int orig;
+       bool change;
+       int err;
+
+       mutex_lock(&codec->regmap_lock);
+       if (codec->regmap) {
+               err = regmap_update_bits_check(codec->regmap, reg, mask, val,
+                                              &change);
+               if (!err)
+                       err = change ? 1 : 0;
+       } else {
+               err = hda_reg_read(codec, reg, &orig);
+               if (!err) {
+                       val &= mask;
+                       val |= orig & ~mask;
+                       if (val != orig) {
+                               err = hda_reg_write(codec, reg, val);
+                               if (!err)
+                                       err = 1;
+                       }
+               }
+       }
+       mutex_unlock(&codec->regmap_lock);
+       return err;
+}
+
 /**
  * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt
  * @codec: the codec object
  */
 int snd_hdac_regmap_update_raw(struct hdac_device *codec, unsigned int reg,
                               unsigned int mask, unsigned int val)
+{
+       return CALL_RAW_FUNC(codec, reg_raw_update(codec, reg, mask, val));
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);
+
+static int reg_raw_update_once(struct hdac_device *codec, unsigned int reg,
+                              unsigned int mask, unsigned int val)
 {
        unsigned int orig;
        int err;
 
-       val &= mask;
-       err = snd_hdac_regmap_read_raw(codec, reg, &orig);
-       if (err < 0)
-               return err;
-       val |= orig & ~mask;
-       if (val == orig)
-               return 0;
-       err = snd_hdac_regmap_write_raw(codec, reg, val);
+       if (!codec->regmap)
+               return reg_raw_update(codec, reg, mask, val);
+
+       mutex_lock(&codec->regmap_lock);
+       regcache_cache_only(codec->regmap, true);
+       err = regmap_read(codec->regmap, reg, &orig);
+       regcache_cache_only(codec->regmap, false);
        if (err < 0)
-               return err;
-       return 1;
+               err = regmap_update_bits(codec->regmap, reg, mask, val);
+       mutex_unlock(&codec->regmap_lock);
+       return err;
 }
-EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw);
+
+/**
+ * snd_hdac_regmap_update_raw_once - initialize the register value only once
+ * @codec: the codec object
+ * @reg: pseudo register
+ * @mask: bit mask to update
+ * @val: value to update
+ *
+ * Performs the update of the register bits only once when the register
+ * hasn't been initialized yet.  Used in HD-audio legacy driver.
+ * Returns zero if successful or a negative error code
+ */
+int snd_hdac_regmap_update_raw_once(struct hdac_device *codec, unsigned int reg,
+                                   unsigned int mask, unsigned int val)
+{
+       return CALL_RAW_FUNC(codec, reg_raw_update_once(codec, reg, mask, val));
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_update_raw_once);
+
+/**
+ * snd_hdac_regmap_sync - sync out the cached values for PM resume
+ * @codec: the codec object
+ */
+void snd_hdac_regmap_sync(struct hdac_device *codec)
+{
+       if (codec->regmap) {
+               mutex_lock(&codec->regmap_lock);
+               regcache_sync(codec->regmap);
+               mutex_unlock(&codec->regmap_lock);
+       }
+}
+EXPORT_SYMBOL_GPL(snd_hdac_regmap_sync);
 
 }
 EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps);
 
+static unsigned int encode_amp(struct hda_codec *codec, hda_nid_t nid,
+                              int ch, int dir, int idx)
+{
+       unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
+
+       /* enable fake mute if no h/w mute but min=mute */
+       if ((query_amp_caps(codec, nid, dir) &
+            (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) == AC_AMPCAP_MIN_MUTE)
+               cmd |= AC_AMP_FAKE_MUTE;
+       return cmd;
+}
+
 /**
  * snd_hda_codec_amp_update - update the AMP mono value
  * @codec: HD-audio codec
 int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid,
                             int ch, int dir, int idx, int mask, int val)
 {
-       unsigned int cmd = snd_hdac_regmap_encode_amp(nid, ch, dir, idx);
+       unsigned int cmd = encode_amp(codec, nid, ch, dir, idx);
 
-       /* enable fake mute if no h/w mute but min=mute */
-       if ((query_amp_caps(codec, nid, dir) &
-            (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) == AC_AMPCAP_MIN_MUTE)
-               cmd |= AC_AMP_FAKE_MUTE;
        return snd_hdac_regmap_update_raw(&codec->core, cmd, mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update);
 int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
                           int dir, int idx, int mask, int val)
 {
-       int orig;
+       unsigned int cmd = encode_amp(codec, nid, ch, dir, idx);
 
        if (!codec->core.regmap)
                return -EINVAL;
-       regcache_cache_only(codec->core.regmap, true);
-       orig = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
-       regcache_cache_only(codec->core.regmap, false);
-       if (orig >= 0)
-               return 0;
-       return snd_hda_codec_amp_update(codec, nid, ch, dir, idx, mask, val);
+       return snd_hdac_regmap_update_raw_once(&codec->core, cmd, mask, val);
 }
 EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
 
        else {
                if (codec->patch_ops.init)
                        codec->patch_ops.init(codec);
-               if (codec->core.regmap)
-                       regcache_sync(codec->core.regmap);
+               snd_hda_regmap_sync(codec);
        }
 
        if (codec->jackpoll_interval)