Merge tag 'arm64-perf' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[linux-2.6-microblaze.git] / sound / hda / hdac_regmap.c
index eb8f7c3..bdbcd6b 100644 (file)
 #include <sound/hdaudio.h>
 #include <sound/hda_regmap.h>
 
-#ifdef CONFIG_PM
-#define codec_is_running(codec)                                \
-       (atomic_read(&(codec)->in_pm) ||                \
-        !pm_runtime_suspended(&(codec)->dev))
-#else
-#define codec_is_running(codec)                true
-#endif
+static int codec_pm_lock(struct hdac_device *codec)
+{
+       return snd_hdac_keep_power_up(codec);
+}
+
+static void codec_pm_unlock(struct hdac_device *codec, int lock)
+{
+       if (lock == 1)
+               snd_hdac_power_down_pm(codec);
+}
 
 #define get_verb(reg)  (((reg) >> 8) & 0xfff)
 
@@ -238,20 +241,28 @@ static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
        struct hdac_device *codec = context;
        int verb = get_verb(reg);
        int err;
+       int pm_lock = 0;
 
-       if (!codec_is_running(codec) && verb != AC_VERB_GET_POWER_STATE)
-               return -EAGAIN;
+       if (verb != AC_VERB_GET_POWER_STATE) {
+               pm_lock = codec_pm_lock(codec);
+               if (pm_lock < 0)
+                       return -EAGAIN;
+       }
        reg |= (codec->addr << 28);
-       if (is_stereo_amp_verb(reg))
-               return hda_reg_read_stereo_amp(codec, reg, val);
-       if (verb == AC_VERB_GET_PROC_COEF)
-               return hda_reg_read_coef(codec, reg, val);
+       if (is_stereo_amp_verb(reg)) {
+               err = hda_reg_read_stereo_amp(codec, reg, val);
+               goto out;
+       }
+       if (verb == AC_VERB_GET_PROC_COEF) {
+               err = hda_reg_read_coef(codec, reg, val);
+               goto out;
+       }
        if ((verb & 0x700) == AC_VERB_SET_AMP_GAIN_MUTE)
                reg &= ~AC_AMP_FAKE_MUTE;
 
        err = snd_hdac_exec_verb(codec, reg, 0, val);
        if (err < 0)
-               return err;
+               goto out;
        /* special handling for asymmetric reads */
        if (verb == AC_VERB_GET_POWER_STATE) {
                if (*val & AC_PWRST_ERROR)
@@ -259,7 +270,9 @@ static int hda_reg_read(void *context, unsigned int reg, unsigned int *val)
                else /* take only the actual state */
                        *val = (*val >> 4) & 0x0f;
        }
-       return 0;
+ out:
+       codec_pm_unlock(codec, pm_lock);
+       return err;
 }
 
 static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
@@ -267,6 +280,7 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
        struct hdac_device *codec = context;
        unsigned int verb;
        int i, bytes, err;
+       int pm_lock = 0;
 
        if (codec->caps_overwriting)
                return 0;
@@ -275,14 +289,21 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
        reg |= (codec->addr << 28);
        verb = get_verb(reg);
 
-       if (!codec_is_running(codec) && verb != AC_VERB_SET_POWER_STATE)
-               return codec->lazy_cache ? 0 : -EAGAIN;
+       if (verb != AC_VERB_SET_POWER_STATE) {
+               pm_lock = codec_pm_lock(codec);
+               if (pm_lock < 0)
+                       return codec->lazy_cache ? 0 : -EAGAIN;
+       }
 
-       if (is_stereo_amp_verb(reg))
-               return hda_reg_write_stereo_amp(codec, reg, val);
+       if (is_stereo_amp_verb(reg)) {
+               err = hda_reg_write_stereo_amp(codec, reg, val);
+               goto out;
+       }
 
-       if (verb == AC_VERB_SET_PROC_COEF)
-               return hda_reg_write_coef(codec, reg, val);
+       if (verb == AC_VERB_SET_PROC_COEF) {
+               err = hda_reg_write_coef(codec, reg, val);
+               goto out;
+       }
 
        switch (verb & 0xf00) {
        case AC_VERB_SET_AMP_GAIN_MUTE:
@@ -319,10 +340,12 @@ static int hda_reg_write(void *context, unsigned int reg, unsigned int val)
                reg |= (verb + i) << 8 | ((val >> (8 * i)) & 0xff);
                err = snd_hdac_exec_verb(codec, reg, 0, NULL);
                if (err < 0)
-                       return err;
+                       goto out;
        }
 
-       return 0;
+ out:
+       codec_pm_unlock(codec, pm_lock);
+       return err;
 }
 
 static const struct regmap_config hda_regmap_cfg = {