Merge branch 'for-3.5' into for-3.6
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 23 Jul 2012 09:45:07 +0000 (10:45 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 23 Jul 2012 09:45:07 +0000 (10:45 +0100)
1  2 
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320aic3x.h
sound/soc/codecs/wm8994.c
sound/soc/soc-dapm.c

@@@ -118,9 -118,7 +118,9 @@@ static const u8 aic3x_reg[AIC3X_CACHERE
        0x00, 0x00, 0x00, 0x00, /* 88 */
        0x00, 0x00, 0x00, 0x00, /* 92 */
        0x00, 0x00, 0x00, 0x00, /* 96 */
 -      0x00, 0x00, 0x02,       /* 100 */
 +      0x00, 0x00, 0x02, 0x00, /* 100 */
 +      0x00, 0x00, 0x00, 0x00, /* 104 */
 +      0x00, 0x00,             /* 108 */
  };
  
  #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \
@@@ -231,25 -229,6 +231,25 @@@ static const struct soc_enum aic3x_enum
        SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf),
  };
  
 +static const char *aic3x_agc_level[] =
 +      { "-5.5dB", "-8dB", "-10dB", "-12dB", "-14dB", "-17dB", "-20dB", "-24dB" };
 +static const struct soc_enum aic3x_agc_level_enum[] = {
 +      SOC_ENUM_SINGLE(LAGC_CTRL_A, 4, 8, aic3x_agc_level),
 +      SOC_ENUM_SINGLE(RAGC_CTRL_A, 4, 8, aic3x_agc_level),
 +};
 +
 +static const char *aic3x_agc_attack[] = { "8ms", "11ms", "16ms", "20ms" };
 +static const struct soc_enum aic3x_agc_attack_enum[] = {
 +      SOC_ENUM_SINGLE(LAGC_CTRL_A, 2, 4, aic3x_agc_attack),
 +      SOC_ENUM_SINGLE(RAGC_CTRL_A, 2, 4, aic3x_agc_attack),
 +};
 +
 +static const char *aic3x_agc_decay[] = { "100ms", "200ms", "400ms", "500ms" };
 +static const struct soc_enum aic3x_agc_decay_enum[] = {
 +      SOC_ENUM_SINGLE(LAGC_CTRL_A, 0, 4, aic3x_agc_decay),
 +      SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay),
 +};
 +
  /*
   * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
   */
@@@ -374,15 -353,6 +374,15 @@@ static const struct snd_kcontrol_new ai
         * adjust PGA to max value when ADC is on and will never go back.
        */
        SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
 +      SOC_ENUM("Left AGC Target level", aic3x_agc_level_enum[0]),
 +      SOC_ENUM("Right AGC Target level", aic3x_agc_level_enum[1]),
 +      SOC_ENUM("Left AGC Attack time", aic3x_agc_attack_enum[0]),
 +      SOC_ENUM("Right AGC Attack time", aic3x_agc_attack_enum[1]),
 +      SOC_ENUM("Left AGC Decay time", aic3x_agc_decay_enum[0]),
 +      SOC_ENUM("Right AGC Decay time", aic3x_agc_decay_enum[1]),
 +
 +      /* De-emphasis */
 +      SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0),
  
        /* Input */
        SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL,
  static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
  
  static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
 -      SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
 +      SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
  
  /* Left DAC Mux */
  static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
@@@ -965,9 -935,7 +965,7 @@@ static int aic3x_hw_params(struct snd_p
        }
  
  found:
-       data = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
-       snd_soc_write(codec, AIC3X_PLL_PROGA_REG,
-                     data | (pll_p << PLLP_SHIFT));
+       snd_soc_update_bits(codec, AIC3X_PLL_PROGA_REG, PLLP_MASK, pll_p);
        snd_soc_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG,
                      pll_r << PLLR_SHIFT);
        snd_soc_write(codec, AIC3X_PLL_PROGB_REG, pll_j << PLLJ_SHIFT);
@@@ -1002,12 -970,6 +1000,12 @@@ static int aic3x_set_dai_sysclk(struct 
        struct snd_soc_codec *codec = codec_dai->codec;
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
  
 +      /* set clock on MCLK or GPIO2 or BCLK */
 +      snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, PLLCLK_IN_MASK,
 +                              clk_id << PLLCLK_IN_SHIFT);
 +      snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, CLKDIV_IN_MASK,
 +                              clk_id << CLKDIV_IN_SHIFT);
 +
        aic3x->sysclk = freq;
        return 0;
  }
