Merge remote-tracking branch 'asoc/topic/dapm' into asoc-next
authorMark Brown <broonie@kernel.org>
Fri, 5 Jun 2015 17:54:45 +0000 (18:54 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 5 Jun 2015 17:54:45 +0000 (18:54 +0100)
18 files changed:
1  2 
include/sound/soc-dapm.h
include/sound/soc.h
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5677.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/uda1380.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8737.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9713.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c

diff --combined include/sound/soc-dapm.h
index 1065095c6973555f2ba8f835b5321df647b5bc21,b9170e2bc5ab71a29c3ce1b983759b0d1cdbaf04..2f66e1c27f50610cbeb1a170d535cdf63eb23dc6
@@@ -107,6 -107,10 +107,10 @@@ struct device
  {     .id = snd_soc_dapm_mux, .name = wname, \
        SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .kcontrol_news = wcontrols, .num_kcontrols = 1}
+ #define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
+ {     .id = snd_soc_dapm_demux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
  
  /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
  #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
        .tlv.p = (tlv_array), \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
 -      .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
 +      .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
  #define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \
        SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array)
  #define SOC_DAPM_ENUM(xname, xenum) \
@@@ -444,11 -448,15 +448,15 @@@ int snd_soc_dapm_dai_get_connected_widg
  struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
        struct snd_kcontrol *kcontrol);
  
+ int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
+       enum snd_soc_bias_level level);
  /* dapm widget types */
  enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
        snd_soc_dapm_output,            /* output pin */
        snd_soc_dapm_mux,                       /* selects 1 analog signal from many inputs */
+       snd_soc_dapm_demux,                     /* connects the input to one of multiple outputs */
        snd_soc_dapm_mixer,                     /* mixes several analog signals together */
        snd_soc_dapm_mixer_named_ctl,           /* mixer with named controls */
        snd_soc_dapm_pga,                       /* programmable gain/attenuation (volume) */
@@@ -585,6 -593,10 +593,10 @@@ struct snd_soc_dapm_update 
        int val;
  };
  
+ struct snd_soc_dapm_wcache {
+       struct snd_soc_dapm_widget *widget;
+ };
  /* DAPM context */
  struct snd_soc_dapm_context {
        enum snd_soc_bias_level bias_level;
        int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
                              enum snd_soc_bias_level level);
  
+       struct snd_soc_dapm_wcache path_sink_cache;
+       struct snd_soc_dapm_wcache path_source_cache;
  #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_dapm;
  #endif
@@@ -623,4 -638,35 +638,35 @@@ struct snd_soc_dapm_stats 
        int neighbour_checks;
  };
  
+ /**
+  * snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
+  * @dapm: The DAPM context to initialize
+  * @level: The DAPM level to initialize to
+  *
+  * This function only sets the driver internal state of the DAPM level and will
+  * not modify the state of the device. Hence it should not be used during normal
+  * operation, but only to synchronize the internal state to the device state.
+  * E.g. during driver probe to set the DAPM level to the one corresponding with
+  * the power-on reset state of the device.
+  *
+  * To change the DAPM state of the device use snd_soc_dapm_set_bias_level().
+  */
+ static inline void snd_soc_dapm_init_bias_level(
+       struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
+ {
+       dapm->bias_level = level;
+ }
+ /**
+  * snd_soc_dapm_get_bias_level() - Get current DAPM bias level
+  * @dapm: The context for which to get the bias level
+  *
+  * Returns: The current bias level of the passed DAPM context.
+  */
+ static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
+       struct snd_soc_dapm_context *dapm)
+ {
+       return dapm->bias_level;
+ }
  #endif
diff --combined include/sound/soc.h
index f6226914acfee0d2486d8e57095dbaead1b4a8cc,2f2e59e1513ef7ac40e817b434970e8f74cc1adc..2314103985d4c76100245dcb41b5afd9828b0fe2
  #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
  {     .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
        .mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
- #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \
-       SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues)
+ #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
+       SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xitems, xtexts, xvalues)
+ #define SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
+ {     .reg = xreg, .shift_l = xshift, .shift_r = xshift, \
+       .mask = xmask, .items = xitems, .texts = xtexts, \
+       .values = xvalues, .autodisable = 1}
  #define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
        SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
  #define SOC_ENUM(xname, xenum) \
                                                        ARRAY_SIZE(xtexts), xtexts, xvalues)
  #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
        SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
+ #define SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
+       const struct soc_enum name = SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, \
+               xshift, xmask, ARRAY_SIZE(xtexts), xtexts, xvalues)
  #define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
        const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
  
@@@ -387,20 -396,8 +396,20 @@@ int snd_soc_codec_set_pll(struct snd_so
  int snd_soc_register_card(struct snd_soc_card *card);
  int snd_soc_unregister_card(struct snd_soc_card *card);
  int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card);
 +#ifdef CONFIG_PM_SLEEP
  int snd_soc_suspend(struct device *dev);
  int snd_soc_resume(struct device *dev);
 +#else
 +static inline int snd_soc_suspend(struct device *dev)
 +{
 +      return 0;
 +}
 +
 +static inline int snd_soc_resume(struct device *dev)
 +{
 +      return 0;
 +}
 +#endif
  int snd_soc_poweroff(struct device *dev);
  int snd_soc_register_platform(struct device *dev,
                const struct snd_soc_platform_driver *platform_drv);
@@@ -819,7 -816,7 +828,7 @@@ struct snd_soc_codec 
        /* component */
        struct snd_soc_component component;
  
-       /* dapm */
+       /* Don't access this directly, use snd_soc_codec_get_dapm() */
        struct snd_soc_dapm_context dapm;
  
  #ifdef CONFIG_DEBUG_FS
@@@ -1200,6 -1197,7 +1209,7 @@@ struct soc_enum 
        unsigned int mask;
        const char * const *texts;
        const unsigned int *values;
+       unsigned int autodisable:1;
  };
  
  /**
@@@ -1281,6 -1279,58 +1291,58 @@@ static inline struct snd_soc_dapm_conte
        return component->dapm_ptr;
  }
  
+ /**
+  * snd_soc_codec_get_dapm() - Returns the DAPM context for the CODEC
+  * @codec: The CODEC for which to get the DAPM context
+  *
+  * Note: Use this function instead of directly accessing the CODEC's dapm field
+  */
+ static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm(
+       struct snd_soc_codec *codec)
+ {
+       return &codec->dapm;
+ }
+ /**
+  * snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level
+  * @dapm: The CODEC for which to initialize the DAPM bias level
+  * @level: The DAPM level to initialize to
+  *
+  * Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level().
+  */
+ static inline void snd_soc_codec_init_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+ {
+       snd_soc_dapm_init_bias_level(snd_soc_codec_get_dapm(codec), level);
+ }
+ /**
+  * snd_soc_dapm_get_bias_level() - Get current CODEC DAPM bias level
+  * @codec: The CODEC for which to get the DAPM bias level
+  *
+  * Returns: The current DAPM bias level of the CODEC.
+  */
+ static inline enum snd_soc_bias_level snd_soc_codec_get_bias_level(
+       struct snd_soc_codec *codec)
+ {
+       return snd_soc_dapm_get_bias_level(snd_soc_codec_get_dapm(codec));
+ }
+ /**
+  * snd_soc_codec_force_bias_level() - Set the CODEC DAPM bias level
+  * @codec: The CODEC for which to set the level
+  * @level: The level to set to
+  *
+  * Forces the CODEC bias level to a specific state. See
+  * snd_soc_dapm_force_bias_level().
+  */
+ static inline int snd_soc_codec_force_bias_level(struct snd_soc_codec *codec,
+       enum snd_soc_bias_level level)
+ {
+       return snd_soc_dapm_force_bias_level(snd_soc_codec_get_dapm(codec),
+               level);
+ }
  /**
   * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
   * @kcontrol: The kcontrol
index f62da48eda9a410cd47d2461ef5f86e7194c38dd,ee31fa77af7b7dcbe9727d61b3bd61e62ceacd35..38b3dad9d48ac42c58e2c9d7058c094392889c7a
@@@ -1140,7 -1140,7 +1140,7 @@@ static int pm860x_set_bias_level(struc
                break;
  
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* Enable Audio PLL & Audio section */
                        data = AUDIO_PLL | AUDIO_SECTION_ON;
                        pm860x_reg_write(pm860x->i2c, REG_MISC2, data);
                pm860x_set_bits(pm860x->i2c, REG_MISC2, data, 0);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
  }
  
@@@ -1187,16 -1186,16 +1186,16 @@@ static struct snd_soc_dai_driver pm860x
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = PM860X_RATES,
 -                      .formats        = SNDRV_PCM_FORMAT_S16_LE | \
 -                                        SNDRV_PCM_FORMAT_S18_3LE,
 +                      .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
 +                                        SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .capture = {
                        .stream_name    = "PCM Capture",
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = PM860X_RATES,
 -                      .formats        = SNDRV_PCM_FORMAT_S16_LE | \
 -                                        SNDRV_PCM_FORMAT_S18_3LE,
 +                      .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
 +                                        SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .ops    = &pm860x_pcm_dai_ops,
        }, {
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = SNDRV_PCM_RATE_8000_48000,
 -                      .formats        = SNDRV_PCM_FORMAT_S16_LE | \
 -                                        SNDRV_PCM_FORMAT_S18_3LE,
 +                      .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
 +                                        SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .capture = {
                        .stream_name    = "I2S Capture",
                        .channels_min   = 2,
                        .channels_max   = 2,
                        .rates          = SNDRV_PCM_RATE_8000_48000,
 -                      .formats        = SNDRV_PCM_FORMAT_S16_LE | \
 -                                        SNDRV_PCM_FORMAT_S18_3LE,
 +                      .formats        = SNDRV_PCM_FMTBIT_S16_LE | \
 +                                        SNDRV_PCM_FMTBIT_S18_3LE,
                },
                .ops    = &pm860x_i2s_dai_ops,
        },
index c82301484156d8ba1914ae711f5915341d63f8a4,ea583675fa001344781774d4d1c137edd8cf72d2..5da29374cd1d95991d77e024500982063cb1900f
@@@ -18,7 -18,6 +18,7 @@@
  #include <linux/platform_device.h>
  #include <linux/spi/spi.h>
  #include <linux/gpio.h>
 +#include <linux/acpi.h>
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
@@@ -464,9 -463,9 +464,9 @@@ static const struct snd_kcontrol_new rt
                RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
  
        /* Headphone Output Volume */
 -      SOC_DOUBLE("HP Channel Switch", RT5645_HP_VOL,
 +      SOC_DOUBLE("Headphone Channel Switch", RT5645_HP_VOL,
                RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
 -      SOC_DOUBLE_TLV("HP Playback Volume", RT5645_HP_VOL,
 +      SOC_DOUBLE_TLV("Headphone Playback Volume", RT5645_HP_VOL,
                RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
  
        /* OUTPUT Control */
@@@ -2410,7 -2409,6 +2410,6 @@@ static int rt5645_set_bias_level(struc
        default:
                break;
        }
-       codec->dapm.bias_level = level;
  
        return 0;
  }
@@@ -2521,7 -2519,7 +2520,7 @@@ static int rt5645_probe(struct snd_soc_
                break;
        }
  
-       rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
  
        snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
  
@@@ -2657,15 -2655,6 +2656,15 @@@ static const struct i2c_device_id rt564
  };
  MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
  
 +#ifdef CONFIG_ACPI
 +static struct acpi_device_id rt5645_acpi_match[] = {
 +      { "10EC5645", 0 },
 +      { "10EC5650", 0 },
 +      {},
 +};
 +MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match);
 +#endif
 +
  static int rt5645_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
  {
  
                case RT5645_DMIC_DATA_GPIO12:
                        regmap_update_bits(rt5645->regmap, RT5645_DMIC_CTRL1,
 -                              RT5645_DMIC_1_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
 +                              RT5645_DMIC_2_DP_MASK, RT5645_DMIC_2_DP_GPIO12);
                        regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
                                RT5645_GP12_PIN_MASK,
                                RT5645_GP12_PIN_DMIC2_SDA);
                }
        }
  
 +      INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
 +
        if (rt5645->i2c->irq) {
                ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
                        dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
        }
  
 -      INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
 -
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
                                      rt5645_dai, ARRAY_SIZE(rt5645_dai));
  }
@@@ -2882,7 -2871,6 +2881,7 @@@ static struct i2c_driver rt5645_i2c_dri
        .driver = {
                .name = "rt5645",
                .owner = THIS_MODULE,
 +              .acpi_match_table = ACPI_PTR(rt5645_acpi_match),
        },
        .probe = rt5645_i2c_probe,
        .remove   = rt5645_i2c_remove,
index 169aa471ffbd447e2ec3f009d775524eb77aa5ae,c0211a1187a57aff0b8fc780eef16857aab441bd..fe5581675983c528055c778a95298e7cef8fc640
@@@ -62,9 -62,6 +62,9 @@@ static const struct reg_default init_li
        {RT5677_PR_BASE + 0x1e, 0x0000},
        {RT5677_PR_BASE + 0x12, 0x0eaa},
        {RT5677_PR_BASE + 0x14, 0x018a},
 +      {RT5677_PR_BASE + 0x15, 0x0490},
 +      {RT5677_PR_BASE + 0x38, 0x0f71},
 +      {RT5677_PR_BASE + 0x39, 0x0f71},
  };
  #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list)
  
@@@ -820,7 -817,7 +820,7 @@@ static int rt5677_dsp_vad_put(struct sn
  
        rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
  
-       if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+       if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF)
                rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
  
        return 0;