@@@ -13,7 -13,7 +13,7 @@@
  #define _AIC3X_H
  
  /* AIC3X register space */
 -#define AIC3X_CACHEREGNUM             103
 +#define AIC3X_CACHEREGNUM             110
  
  /* Page select register */
  #define AIC3X_PAGE_SELECT             0
@@@ -74,8 -74,6 +74,8 @@@
  #define HPLCOM_CFG                    37
  /* Right High Power Output control registers */
  #define HPRCOM_CFG                    38
 +/* High Power Output Stage Control Register */
 +#define HPOUT_SC                      40
  /* DAC Output Switching control registers */
  #define DAC_LINE_MUX                  41
  /* High Power Output Driver Pop Reduction registers */
  #define AIC3X_GPIOB_REG                       101
  /* Clock generation control register */
  #define AIC3X_CLKGEN_CTRL_REG         102
 +/* New AGC registers */
 +#define LAGCN_ATTACK                  103
 +#define LAGCN_DECAY                   104
 +#define RAGCN_ATTACK                  105
 +#define RAGCN_DECAY                   106
 +/* New Programmable ADC Digital Path and I2C Bus Condition Register */
 +#define NEW_ADC_DIGITALPATH           107
 +/* Passive Analog Signal Bypass Selection During Powerdown Register */
 +#define PASSIVE_BYPASS                        108
 +/* DAC Quiescent Current Adjustment Register */
 +#define DAC_ICC_ADJ                   109
  
  /* Page select register bits */
  #define PAGE0_SELECT          0
  #define DUAL_RATE_MODE                ((1 << 5) | (1 << 6))
  #define LDAC2LCH              (0x1 << 3)
  #define RDAC2RCH              (0x1 << 1)
 +#define LDAC2RCH              (0x2 << 3)
 +#define RDAC2LCH              (0x2 << 1)
 +#define LDAC2MONOMIX          (0x3 << 3)
 +#define RDAC2MONOMIX          (0x3 << 1)
  
  /* PLL registers bitfields */
  #define PLLP_SHIFT            0
+ #define PLLP_MASK             7
  #define PLLQ_SHIFT            3
  #define PLLR_SHIFT            0
  #define PLLJ_SHIFT            2
  #define PLL_CLKIN_SHIFT               4
  #define MCLK_SOURCE           0x0
  #define PLL_CLKDIV_SHIFT      0
 +#define PLLCLK_IN_MASK                0x30
 +#define PLLCLK_IN_SHIFT               4
 +#define CLKDIV_IN_MASK                0xc0
 +#define CLKDIV_IN_SHIFT               6
 +/* clock in source */
 +#define CLKIN_MCLK            0
 +#define CLKIN_GPIO2           1
 +#define CLKIN_BCLK            2
  
  /* Software reset register bits */
  #define SOFT_RESET            0x80
@@@ -1,7 -1,7 +1,7 @@@
  /*
   * wm8994.c  --  WM8994 ALSA SoC Audio driver
   *
 - * Copyright 2009 Wolfson Microelectronics plc
 + * Copyright 2009-12 Wolfson Microelectronics plc
   *
   * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   *
@@@ -727,9 -727,6 +727,6 @@@ static void wm1811_jackdet_set_mode(str
        if (!wm8994->jackdet || !wm8994->jack_cb)
                return;
  
-       if (!wm8994->jackdet || !wm8994->jack_cb)
-               return;
        if (wm8994->active_refcount)
                mode = WM1811_JACKDET_MODE_AUDIO;
  
@@@ -2970,8 -2967,23 +2967,8 @@@ static struct snd_soc_dai_driver wm8994
  static int wm8994_codec_suspend(struct snd_soc_codec *codec)
  {
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 -      struct wm8994 *control = wm8994->wm8994;
        int i, ret;
  
 -      switch (control->type) {
 -      case WM8994:
 -              snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
 -              break;
 -      case WM1811:
 -              snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
 -                                  WM1811_JACKDET_MODE_MASK, 0);
 -              /* Fall through */
 -      case WM8958:
 -              snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 -                                  WM8958_MICD_ENA, 0);
 -              break;
 -      }
 -
        for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
                memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
                       sizeof(struct wm8994_fll_config));