@@@ -917,7 -914,7 +917,7 @@@ static int set_dmic_clk(struct snd_soc_
  {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 -      int idx = rl6231_calc_dmic_clk(rt5677->sysclk);
 +      int idx = rl6231_calc_dmic_clk(rt5677->lrck[RT5677_AIF1] << 8);
  
        if (idx < 0)
                dev_err(codec->dev, "Failed to set DMIC clock\n");
@@@ -2479,7 -2476,7 +2479,7 @@@ static int rt5677_vref_event(struct snd
  
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               if (codec->dapm.bias_level != SND_SOC_BIAS_ON &&
+               if (snd_soc_codec_get_bias_level(codec) != SND_SOC_BIAS_ON &&
                        !rt5677->is_vref_slow) {
                        mdelay(20);
                        regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
@@@ -4353,7 -4350,7 +4353,7 @@@ static int rt5677_set_bias_level(struc
                break;
  
        case SND_SOC_BIAS_PREPARE:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) {
                        rt5677_set_dsp_vad(codec, false);
  
                        regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
        default:
                break;
        }
-       codec->dapm.bias_level = level;
  
        return 0;
  }
@@@ -4606,22 -4602,23 +4605,23 @@@ static void rt5677_free_gpio(struct i2c
  
  static int rt5677_probe(struct snd_soc_codec *codec)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        int i;
  
        rt5677->codec = codec;
  
        if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) {
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5677_dmic2_clk_2,
                        ARRAY_SIZE(rt5677_dmic2_clk_2));
        } else { /*use dmic1 clock by default*/
-               snd_soc_dapm_add_routes(&codec->dapm,
+               snd_soc_dapm_add_routes(dapm,
                        rt5677_dmic2_clk_1,
                        ARRAY_SIZE(rt5677_dmic2_clk_1));
        }
  
-       rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
  
        regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
        regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
index 7f939aec5a7fa83325de28ea75517c0921880a76,2341e8e6bfc15b26e157c85bf9e2b1dd397e0eec..ed4cca7f6779937a4e92717cc29209356f9a9e5e
@@@ -236,7 -236,6 +236,6 @@@ static int stac9766_set_bias_level(stru
                stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
  }
  
@@@ -321,7 -320,7 +320,7 @@@ static struct snd_soc_dai_driver stac97
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_32000 | \
                        SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 -              .formats = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE,
 +              .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
        },
        /* alsa ops */
        .ops = &stac9766_dai_ops_digital,
index c3c33bd0df1c5c2c4d94bdcf93a498b62744d23e,d708a9c43259854dd52c309b986941d69e73dd8f..6e159f59d219beaba3ff75a0b4f7c7b5405d2b9b
@@@ -437,7 -437,7 +437,7 @@@ static int uda1380_set_dai_fmt_both(str
        if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
                return -EINVAL;
  
 -      uda1380_write(codec, UDA1380_IFACE, iface);
 +      uda1380_write_reg_cache(codec, UDA1380_IFACE, iface);
  
        return 0;
  }
@@@ -590,9 -590,6 +590,6 @@@ static int uda1380_set_bias_level(struc
        int reg;
        struct uda1380_platform_data *pdata = codec->dev->platform_data;
  
-       if (codec->dapm.bias_level == level)
-               return 0;
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
                uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
                break;
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        if (gpio_is_valid(pdata->gpio_power)) {
                                gpio_set_value(pdata->gpio_power, 1);
                                mdelay(1);
                for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
                        set_bit(reg - 0x10, &uda1380_cache_dirty);
        }
-       codec->dapm.bias_level = level;
        return 0;
  }
  
index d476221dba51dcaa691755b29a72b564c2c79d78,f11523fc5bd05c4417cdc86fa1815bf8bea1e5c1..b1537046e9fdb009d9ad015eb2be96cc3086ccdd
@@@ -42,7 -42,7 +42,7 @@@ struct wm5102_priv 
  static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
  static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
  static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
 -static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
 +static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
  static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
  
  static const struct wm_adsp_region wm5102_dsp1_regions[] = {
@@@ -1827,6 -1827,7 +1827,7 @@@ static struct snd_soc_dai_driver wm5102
  
  static int wm5102_codec_probe(struct snd_soc_codec *codec)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
  
        arizona_init_spk(codec);
        arizona_init_gpio(codec);
  
-       snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
  
-       priv->core.arizona->dapm = &codec->dapm;
+       priv->core.arizona->dapm = dapm;
  
        return 0;
  }
index 3ee6cfd0578bec1504ea39c66c065575d8ceabc3,67960009f0c456589b845b87bf776c1af23b1b58..efcfe180cbbca8a85925b79e886ada253eca73c1
@@@ -167,7 -167,7 +167,7 @@@ static int wm5110_sysclk_ev(struct snd_
  static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
  static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
  static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
 -static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
 +static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
  static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
  
  #define WM5110_NG_SRC(name, base) \
@@@ -1598,10 -1598,11 +1598,11 @@@ static struct snd_soc_dai_driver wm5110
  
  static int wm5110_codec_probe(struct snd_soc_codec *codec)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
        int ret;
  
-       priv->core.arizona->dapm = &codec->dapm;
+       priv->core.arizona->dapm = dapm;
  
        arizona_init_spk(codec);
        arizona_init_gpio(codec);
        if (ret != 0)
                return ret;
  
-       snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
-       priv->core.arizona->dapm = &codec->dapm;
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
  
        return 0;
  }
index 51171e457fa483e93939593894eb590a6faae5b2,ff4c8e979e01f7c7c994730a308ec05bdbbec93a..6ad606fd8b6908c2382d501da96036a942998b9f
@@@ -469,7 -469,7 +469,7 @@@ static int wm8737_set_bias_level(struc
                break;
  
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
                                                    wm8737->supplies);
                        if (ret != 0) {
  
                        /* Fast VMID ramp at 2*2.5k */
                        snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
 -                                          WM8737_VMIDSEL_MASK, 0x4);
 +                                          WM8737_VMIDSEL_MASK,
 +                                          2 << WM8737_VMIDSEL_SHIFT);
  
                        /* Bring VMID up */
                        snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
  
                /* VMID at 2*300k */
                snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
 -                                  WM8737_VMIDSEL_MASK, 2);
 +                                  WM8737_VMIDSEL_MASK,
 +                                  1 << WM8737_VMIDSEL_SHIFT);
  
                break;
  
                break;
        }
  
-       codec->dapm.bias_level = level;
        return 0;
  }
  
@@@ -562,7 -559,7 +561,7 @@@ static int wm8737_probe(struct snd_soc_
        snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
                            WM8737_RVU);
  