@@@ -3021,6 -3033,28 +3018,6 @@@ static int wm8994_codec_resume(struct s
                                 i + 1, ret);
        }
  
 -      switch (control->type) {
 -      case WM8994:
 -              if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
 -                      snd_soc_update_bits(codec, WM8994_MICBIAS,
 -                                          WM8994_MICD_ENA, WM8994_MICD_ENA);
 -              break;
 -      case WM1811:
 -              if (wm8994->jackdet && wm8994->jack_cb) {
 -                      /* Restart from idle */
 -                      snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
 -                                          WM1811_JACKDET_MODE_MASK,
 -                                          WM1811_JACKDET_MODE_JACK);
 -                      break;
 -              }
 -              break;
 -      case WM8958:
 -              if (wm8994->jack_cb)
 -                      snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
 -                                          WM8958_MICD_ENA, WM8958_MICD_ENA);
 -              break;
 -      }
 -
        return 0;
  }
  #else
@@@ -3695,6 -3729,9 +3692,6 @@@ static int wm8994_codec_probe(struct sn
  
        if (wm8994->pdata && wm8994->pdata->micdet_irq)
                wm8994->micdet_irq = wm8994->pdata->micdet_irq;
 -      else if (wm8994->pdata && wm8994->pdata->irq_base)
 -              wm8994->micdet_irq = wm8994->pdata->irq_base +
 -                                   WM8994_IRQ_MIC1_DET;
  
        pm_runtime_enable(codec->dev);
        pm_runtime_idle(codec->dev);
                                dev_warn(codec->dev,
                                         "Failed to request Mic detect IRQ: %d\n",
                                         ret);
 +              } else {
 +                      wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_MIC1_DET,
 +                                         wm8958_mic_irq, "Mic detect",
 +                                         wm8994);
                }
        }
  
diff --combined sound/soc/soc-dapm.c
@@@ -35,7 -35,6 +35,7 @@@
  #include <linux/debugfs.h>
  #include <linux/pm_runtime.h>
  #include <linux/regulator/consumer.h>
 +#include <linux/clk.h>
  #include <linux/slab.h>
  #include <sound/core.h>
  #include <sound/pcm.h>
@@@ -52,7 -51,6 +52,7 @@@ static int dapm_up_seq[] = 
        [snd_soc_dapm_pre] = 0,
        [snd_soc_dapm_supply] = 1,
        [snd_soc_dapm_regulator_supply] = 1,
 +      [snd_soc_dapm_clock_supply] = 1,
        [snd_soc_dapm_micbias] = 2,
        [snd_soc_dapm_dai_link] = 2,
        [snd_soc_dapm_dai] = 3,
@@@ -94,7 -92,6 +94,7 @@@ static int dapm_down_seq[] = 
        [snd_soc_dapm_aif_out] = 10,
        [snd_soc_dapm_dai] = 10,
        [snd_soc_dapm_dai_link] = 11,
 +      [snd_soc_dapm_clock_supply] = 12,
        [snd_soc_dapm_regulator_supply] = 12,
        [snd_soc_dapm_supply] = 12,
        [snd_soc_dapm_post] = 13,
@@@ -291,9 -288,9 +291,9 @@@ static int snd_soc_dapm_set_bias_level(
                if (dapm->codec->driver->set_bias_level)
                        ret = dapm->codec->driver->set_bias_level(dapm->codec,
                                                                  level);
-               else
-                       dapm->bias_level = level;
-       }
+       } else
+               dapm->bias_level = level;
        if (ret != 0)
                goto out;
  
@@@ -324,11 -321,10 +324,10 @@@ static void dapm_set_path_status(struc
  
                val = soc_widget_read(w, reg);
                val = (val >> shift) & mask;
+               if (invert)
+                       val = max - val;
  
-               if ((invert && !val) || (!invert && val))
-                       p->connect = 1;
-               else
-                       p->connect = 0;
+               p->connect = !!val;
        }
        break;
        case snd_soc_dapm_mux: {
        case snd_soc_dapm_vmid:
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
 +      case snd_soc_dapm_clock_supply:
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai:
@@@ -768,7 -763,6 +767,7 @@@ static int is_connected_output_ep(struc
        switch (widget->id) {
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
 +      case snd_soc_dapm_clock_supply:
                return 0;
        default:
                break;
@@@ -855,7 -849,6 +854,7 @@@ static int is_connected_input_ep(struc
        switch (widget->id) {
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
 +      case snd_soc_dapm_clock_supply:
                return 0;
        default:
                break;
@@@ -1002,27 -995,6 +1001,27 @@@ int dapm_regulator_event(struct snd_soc
  }
  EXPORT_SYMBOL_GPL(dapm_regulator_event);
  
 +/*
 + * Handler for clock supply widget.
 + */
 +int dapm_clock_event(struct snd_soc_dapm_widget *w,
 +                 struct snd_kcontrol *kcontrol, int event)
 +{
 +      if (!w->clk)
 +              return -EIO;
 +
 +#ifdef CONFIG_HAVE_CLK
 +      if (SND_SOC_DAPM_EVENT_ON(event)) {
 +              return clk_enable(w->clk);
 +      } else {
 +              clk_disable(w->clk);
 +              return 0;
 +      }
 +#endif
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(dapm_clock_event);
 +
  static int dapm_widget_power_check(struct snd_soc_dapm_widget *w)
  {
        if (w->power_checked)
@@@ -1514,7 -1486,6 +1513,7 @@@ static void dapm_widget_set_power(struc
        switch (w->id) {
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
 +      case snd_soc_dapm_clock_supply:
                /* Supplies can't affect their outputs, only their inputs */
                break;
        default:
@@@ -1598,15 -1569,7 +1597,15 @@@ static int dapm_power_widgets(struct sn
        }
  
        list_for_each_entry(w, &card->widgets, list) {
 -              list_del_init(&w->dirty);
 +              switch (w->id) {
 +              case snd_soc_dapm_pre:
 +              case snd_soc_dapm_post:
 +                      /* These widgets always need to be powered */
 +                      break;
 +              default:
 +                      list_del_init(&w->dirty);
 +                      break;
 +              }
  
                if (w->power) {
                        d = w->dapm;
                                break;
                        case snd_soc_dapm_supply:
                        case snd_soc_dapm_regulator_supply:
 +                      case snd_soc_dapm_clock_supply:
                        case snd_soc_dapm_micbias:
                                if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
                                        d->target_bias_level = SND_SOC_BIAS_STANDBY;
@@@ -1978,7 -1940,6 +1977,7 @@@ static ssize_t dapm_widget_show(struct 
                case snd_soc_dapm_mixer_named_ctl:
                case snd_soc_dapm_supply:
                case snd_soc_dapm_regulator_supply:
 +              case snd_soc_dapm_clock_supply:
                        if (w->name)
                                count += sprintf(buf + count, "%s: %s\n",
                                        w->name, w->power ? "On":"Off");
@@@ -2225,7 -2186,6 +2224,7 @@@ static int snd_soc_dapm_add_route(struc
        case snd_soc_dapm_post:
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
 +      case snd_soc_dapm_clock_supply:
        case snd_soc_dapm_aif_in:
        case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai:
                path->connect = 0;
                return 0;
        }
 +
 +      dapm_mark_dirty(wsource, "Route added");
 +      dapm_mark_dirty(wsink, "Route added");
 +
        return 0;
  
  err:
        return ret;
  }
  
 +static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
 +                                const struct snd_soc_dapm_route *route)
 +{
 +      struct snd_soc_dapm_path *path, *p;
 +      const char *sink;
 +      const char *source;
 +      char prefixed_sink[80];
 +      char prefixed_source[80];
 +
 +      if (route->control) {
 +              dev_err(dapm->dev,
 +                      "Removal of routes with controls not supported\n");
 +              return -EINVAL;
 +      }
 +
 +      if (dapm->codec && dapm->codec->name_prefix) {
 +              snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
 +                       dapm->codec->name_prefix, route->sink);
 +              sink = prefixed_sink;
 +              snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
 +                       dapm->codec->name_prefix, route->source);
 +              source = prefixed_source;
 +      } else {
 +              sink = route->sink;
 +              source = route->source;
 +      }
 +
 +      path = NULL;
 +      list_for_each_entry(p, &dapm->card->paths, list) {
 +              if (strcmp(p->source->name, source) != 0)
 +                      continue;
 +              if (strcmp(p->sink->name, sink) != 0)
 +                      continue;
 +              path = p;
 +              break;
 +      }
 +
 +      if (path) {
 +              dapm_mark_dirty(path->source, "Route removed");
 +              dapm_mark_dirty(path->sink, "Route removed");
 +
 +              list_del(&path->list);
 +              list_del(&path->list_sink);
 +              list_del(&path->list_source);
 +              kfree(path);
 +      } else {
 +              dev_warn(dapm->dev, "Route %s->%s does not exist\n",
 +                       source, sink);
 +      }
 +
 +      return 0;
 +}
 +
  /**
   * snd_soc_dapm_add_routes - Add routes between DAPM widgets
   * @dapm: DAPM context
  int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
                            const struct snd_soc_dapm_route *route, int num)
  {
 -      int i, ret = 0;
 +      int i, r, ret = 0;
  
        mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
        for (i = 0; i < num; i++) {
 -              ret = snd_soc_dapm_add_route(dapm, route);
 -              if (ret < 0) {
 +              r = snd_soc_dapm_add_route(dapm, route);
 +              if (r < 0) {
                        dev_err(dapm->dev, "Failed to add route %s->%s\n",
                                route->source, route->sink);
 -                      break;
 +                      ret = r;
                }
                route++;
        }
  }
  EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
  
 +/**
 + * snd_soc_dapm_del_routes - Remove routes between DAPM widgets
 + * @dapm: DAPM context
 + * @route: audio routes
 + * @num: number of routes
 + *
 + * Removes routes from the DAPM context.
 + */
 +int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
 +                          const struct snd_soc_dapm_route *route, int num)
 +{
 +      int i, ret = 0;
 +
 +      mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 +      for (i = 0; i < num; i++) {
 +              snd_soc_dapm_del_route(dapm, route);
 +              route++;
 +      }
 +      mutex_unlock(&dapm->card->dapm_mutex);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes);
 +
  static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
                                   const struct snd_soc_dapm_route *route)
  {
@@@ -2554,20 -2433,23 +2553,20 @@@ int snd_soc_dapm_get_volsw(struct snd_k
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
        unsigned int shift = mc->shift;
 -      unsigned int rshift = mc->rshift;
        int max = mc->max;
 -      unsigned int invert = mc->invert;
        unsigned int mask = (1 << fls(max)) - 1;
 +      unsigned int invert = mc->invert;
 +
 +      if (snd_soc_volsw_is_stereo(mc))
 +              dev_warn(widget->dapm->dev,
 +                       "Control '%s' is stereo, which is not supported\n",
 +                       kcontrol->id.name);
  
        ucontrol->value.integer.value[0] =
                (snd_soc_read(widget->codec, reg) >> shift) & mask;
 -      if (shift != rshift)
 -              ucontrol->value.integer.value[1] =
 -                      (snd_soc_read(widget->codec, reg) >> rshift) & mask;
 -      if (invert) {
 +      if (invert)
                ucontrol->value.integer.value[0] =
                        max - ucontrol->value.integer.value[0];
 -              if (shift != rshift)
 -                      ucontrol->value.integer.value[1] =
 -                              max - ucontrol->value.integer.value[1];
 -      }
  
        return 0;
  }
@@@ -2601,19 -2483,20 +2600,19 @@@ int snd_soc_dapm_put_volsw(struct snd_k
        struct snd_soc_dapm_update update;
        int wi;
  
 +      if (snd_soc_volsw_is_stereo(mc))
 +              dev_warn(widget->dapm->dev,
 +                       "Control '%s' is stereo, which is not supported\n",
 +                       kcontrol->id.name);
 +
        val = (ucontrol->value.integer.value[0] & mask);
 +      connect = !!val;
  
        if (invert)
                val = max - val;
        mask = mask << shift;
        val = val << shift;
  
 -      if (val)
 -              /* new connection */
 -              connect = invert ? 0 : 1;
 -      else
 -              /* old connection must be powered down */
 -              connect = invert ? 1 : 0;
 -
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
  
        change = snd_soc_test_bits(widget->codec, reg, mask, val);
@@@ -2989,19 -2872,6 +2988,19 @@@ snd_soc_dapm_new_control(struct snd_soc
                        return NULL;
                }
                break;
 +      case snd_soc_dapm_clock_supply:
 +#ifdef CONFIG_CLKDEV_LOOKUP
 +              w->clk = devm_clk_get(dapm->dev, w->name);
 +              if (IS_ERR(w->clk)) {
 +                      ret = PTR_ERR(w->clk);
 +                      dev_err(dapm->dev, "Failed to request %s: %d\n",
 +                              w->name, ret);
 +                      return NULL;
 +              }
 +#else
 +              return NULL;
 +#endif
 +              break;
        default:
                break;
        }
                break;
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
 +      case snd_soc_dapm_clock_supply:
                w->power_check = dapm_supply_check_power;
                break;
        case snd_soc_dapm_dai:
@@@ -3668,10 -3537,13 +3667,13 @@@ EXPORT_SYMBOL_GPL(snd_soc_dapm_free)
  
  static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
  {
+       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(down_list);
        int powerdown = 0;
  
+       mutex_lock(&card->dapm_mutex);
        list_for_each_entry(w, &dapm->card->widgets, list) {
                if (w->dapm != dapm)
                        continue;
                        snd_soc_dapm_set_bias_level(dapm,
                                                    SND_SOC_BIAS_STANDBY);
        }
+       mutex_unlock(&card->dapm_mutex);
  }
  
  /*