-       wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
  
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
index fdb765600a10910624d6c0df9441cfd91e74a179,ecc7b4703617dd7e1f9870eb1e4e13ae1f4fd904..f3759ec5a8638647cd54088f560a239e58776428
@@@ -998,8 -998,8 +998,8 @@@ static int wm8900_digital_mute(struct s
                      SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
  
  #define WM8900_PCM_FORMATS \
 -      (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
 -       SNDRV_PCM_FORMAT_S24_LE)
 +      (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 +       SNDRV_PCM_FMTBIT_S24_LE)
  
  static const struct snd_soc_dai_ops wm8900_dai_ops = {
        .hw_params      = wm8900_hw_params,
@@@ -1049,7 -1049,7 +1049,7 @@@ static int wm8900_set_bias_level(struc
  
        case SND_SOC_BIAS_STANDBY:
                /* Charge capacitors if initial power up */
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        /* STARTUP_BIAS_ENA on */
                        snd_soc_write(codec, WM8900_REG_POWER1,
                                     WM8900_REG_POWER1_STARTUP_BIAS_ENA);
                             WM8900_REG_POWER2_SYSCLK_ENA);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
  }
  
@@@ -1138,7 -1137,7 +1137,7 @@@ static int wm8900_suspend(struct snd_so
        wm8900->fll_out = fll_out;
        wm8900->fll_in = fll_in;
  
-       wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
  
        return 0;
  }
@@@ -1156,7 -1155,7 +1155,7 @@@ static int wm8900_resume(struct snd_soc
                return ret;
        }
  
-       wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
  
        /* Restart the FLL? */
        if (wm8900->fll_out) {
@@@ -1189,7 -1188,7 +1188,7 @@@ static int wm8900_probe(struct snd_soc_
        wm8900_reset(codec);
  
        /* Turn the chip on */
-       wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
  
        /* Latch the volume update bits */
        snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100);
index 03e04bf6c5ba299e9a842784bb1410cd1d22122c,3a5bf894ff6df8d77251a3cb4463e91d10ba3591..2d591c24704be487830ab956e9f4b2ef1be02075
@@@ -298,7 -298,7 +298,7 @@@ static int wm8955_configure_clocking(st
                snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
                                    WM8955_K_17_9_MASK,
                                    (pll.k >> 9) & WM8955_K_17_9_MASK);
 -              snd_soc_update_bits(codec, WM8955_PLL_CONTROL_2,
 +              snd_soc_update_bits(codec, WM8955_PLL_CONTROL_3,
                                    WM8955_K_8_0_MASK,
                                    pll.k & WM8955_K_8_0_MASK);
                if (pll.k)
@@@ -785,7 -785,7 +785,7 @@@ static int wm8955_set_bias_level(struc
                break;
  
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        ret = regulator_bulk_enable(ARRAY_SIZE(wm8955->supplies),
                                                    wm8955->supplies);
                        if (ret != 0) {
                                       wm8955->supplies);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
  }
  
@@@ -929,7 -928,7 +928,7 @@@ static int wm8955_probe(struct snd_soc_
                                            WM8955_DMEN, WM8955_DMEN);
        }
  
-       wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
  
        /* Bias level configuration will have done an extra enable */
        regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
index e97a7615df85059a120f19857babe4d77df0cb46,edd34db9bd252b530367f87f24cf87cc00ac1555..af095b64f8804f9a45dcfe84562045d9f6c7a955
@@@ -395,7 -395,7 +395,7 @@@ static const struct snd_soc_dapm_route 
        { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
        { "Right Input Mixer", NULL, "RINPUT1", },  /* Really Boost Switch */
        { "Right Input Mixer", NULL, "RINPUT2" },
 -      { "Right Input Mixer", NULL, "LINPUT3" },
 +      { "Right Input Mixer", NULL, "RINPUT3" },
  
        { "Left ADC", NULL, "Left Input Mixer" },
        { "Right ADC", NULL, "Right Input Mixer" },
@@@ -445,7 -445,7 +445,7 @@@ static int wm8960_add_widgets(struct sn
  {
        struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
        struct wm8960_data *pdata = &wm8960->pdata;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct snd_soc_dapm_widget *w;
  
        snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
         * and save the result.
         */
        list_for_each_entry(w, &codec->component.card->widgets, list) {
-               if (w->dapm != &codec->dapm)
+               if (w->dapm != dapm)
                        continue;
                if (strcmp(w->name, "LOUT1 PGA") == 0)
                        wm8960->lout1 = w;
@@@ -627,7 -627,7 +627,7 @@@ static int wm8960_set_bias_level_out3(s
                break;
  
        case SND_SOC_BIAS_PREPARE:
-               switch (codec->dapm.bias_level) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
                case SND_SOC_BIAS_STANDBY:
                        if (!IS_ERR(wm8960->mclk)) {
                                ret = clk_prepare_enable(wm8960->mclk);
                break;
  
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        regcache_sync(wm8960->regmap);
  
                        /* Enable anti-pop features */
                break;
        }
  
-       codec->dapm.bias_level = level;
        return 0;
  }
  
@@@ -707,7 -705,7 +705,7 @@@ static int wm8960_set_bias_level_caples
                break;
  
        case SND_SOC_BIAS_PREPARE:
-               switch (codec->dapm.bias_level) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
                case SND_SOC_BIAS_STANDBY:
                        /* Enable anti pop mode */
                        snd_soc_update_bits(codec, WM8960_APOP1,
                break;
  
        case SND_SOC_BIAS_STANDBY:
-               switch (codec->dapm.bias_level) {
+               switch (snd_soc_codec_get_bias_level(codec)) {
                case SND_SOC_BIAS_PREPARE:
                        /* Disable HP discharge */
                        snd_soc_update_bits(codec, WM8960_APOP2,
                break;
        }
  
-       codec->dapm.bias_level = level;
        return 0;
  }
  
index a1c04dab668469f08161c086f138e562c81f4d0f,99a758a549865357de647ebc08ba877b7a3b0802..7c3ee6f91a4a56b1cff5c79f9194887a4caa4ebc
@@@ -212,6 -212,7 +212,7 @@@ static int configure_aif_clock(struct s
  
  static int configure_clock(struct snd_soc_codec *codec)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        int change, new;
  
        change = snd_soc_update_bits(codec, WM8994_CLOCKING_1,
                                     WM8994_SYSCLK_SRC, new);
        if (change)
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_sync(dapm);
  
        wm8958_micd_set_rate(codec);
  
@@@ -2492,12 -2493,12 +2493,12 @@@ static int wm8994_set_bias_level(struc
                        break;
                }
  
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
                        active_reference(codec);
                break;
  
        case SND_SOC_BIAS_STANDBY:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) {
                        switch (control->type) {
                        case WM8958:
                                if (control->revision == 0) {
                                            WM8994_LINEOUT2_DISCH);
                }
  
-               if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE)
                        active_dereference(codec);
  
                /* MICBIAS into bypass mode on newer devices */
                break;
  
        case SND_SOC_BIAS_OFF:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
+               if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY)
                        wm8994->cur_fw = NULL;
                break;
        }
  
-       codec->dapm.bias_level = level;
        return 0;
  }
  
  int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode)
  {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
  
        switch (mode) {
        case WM8994_VMID_NORMAL:
@@@ -2754,7 -2753,7 +2753,7 @@@ static struct 
  };
  
  static int fs_ratios[] = {
 -      64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536
 +      64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536
  };
  
  static int bclk_divs[] = {
@@@ -3163,7 -3162,7 +3162,7 @@@ static int wm8994_codec_suspend(struct 
                                 i + 1, ret);
        }
  
-       wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF);
  
        return 0;
  }
@@@ -3356,6 -3355,7 +3355,7 @@@ static void wm8994_handle_pdata(struct 
  int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                      int micbias)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994_micdet *micdet;
        struct wm8994 *control = wm8994->wm8994;
        case 1:
                micdet = &wm8994->micdet[0];
                if (jack)
-                       ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                           "MICBIAS1");
+                       ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
                else
-                       ret = snd_soc_dapm_disable_pin(&codec->dapm,
-                                                      "MICBIAS1");
+                       ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
                break;
        case 2:
                micdet = &wm8994->micdet[1];
                if (jack)
-                       ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                                           "MICBIAS1");
+                       ret = snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
                else
-                       ret = snd_soc_dapm_disable_pin(&codec->dapm,
-                                                      "MICBIAS1");
+                       ret = snd_soc_dapm_disable_pin(dapm, "MICBIAS1");
                break;
        default:
                dev_warn(codec->dev, "Invalid MICBIAS %d\n", micbias);
                            WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
                            WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
  
-       snd_soc_dapm_sync(&codec->dapm);
+       snd_soc_dapm_sync(dapm);
  
        return 0;
  }
@@@ -3505,6 -3501,7 +3501,7 @@@ static irqreturn_t wm8994_mic_irq(int i
  /* Should be called with accdet_lock held */
  static void wm1811_micd_stop(struct snd_soc_codec *codec)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
  
        if (!wm8994->jackdet)
        wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_JACK);
  
        if (wm8994->wm8994->pdata.jd_ext_cap)
-               snd_soc_dapm_disable_pin(&codec->dapm,
-                                        "MICBIAS2");
+               snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
  }
  
  static void wm8958_button_det(struct snd_soc_codec *codec, u16 status)
@@@ -3625,14 -3621,14 +3621,14 @@@ static void wm1811_mic_work(struct work
                                                  mic_work.work);
        struct wm8994 *control = wm8994->wm8994;
        struct snd_soc_codec *codec = wm8994->hubs.codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
  
        pm_runtime_get_sync(codec->dev);
  
        /* If required for an external cap force MICBIAS on */
        if (control->pdata.jd_ext_cap) {
-               snd_soc_dapm_force_enable_pin(&codec->dapm,
-                                             "MICBIAS2");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2");
+               snd_soc_dapm_sync(dapm);
        }
  
        mutex_lock(&wm8994->accdet_lock);
@@@ -3664,6 -3660,7 +3660,7 @@@ static irqreturn_t wm1811_jackdet_irq(i
        struct wm8994_priv *wm8994 = data;
        struct wm8994 *control = wm8994->wm8994;
        struct snd_soc_codec *codec = wm8994->hubs.codec;
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        int reg, delay;
        bool present;
  
  
        /* Turn off MICBIAS if it was on for an external cap */
        if (control->pdata.jd_ext_cap && !present)
-               snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
+               snd_soc_dapm_disable_pin(dapm, "MICBIAS2");
  
        if (present)
                snd_soc_jack_report(wm8994->micdet[0].jack,
@@@ -3770,6 -3767,7 +3767,7 @@@ int wm8958_mic_detect(struct snd_soc_co
                      wm1811_micdet_cb det_cb, void *det_cb_data,
                      wm1811_mic_id_cb id_cb, void *id_cb_data)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        u16 micd_lvl_sel;
        }
  
        if (jack) {
-               snd_soc_dapm_force_enable_pin(&codec->dapm, "CLK_SYS");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_force_enable_pin(dapm, "CLK_SYS");
+               snd_soc_dapm_sync(dapm);
  
                wm8994->micdet[0].jack = jack;
  
                snd_soc_update_bits(codec, WM8958_MIC_DETECT_2,
                                    WM8958_MICD_LVL_SEL_MASK, micd_lvl_sel);
  
-               WARN_ON(codec->dapm.bias_level > SND_SOC_BIAS_STANDBY);
+               WARN_ON(snd_soc_codec_get_bias_level(codec) > SND_SOC_BIAS_STANDBY);
  
                /*
                 * If we can use jack detection start off with that,
                snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
                                    WM8958_MICD_ENA, 0);
                wm1811_jackdet_set_mode(codec, WM1811_JACKDET_MODE_NONE);
-               snd_soc_dapm_disable_pin(&codec->dapm, "CLK_SYS");
-               snd_soc_dapm_sync(&codec->dapm);
+               snd_soc_dapm_disable_pin(dapm, "CLK_SYS");
+               snd_soc_dapm_sync(dapm);
        }
  
        return 0;
@@@ -3985,9 -3983,9 +3983,9 @@@ static irqreturn_t wm8994_temp_shut(in
  
  static int wm8994_codec_probe(struct snd_soc_codec *codec)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8994 *control = dev_get_drvdata(codec->dev->parent);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        unsigned int reg;
        int ret, i;
  
        wm8994->micdet_irq = control->pdata.micdet_irq;
  
        /* By default use idle_bias_off, will override for WM8994 */
-       codec->dapm.idle_bias_off = 1;
+       dapm->idle_bias_off = 1;
  
        /* Set revision-specific configuration */
        switch (control->type) {
                /* Single ended line outputs should have VMID on. */
                if (!control->pdata.lineout1_diff ||
                    !control->pdata.lineout2_diff)
-                       codec->dapm.idle_bias_off = 0;
+                       dapm->idle_bias_off = 0;
  
                switch (control->revision) {
                case 2:
index e7c81baefe6624f9dfe3918e568940f0e2d5243d,e9c4a9f353926566b2ef6ae02d8eb1a33462efdb..52404d7bc79047443fff2fecfdcd362bcfd3d3be
@@@ -40,7 -40,7 +40,7 @@@ struct wm8997_priv 
  static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
  static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
  static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
 -static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
 +static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0);
  static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
  
  static const struct reg_default wm8997_sysclk_reva_patch[] = {
@@@ -1055,13 -1055,14 +1055,14 @@@ static struct snd_soc_dai_driver wm8997
  
  static int wm8997_codec_probe(struct snd_soc_codec *codec)
  {
+       struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
  
        arizona_init_spk(codec);
  
-       snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+       snd_soc_dapm_disable_pin(dapm, "HAPTICS");
  
-       priv->core.arizona->dapm = &codec->dapm;
+       priv->core.arizona->dapm = dapm;
  
        return 0;
  }
index 1b20b8d2b15dfe2dd92699197cb1b67335532a7f,9d18a0ec42809a29a38034e7147aff8a539a76b1..89cd2d6f57c01d46a8eaf8dd24b81f7cb2a054fb
@@@ -1054,8 -1054,8 +1054,8 @@@ static int ac97_aux_prepare(struct snd_
                          SNDRV_PCM_RATE_48000)
  
  #define WM9713_PCM_FORMATS \
 -      (SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_S20_3LE | \
 -       SNDRV_PCM_FORMAT_S24_LE)
 +      (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
 +       SNDRV_PCM_FMTBIT_S24_LE)
  
  static const struct snd_soc_dai_ops wm9713_dai_ops_hifi = {
        .prepare        = ac97_hifi_prepare,
@@@ -1171,7 -1171,6 +1171,6 @@@ static int wm9713_set_bias_level(struc
                ac97_write(codec, AC97_POWERDOWN, 0xffff);
                break;
        }
-       codec->dapm.bias_level = level;
        return 0;
  }
  
@@@ -1201,7 -1200,7 +1200,7 @@@ static int wm9713_soc_resume(struct snd
        if (ret < 0)
                return ret;
  
-       wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+       snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY);
  
        /* do we need to re-start the PLL ? */
        if (wm9713->pll_in)
diff --combined sound/soc/soc-core.c
index 80b7cf5ef69abe0d215c0e628b45880ded700844,95b5f034d864ecf9e128f8c99792b20b5e84256c..95f83bec1d14398ba321ac6648bcbdb8c1adb8ec
@@@ -92,21 -92,30 +92,21 @@@ static int format_register_str(struct s
        int wordsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
        int regsize = codec->driver->reg_word_size * 2;
        int ret;
 -      char tmpbuf[len + 1];
 -      char regbuf[regsize + 1];
 -
 -      /* since tmpbuf is allocated on the stack, warn the callers if they
 -       * try to abuse this function */
 -      WARN_ON(len > 63);
  
        /* +2 for ': ' and + 1 for '\n' */
        if (wordsize + regsize + 2 + 1 != len)
                return -EINVAL;
  
 -      ret = snd_soc_read(codec, reg);
 -      if (ret < 0) {
 -              memset(regbuf, 'X', regsize);
 -              regbuf[regsize] = '\0';
 -      } else {
 -              snprintf(regbuf, regsize + 1, "%.*x", regsize, ret);
 -      }
 -
 -      /* prepare the buffer */
 -      snprintf(tmpbuf, len + 1, "%.*x: %s\n", wordsize, reg, regbuf);
 -      /* copy it back to the caller without the '\0' */
 -      memcpy(buf, tmpbuf, len);
 +      sprintf(buf, "%.*x: ", wordsize, reg);
 +      buf += wordsize + 2;
  
 +      ret = snd_soc_read(codec, reg);
 +      if (ret < 0)
 +              memset(buf, 'X', regsize);
 +      else
 +              sprintf(buf, "%.*x", regsize, ret);
 +      buf[regsize] = '\n';
 +      /* no NUL-termination needed */
        return 0;
  }
  
@@@ -741,23 -750,10 +741,10 @@@ static void soc_resume_deferred(struct 
        }
  
        list_for_each_entry(codec, &card->codec_dev_list, card_list) {
-               /* If the CODEC was idle over suspend then it will have been
-                * left with bias OFF or STANDBY and suspended so we must now
-                * resume.  Otherwise the suspend was suppressed.
-                */
                if (codec->suspended) {
-                       switch (codec->dapm.bias_level) {
-                       case SND_SOC_BIAS_STANDBY:
-                       case SND_SOC_BIAS_OFF:
-                               if (codec->driver->resume)
-                                       codec->driver->resume(codec);
-                               codec->suspended = 0;
-                               break;
-                       default:
-                               dev_dbg(codec->dev,
-                                       "ASoC: CODEC was on over suspend\n");
-                               break;
-                       }
+                       if (codec->driver->resume)
+                               codec->driver->resume(codec);
+                       codec->suspended = 0;
                }
        }
  
@@@ -895,17 -891,12 +882,17 @@@ static struct snd_soc_dai *snd_soc_find
  {
        struct snd_soc_component *component;
        struct snd_soc_dai *dai;
 +      struct device_node *component_of_node;
  
        lockdep_assert_held(&client_mutex);
  
        /* Find CPU DAI from registered DAIs*/
        list_for_each_entry(component, &component_list, list) {
 -              if (dlc->of_node && component->dev->of_node != dlc->of_node)
 +              component_of_node = component->dev->of_node;
 +              if (!component_of_node && component->dev->parent)
 +                      component_of_node = component->dev->parent->of_node;
 +
 +              if (dlc->of_node && component_of_node != dlc->of_node)
                        continue;
                if (dlc->name && strcmp(component->name, dlc->name))
                        continue;
@@@ -2595,8 -2586,7 +2582,8 @@@ static int snd_soc_register_dais(struc
                 * the same naming style even though those DAIs are not
                 * component-less anymore.
                 */
 -              if (count == 1 && legacy_dai_naming) {
 +              if (count == 1 && legacy_dai_naming &&
 +                      (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) {
                        dai->name = fmt_single_name(dev, &dai->id);
                } else {
                        dai->name = fmt_multiple_name(dev, &dai_drv[i]);
@@@ -3485,16 -3475,11 +3472,16 @@@ static int snd_soc_get_dai_name(struct 
                                const char **dai_name)
  {
        struct snd_soc_component *pos;
 +      struct device_node *component_of_node;
        int ret = -EPROBE_DEFER;
  
        mutex_lock(&client_mutex);
        list_for_each_entry(pos, &component_list, list) {
 -              if (pos->dev->of_node != args->np)
 +              component_of_node = pos->dev->of_node;
 +              if (!component_of_node && pos->dev->parent)
 +                      component_of_node = pos->dev->parent->of_node;
 +
 +              if (component_of_node != args->np)
                        continue;
  
                if (pos->driver->of_xlate_dai_name) {
diff --combined sound/soc/soc-dapm.c
index 158204d08924972aee5843fcdc54735e8c0509bd,1b4a6eb4317430f2822d35f90200818e35079265..aa327c92480c56c2609699380594a75ad765fbda
@@@ -52,10 -52,15 +52,15 @@@ static int snd_soc_dapm_add_path(struc
        const char *control,
        int (*connected)(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink));
- static struct snd_soc_dapm_widget *
+ struct snd_soc_dapm_widget *
  snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget);
  
+ struct snd_soc_dapm_widget *
+ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
+                        const struct snd_soc_dapm_widget *widget);
  /* dapm power sequences - make this per codec in the future */
  static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 0,
@@@ -70,6 -75,7 +75,7 @@@
        [snd_soc_dapm_aif_out] = 4,
        [snd_soc_dapm_mic] = 5,
        [snd_soc_dapm_mux] = 6,
+       [snd_soc_dapm_demux] = 6,
        [snd_soc_dapm_dac] = 7,
        [snd_soc_dapm_switch] = 8,
        [snd_soc_dapm_mixer] = 8,
@@@ -100,6 -106,7 +106,7 @@@ static int dapm_down_seq[] = 
        [snd_soc_dapm_mic] = 7,
        [snd_soc_dapm_micbias] = 8,
        [snd_soc_dapm_mux] = 9,
+       [snd_soc_dapm_demux] = 9,
        [snd_soc_dapm_aif_in] = 10,
        [snd_soc_dapm_aif_out] = 10,
        [snd_soc_dapm_dai_in] = 10,
@@@ -308,14 -315,13 +315,13 @@@ static int dapm_kcontrol_data_alloc(str
  {
        struct dapm_kcontrol_data *data;
        struct soc_mixer_control *mc;
+       struct soc_enum *e;
+       const char *name;
+       int ret;
  
        data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               dev_err(widget->dapm->dev,
-                               "ASoC: can't allocate kcontrol data for %s\n",
-                               widget->name);
+       if (!data)
                return -ENOMEM;
-       }
  
        INIT_LIST_HEAD(&data->paths);
  
                if (mc->autodisable) {
                        struct snd_soc_dapm_widget template;
  
+                       name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+                                        "Autodisable");
+                       if (!name) {
+                               ret = -ENOMEM;
+                               goto err_data;
+                       }
                        memset(&template, 0, sizeof(template));
                        template.reg = mc->reg;
                        template.mask = (1 << fls(mc->max)) - 1;
                                template.off_val = 0;
                        template.on_val = template.off_val;
                        template.id = snd_soc_dapm_kcontrol;
-                       template.name = kcontrol->id.name;
+                       template.name = name;
  
                        data->value = template.on_val;
  
-                       data->widget = snd_soc_dapm_new_control(widget->dapm,
+                       data->widget =
+                               snd_soc_dapm_new_control_unlocked(widget->dapm,
                                &template);
                        if (!data->widget) {
-                               kfree(data);
-                               return -ENOMEM;
+                               ret = -ENOMEM;
+                               goto err_name;
                        }
                }
                break;
+       case snd_soc_dapm_demux:
+       case snd_soc_dapm_mux:
+               e = (struct soc_enum *)kcontrol->private_value;
+               if (e->autodisable) {
+                       struct snd_soc_dapm_widget template;
+                       name = kasprintf(GFP_KERNEL, "%s %s", kcontrol->id.name,
+                                        "Autodisable");
+                       if (!name) {
+                               ret = -ENOMEM;
+                               goto err_data;
+                       }
+                       memset(&template, 0, sizeof(template));
+                       template.reg = e->reg;
+                       template.mask = e->mask << e->shift_l;
+                       template.shift = e->shift_l;
+                       template.off_val = snd_soc_enum_item_to_val(e, 0);
+                       template.on_val = template.off_val;
+                       template.id = snd_soc_dapm_kcontrol;
+                       template.name = name;
+                       data->value = template.on_val;
+                       data->widget = snd_soc_dapm_new_control(widget->dapm,
+                                       &template);
+                       if (!data->widget) {
+                               ret = -ENOMEM;
+                               goto err_name;
+                       }
+                       snd_soc_dapm_add_path(widget->dapm, data->widget,
+                                             widget, NULL, NULL);
+               }
+               break;
        default:
                break;
        }
        kcontrol->private_data = data;
  
        return 0;
+ err_name:
+       kfree(name);
+ err_data:
+       kfree(data);
+       return ret;
  }
  
  static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
  {
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
+       if (data->widget)
+               kfree(data->widget->name);
        kfree(data->wlist);
        kfree(data);
  }
@@@ -405,11 -463,6 +463,6 @@@ static void dapm_kcontrol_add_path(cons
        struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
  
        list_add_tail(&path->list_kcontrol, &data->paths);
-       if (data->widget) {
-               snd_soc_dapm_add_path(data->widget->dapm, data->widget,
-                   path->source, NULL, NULL);
-       }
  }
  
  static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
@@@ -525,6 -578,67 +578,67 @@@ static void soc_dapm_async_complete(str
                snd_soc_component_async_complete(dapm->component);
  }
  
+ static struct snd_soc_dapm_widget *
+ dapm_wcache_lookup(struct snd_soc_dapm_wcache *wcache, const char *name)
+ {
+       struct snd_soc_dapm_widget *w = wcache->widget;
+       struct list_head *wlist;
+       const int depth = 2;
+       int i = 0;
+       if (w) {
+               wlist = &w->dapm->card->widgets;
+               list_for_each_entry_from(w, wlist, list) {
+                       if (!strcmp(name, w->name))
+                               return w;
+                       if (++i == depth)
+                               break;
+               }
+       }
+       return NULL;
+ }
+ static inline void dapm_wcache_update(struct snd_soc_dapm_wcache *wcache,
+                                     struct snd_soc_dapm_widget *w)
+ {
+       wcache->widget = w;
+ }
+ /**
+  * snd_soc_dapm_force_bias_level() - Sets the DAPM bias level
+  * @dapm: The DAPM context for which to set the level
+  * @level: The level to set
+  *
+  * Forces the DAPM bias level to a specific state. It will call the bias level
+  * callback of DAPM context with the specified level. This will even happen if
+  * the context is already at the same level. Furthermore it will not go through
+  * the normal bias level sequencing, meaning any intermediate states between the
+  * current and the target state will not be entered.
+  *
+  * Note that the change in bias level is only temporary and the next time
+  * snd_soc_dapm_sync() is called the state will be set to the level as
+  * determined by the DAPM core. The function is mainly intended to be used to
+  * used during probe or resume from suspend to power up the device so
+  * initialization can be done, before the DAPM core takes over.
+  */
+ int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
+       enum snd_soc_bias_level level)
+ {
+       int ret = 0;
+       if (dapm->set_bias_level)
+               ret = dapm->set_bias_level(dapm, level);
+       if (ret == 0)
+               dapm->bias_level = level;
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(snd_soc_dapm_force_bias_level);
  /**
   * snd_soc_dapm_set_bias_level - set the bias level for the system
   * @dapm: DAPM context
@@@ -547,10 -661,8 +661,8 @@@ static int snd_soc_dapm_set_bias_level(
        if (ret != 0)
                goto out;
  
-       if (dapm->set_bias_level)
-               ret = dapm->set_bias_level(dapm, level);
-       else if (!card || dapm != &card->dapm)
-               dapm->bias_level = level;
+       if (!card || dapm != &card->dapm)
+               ret = snd_soc_dapm_force_bias_level(dapm, level);
  
        if (ret != 0)
                goto out;
@@@ -565,9 -677,10 +677,10 @@@ out
  
  /* connect mux widget to its interconnecting audio paths */
  static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
-       struct snd_soc_dapm_path *path, const char *control_name)
+       struct snd_soc_dapm_path *path, const char *control_name,
+       struct snd_soc_dapm_widget *w)
  {
-       const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0];
+       const struct snd_kcontrol_new *kcontrol = &w->kcontrol_news[0];
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, item;
        int i;
@@@ -707,6 -820,7 +820,7 @@@ static int dapm_create_or_share_mixmux_
                                wname_in_long_name = false;
                                kcname_in_long_name = true;
                                break;
+                       case snd_soc_dapm_demux:
                        case snd_soc_dapm_mux:
                                wname_in_long_name = true;
                                kcname_in_long_name = false;
@@@ -777,6 -891,7 +891,7 @@@ static int dapm_new_mixer(struct snd_so
  {
        int i, ret;
        struct snd_soc_dapm_path *path;
+       struct dapm_kcontrol_data *data;
  
        /* add kcontrol */
        for (i = 0; i < w->num_kcontrols; i++) {
                        if (path->name != (char *)w->kcontrol_news[i].name)
                                continue;
  
-                       if (w->kcontrols[i]) {
-                               dapm_kcontrol_add_path(w->kcontrols[i], path);
-                               continue;
+                       if (!w->kcontrols[i]) {
+                               ret = dapm_create_or_share_mixmux_kcontrol(w, i);
+                               if (ret < 0)
+                                       return ret;
                        }
  
-                       ret = dapm_create_or_share_mixmux_kcontrol(w, i);
-                       if (ret < 0)
-                               return ret;
                        dapm_kcontrol_add_path(w->kcontrols[i], path);
+                       data = snd_kcontrol_chip(w->kcontrols[i]);
+                       if (data->widget)
+                               snd_soc_dapm_add_path(data->widget->dapm,
+                                                     data->widget,
+                                                     path->source,
+                                                     NULL, NULL);
                }
        }
  
@@@ -807,17 -926,32 +926,32 @@@ static int dapm_new_mux(struct snd_soc_
  {
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_dapm_path *path;
+       struct list_head *paths;
+       const char *type;
        int ret;
  
+       switch (w->id) {
+       case snd_soc_dapm_mux:
+               paths = &w->sources;
+               type = "mux";
+               break;
+       case snd_soc_dapm_demux:
+               paths = &w->sinks;
+               type = "demux";
+               break;
+       default:
+               return -EINVAL;
+       }
        if (w->num_kcontrols != 1) {
                dev_err(dapm->dev,
-                       "ASoC: mux %s has incorrect number of controls\n",
+                       "ASoC: %s %s has incorrect number of controls\n", type,
                        w->name);
                return -EINVAL;
        }
  
-       if (list_empty(&w->sources)) {
-               dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
+       if (list_empty(paths)) {
+               dev_err(dapm->dev, "ASoC: %s %s has no paths\n", type, w->name);
                return -EINVAL;
        }
  
        if (ret < 0)
                return ret;
  
-       list_for_each_entry(path, &w->sources, list_sink) {
-               if (path->name)
-                       dapm_kcontrol_add_path(w->kcontrols[0], path);
+       if (w->id == snd_soc_dapm_mux) {
+               list_for_each_entry(path, &w->sources, list_sink) {
+                       if (path->name)
+                               dapm_kcontrol_add_path(w->kcontrols[0], path);
+               }
+       } else {
+               list_for_each_entry(path, &w->sinks, list_source) {
+                       if (path->name)
+                               dapm_kcontrol_add_path(w->kcontrols[0], path);
+               }
        }
  
        return 0;
@@@ -2335,6 -2476,50 +2476,50 @@@ static void dapm_update_widget_flags(st
        }
  }
  
+ static int snd_soc_dapm_check_dynamic_path(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink,
+       const char *control)
+ {
+       bool dynamic_source = false;
+       bool dynamic_sink = false;
+       if (!control)
+               return 0;
+       switch (source->id) {
+       case snd_soc_dapm_demux:
+               dynamic_source = true;
+               break;
+       default:
+               break;
+       }
+       switch (sink->id) {
+       case snd_soc_dapm_mux:
+       case snd_soc_dapm_switch:
+       case snd_soc_dapm_mixer:
+       case snd_soc_dapm_mixer_named_ctl:
+               dynamic_sink = true;
+               break;
+       default:
+               break;
+       }
+       if (dynamic_source && dynamic_sink) {
+               dev_err(dapm->dev,
+                       "Direct connection between demux and mixer/mux not supported for path %s -> [%s] -> %s\n",
+                       source->name, control, sink->name);
+               return -EINVAL;
+       } else if (!dynamic_source && !dynamic_sink) {
+               dev_err(dapm->dev,
+                       "Control not supported for path %s -> [%s] -> %s\n",
+                       source->name, control, sink->name);
+               return -EINVAL;
+       }
+       return 0;
+ }
  static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
        struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
        const char *control,
                return -EINVAL;
        }
  
+       ret = snd_soc_dapm_check_dynamic_path(dapm, wsource, wsink, control);
+       if (ret)
+               return ret;
        path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
        if (!path)
                return -ENOMEM;
        if (control == NULL) {
                path->connect = 1;
        } else {
-               /* connect dynamic paths */
+               switch (wsource->id) {
+               case snd_soc_dapm_demux:
+                       ret = dapm_connect_mux(dapm, path, control, wsource);
+                       if (ret)
+                               goto err;
+                       break;
+               default:
+                       break;
+               }
                switch (wsink->id) {
                case snd_soc_dapm_mux:
-                       ret = dapm_connect_mux(dapm, path, control);
+                       ret = dapm_connect_mux(dapm, path, control, wsink);
                        if (ret != 0)
                                goto err;
                        break;
                                goto err;
                        break;
                default:
-                       dev_err(dapm->dev,
-                               "Control not supported for path %s -> [%s] -> %s\n",
-                               wsource->name, control, wsink->name);
-                       ret = -EINVAL;
-                       goto err;
+                       break;
                }
        }
  
@@@ -2451,6 -2645,12 +2645,12 @@@ static int snd_soc_dapm_add_route(struc
                source = route->source;
        }
  
+       wsource = dapm_wcache_lookup(&dapm->path_source_cache, source);
+       wsink = dapm_wcache_lookup(&dapm->path_sink_cache, sink);
+       if (wsink && wsource)
+               goto skip_search;
        /*
         * find src and dest widgets over all widgets but favor a widget from
         * current DAPM context
        list_for_each_entry(w, &dapm->card->widgets, list) {
                if (!wsink && !(strcmp(w->name, sink))) {
                        wtsink = w;
-                       if (w->dapm == dapm)
+                       if (w->dapm == dapm) {
                                wsink = w;
+                               if (wsource)
+                                       break;
+                       }
                        continue;
                }
                if (!wsource && !(strcmp(w->name, source))) {
                        wtsource = w;
-                       if (w->dapm == dapm)
+                       if (w->dapm == dapm) {
                                wsource = w;
+                               if (wsink)
+                                       break;
+                       }
                }
        }
        /* use widget from another DAPM context if not found from this */
                return -ENODEV;
        }
  
+ skip_search:
+       dapm_wcache_update(&dapm->path_sink_cache, wsink);
+       dapm_wcache_update(&dapm->path_source_cache, wsource);
        ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
                route->connected);
        if (ret)
@@@ -2736,6 -2946,7 +2946,7 @@@ int snd_soc_dapm_new_widgets(struct snd
                        dapm_new_mixer(w);
                        break;
                case snd_soc_dapm_mux:
+               case snd_soc_dapm_demux:
                        dapm_new_mux(w);
                        break;
                case snd_soc_dapm_pga:
@@@ -2902,16 -3113,21 +3113,21 @@@ int snd_soc_dapm_get_enum_double(struc
        struct snd_ctl_elem_value *ucontrol)
  {
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       struct snd_soc_card *card = dapm->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val;
  
-       if (e->reg != SND_SOC_NOPM) {
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       if (e->reg != SND_SOC_NOPM && dapm_kcontrol_is_powered(kcontrol)) {
                int ret = soc_dapm_read(dapm, e->reg, &reg_val);
-               if (ret)
+               if (ret) {
+                       mutex_unlock(&card->dapm_mutex);
                        return ret;
+               }
        } else {
                reg_val = dapm_kcontrol_get_value(kcontrol);
        }
+       mutex_unlock(&card->dapm_mutex);
  
        val = (reg_val >> e->shift_l) & e->mask;
        ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val);
@@@ -2941,7 -3157,7 +3157,7 @@@ int snd_soc_dapm_put_enum_double(struc
        struct snd_soc_card *card = dapm->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int *item = ucontrol->value.enumerated.item;
-       unsigned int val, change;
+       unsigned int val, change, reg_change = 0;
        unsigned int mask;
        struct snd_soc_dapm_update update;
        int ret = 0;
  
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
  
+       change = dapm_kcontrol_set_value(kcontrol, val);
        if (e->reg != SND_SOC_NOPM)
-               change = soc_dapm_test_bits(dapm, e->reg, mask, val);
-       else
-               change = dapm_kcontrol_set_value(kcontrol, val);
+               reg_change = soc_dapm_test_bits(dapm, e->reg, mask, val);
  
-       if (change) {
-               if (e->reg != SND_SOC_NOPM) {
+       if (change || reg_change) {
+               if (reg_change) {
                        update.kcontrol = kcontrol;
                        update.reg = e->reg;
                        update.mask = mask;
                        update.val = val;
                        card->update = &update;
                }
+               change |= reg_change;
  
                ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e);
  
@@@ -3053,8 -3270,25 +3270,25 @@@ int snd_soc_dapm_put_pin_switch(struct 
  }
  EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
  
- static struct snd_soc_dapm_widget *
+ struct snd_soc_dapm_widget *
  snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+       const struct snd_soc_dapm_widget *widget)
+ {
+       struct snd_soc_dapm_widget *w;
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       w = snd_soc_dapm_new_control_unlocked(dapm, widget);
+       if (!w)
+               dev_err(dapm->dev,
+                       "ASoC: Failed to create DAPM control %s\n",
+                       widget->name);
+       mutex_unlock(&dapm->card->dapm_mutex);
+       return w;
+ }
+ struct snd_soc_dapm_widget *
+ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget)
  {
        struct snd_soc_dapm_widget *w;
        }
  
        prefix = soc_dapm_prefix(dapm);
 -      if (prefix)
 +      if (prefix) {
                w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name);
 -      else
 +              if (widget->sname)
 +                      w->sname = kasprintf(GFP_KERNEL, "%s %s", prefix,
 +                                           widget->sname);
 +      } else {
                w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
 -
 +              if (widget->sname)
 +                      w->sname = kasprintf(GFP_KERNEL, "%s", widget->sname);
 +      }
        if (w->name == NULL) {
                kfree(w);
                return NULL;
                w->power_check = dapm_always_on_check_power;
                break;
        case snd_soc_dapm_mux:
+       case snd_soc_dapm_demux:
        case snd_soc_dapm_switch:
        case snd_soc_dapm_mixer:
        case snd_soc_dapm_mixer_named_ctl:
        INIT_LIST_HEAD(&w->sinks);
        INIT_LIST_HEAD(&w->list);
        INIT_LIST_HEAD(&w->dirty);
-       list_add(&w->list, &dapm->card->widgets);
+       list_add_tail(&w->list, &dapm->card->widgets);
  
        w->inputs = -1;
        w->outputs = -1;
@@@ -3204,7 -3434,7 +3439,7 @@@ int snd_soc_dapm_new_controls(struct sn
  
        mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
        for (i = 0; i < num; i++) {
-               w = snd_soc_dapm_new_control(dapm, widget);
+               w = snd_soc_dapm_new_control_unlocked(dapm, widget);
                if (!w) {
                        dev_err(dapm->dev,
                                "ASoC: Failed to create DAPM control %s\n",
@@@ -3442,7 -3672,7 +3677,7 @@@ int snd_soc_dapm_new_pcm(struct snd_soc
  
        dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
  
-       w = snd_soc_dapm_new_control(&card->dapm, &template);
+       w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
        if (!w) {
                dev_err(card->dev, "ASoC: Failed to create %s widget\n",
                        link_name);
@@@ -3493,7 -3723,7 +3728,7 @@@ int snd_soc_dapm_new_dai_widgets(struc
                dev_dbg(dai->dev, "ASoC: adding %s widget\n",
                        template.name);
  
-               w = snd_soc_dapm_new_control(dapm, &template);
+               w = snd_soc_dapm_new_control_unlocked(dapm, &template);
                if (!w) {
                        dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
                                dai->driver->playback.stream_name);
                dev_dbg(dai->dev, "ASoC: adding %s widget\n",
                        template.name);
  
-               w = snd_soc_dapm_new_control(dapm, &template);
+               w = snd_soc_dapm_new_control_unlocked(dapm, &template);
                if (!w) {
                        dev_err(dapm->dev, "ASoC: Failed to create %s widget\n",
                                dai->driver->capture.stream_name);