OSDN Git Service

Merge tag 'asoc-v3.10-4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Fri, 3 May 2013 09:39:36 +0000 (11:39 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 3 May 2013 09:39:36 +0000 (11:39 +0200)
ASoC: Updates for v3.10

A few more bug fixes, the DAPM clock fix is actually a driver specific
one since currently there's only one user of the clock support due to
the problems relying on the clock API.

1  2 
sound/soc/codecs/wm8994.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/soc-dapm.c

@@@ -2209,7 -2209,7 +2209,7 @@@ static int _wm8994_set_fll(struct snd_s
                                vmid_reference(codec);
                                break;
                        case WM8958:
 -                              if (wm8994->revision < 1)
 +                              if (control->revision < 1)
                                        vmid_reference(codec);
                                break;
                        default:
                                vmid_dereference(codec);
                                break;
                        case WM8958:
 -                              if (wm8994->revision < 1)
 +                              if (control->revision < 1)
                                        vmid_dereference(codec);
                                break;
                        default:
         */
        if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
                dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
 +
 +              wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
 +                      & WM8994_AIF1CLK_RATE_MASK;
 +              wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
 +                      & WM8994_AIF1CLK_RATE_MASK;
 +
                snd_soc_update_bits(codec, WM8994_AIF1_RATE,
                                    WM8994_AIF1CLK_RATE_MASK, 0x1);
                snd_soc_update_bits(codec, WM8994_AIF2_RATE,
                                    WM8994_AIF2CLK_RATE_MASK, 0x1);
 +      } else if (wm8994->aifdiv[0]) {
 +              snd_soc_update_bits(codec, WM8994_AIF1_RATE,
 +                                  WM8994_AIF1CLK_RATE_MASK,
 +                                  wm8994->aifdiv[0]);
 +              snd_soc_update_bits(codec, WM8994_AIF2_RATE,
 +                                  WM8994_AIF2CLK_RATE_MASK,
 +                                  wm8994->aifdiv[1]);
 +
 +              wm8994->aifdiv[0] = 0;
 +              wm8994->aifdiv[1] = 0;
        }
  
        return 0;
@@@ -2384,26 -2368,10 +2384,26 @@@ static int wm8994_set_dai_sysclk(struc
         */
        if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
                dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
 +
 +              wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
 +                      & WM8994_AIF1CLK_RATE_MASK;
 +              wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
 +                      & WM8994_AIF1CLK_RATE_MASK;
 +
                snd_soc_update_bits(codec, WM8994_AIF1_RATE,
                                    WM8994_AIF1CLK_RATE_MASK, 0x1);
                snd_soc_update_bits(codec, WM8994_AIF2_RATE,
                                    WM8994_AIF2CLK_RATE_MASK, 0x1);
 +      } else if (wm8994->aifdiv[0]) {
 +              snd_soc_update_bits(codec, WM8994_AIF1_RATE,
 +                                  WM8994_AIF1CLK_RATE_MASK,
 +                                  wm8994->aifdiv[0]);
 +              snd_soc_update_bits(codec, WM8994_AIF2_RATE,
 +                                  WM8994_AIF2CLK_RATE_MASK,
 +                                  wm8994->aifdiv[1]);
 +
 +              wm8994->aifdiv[0] = 0;
 +              wm8994->aifdiv[1] = 0;
        }
  
        return 0;
@@@ -2443,7 -2411,7 +2443,7 @@@ static int wm8994_set_bias_level(struc
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        switch (control->type) {
                        case WM8958:
 -                              if (wm8994->revision == 0) {
 +                              if (control->revision == 0) {
                                        /* Optimise performance for rev A */
                                        snd_soc_update_bits(codec,
                                                            WM8958_CHARGE_PUMP_2,
@@@ -2688,8 -2656,6 +2688,8 @@@ static int wm8994_hw_params(struct snd_
  {
        struct snd_soc_codec *codec = dai->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 +      struct wm8994 *control = wm8994->wm8994;
 +      struct wm8994_pdata *pdata = &control->pdata;
        int aif1_reg;
        int aif2_reg;
        int bclk_reg;
        }
  
        wm8994->channels[id] = params_channels(params);
 -      switch (params_channels(params)) {
 +      if (pdata->max_channels_clocked[id] &&
 +          wm8994->channels[id] > pdata->max_channels_clocked[id]) {
 +              dev_dbg(dai->dev, "Constraining channels to %d from %d\n",
 +                      pdata->max_channels_clocked[id], wm8994->channels[id]);
 +              wm8994->channels[id] = pdata->max_channels_clocked[id];
 +      }
 +
 +      switch (wm8994->channels[id]) {
        case 1:
        case 2:
                bclk_rate *= 2;
        dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
                dai->id, wm8994->aifclk[id], bclk_rate);
  
 -      if (params_channels(params) == 1 &&
 +      if (wm8994->channels[id] == 1 &&
            (snd_soc_read(codec, aif1_reg) & 0x18) == 0x18)
                aif2 |= WM8994_AIF1_MONO;
  
@@@ -2882,6 -2841,7 +2882,7 @@@ static int wm8994_aif3_hw_params(struc
                default:
                        return 0;
                }
+               break;
        default:
                return 0;
        }
@@@ -3094,7 -3054,7 +3095,7 @@@ static int wm8994_codec_resume(struct s
        int i, ret;
        unsigned int val, mask;
  
 -      if (wm8994->revision < 4) {
 +      if (control->revision < 4) {
                /* force a HW read */
                ret = regmap_read(control->regmap,
                                  WM8994_POWER_MANAGEMENT_5, &val);
@@@ -3911,6 -3871,7 +3912,6 @@@ static int wm8994_codec_probe(struct sn
        codec->dapm.idle_bias_off = 1;
  
        /* Set revision-specific configuration */
 -      wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
        switch (control->type) {
        case WM8994:
                /* Single ended line outputs should have VMID on. */
                    !control->pdata.lineout2_diff)
                        codec->dapm.idle_bias_off = 0;
  
 -              switch (wm8994->revision) {
 +              switch (control->revision) {
                case 2:
                case 3:
                        wm8994->hubs.dcs_codes_l = -5;
                wm8994->hubs.dcs_readback_mode = 1;
                wm8994->hubs.hp_startup_mode = 1;
  
 -              switch (wm8994->revision) {
 +              switch (control->revision) {
                case 0:
                        break;
                default:
  
        switch (control->type) {
        case WM1811:
 -              if (control->cust_id > 1 || wm8994->revision > 1) {
 +              if (control->cust_id > 1 || control->revision > 1) {
                        ret = wm8994_request_irq(wm8994->wm8994,
                                                 WM8994_IRQ_GPIO(6),
                                                 wm1811_jackdet_irq, "JACKDET",
        case WM8994:
                snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
                                          ARRAY_SIZE(wm8994_specific_dapm_widgets));
 -              if (wm8994->revision < 4) {
 +              if (control->revision < 4) {
                        snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
                                                  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
                        snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
                                     ARRAY_SIZE(wm8958_snd_controls));
                snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
                                          ARRAY_SIZE(wm8958_dapm_widgets));
 -              if (wm8994->revision < 1) {
 +              if (control->revision < 1) {
                        snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
                                                  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
                        snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
                snd_soc_dapm_add_routes(dapm, wm8994_intercon,
                                        ARRAY_SIZE(wm8994_intercon));
  
 -              if (wm8994->revision < 4) {
 +              if (control->revision < 4) {
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
                                                ARRAY_SIZE(wm8994_revd_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
                }
                break;
        case WM8958:
 -              if (wm8994->revision < 1) {
 +              if (control->revision < 1) {
                        snd_soc_dapm_add_routes(dapm, wm8994_intercon,
                                                ARRAY_SIZE(wm8994_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
  #define DISMOD                (val)(val<<2)
  #define TXSTATE               BIT(4)
  #define RXSTATE               BIT(5)
 +#define SRMOD_MASK    3
 +#define SRMOD_INACTIVE        0
  
  /*
   * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
@@@ -505,7 -503,10 +505,10 @@@ static int davinci_mcasp_set_dai_fmt(st
                mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE);
                mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE);
  
-               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, ACLKX | AFSX);
+               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               ACLKX | ACLKR);
+               mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG,
+                               AFSX | AFSR);
                break;
        case SND_SOC_DAIFMT_CBM_CFS:
                /* codec is clock master and frame slave */
                mcasp_set_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
  
-               mcasp_clr_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
  
@@@ -636,43 -637,35 +639,43 @@@ static int davinci_config_channel_size(
         * callback, take it into account here. That allows us to for example
         * send 32 bits per channel to the codec, while only 16 of them carry
         * audio payload.
 -       * The clock ratio is given for a full period of data (both left and
 -       * right channels), so it has to be divided by 2.
 +       * The clock ratio is given for a full period of data (for I2S format
 +       * both left and right channels), so it has to be divided by number of
 +       * tdm-slots (for I2S - divided by 2).
         */
        if (dev->bclk_lrclk_ratio)
 -              word_length = dev->bclk_lrclk_ratio / 2;
 +              word_length = dev->bclk_lrclk_ratio / dev->tdm_slots;
  
        /* mapping of the XSSZ bit-field as described in the datasheet */
        fmt = (word_length >> 1) - 1;
  
 -      mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
 -                                      RXSSZ(fmt), RXSSZ(0x0F));
 -      mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
 -                                      TXSSZ(fmt), TXSSZ(0x0F));
 -      mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate),
 -                                                      TXROT(7));
 -      mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate),
 -                                                      RXROT(7));
 +      if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
 +              mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
 +                              RXSSZ(fmt), RXSSZ(0x0F));
 +              mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
 +                              TXSSZ(fmt), TXSSZ(0x0F));
 +              mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
 +                              TXROT(rotate), TXROT(7));
 +              mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
 +                              RXROT(rotate), RXROT(7));
 +              mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG,
 +                              mask);
 +      }
 +
        mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
 -      mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask);
  
        return 0;
  }
  
 -static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
 +static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
 +                                  int channels)
  {
        int i;
        u8 tx_ser = 0;
        u8 rx_ser = 0;
 -
 +      u8 ser;
 +      u8 slots = dev->tdm_slots;
 +      u8 max_active_serializers = (channels + slots - 1) / slots;
        /* Default configuration */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
  
        for (i = 0; i < dev->num_serializer; i++) {
                mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
                                        dev->serial_dir[i]);
 -              if (dev->serial_dir[i] == TX_MODE) {
 +              if (dev->serial_dir[i] == TX_MODE &&
 +                                      tx_ser < max_active_serializers) {
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        tx_ser++;
 -              } else if (dev->serial_dir[i] == RX_MODE) {
 +              } else if (dev->serial_dir[i] == RX_MODE &&
 +                                      rx_ser < max_active_serializers) {
                        mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        rx_ser++;
 +              } else {
 +                      mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
 +                                      SRMOD_INACTIVE, SRMOD_MASK);
                }
        }
  
 +      if (stream == SNDRV_PCM_STREAM_PLAYBACK)
 +              ser = tx_ser;
 +      else
 +              ser = rx_ser;
 +
 +      if (ser < max_active_serializers) {
 +              dev_warn(dev->dev, "stream has more channels (%d) than are "
 +                      "enabled in mcasp (%d)\n", channels, ser * slots);
 +              return -EINVAL;
 +      }
 +
        if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (dev->txnumevt * tx_ser > 64)
                        dev->txnumevt = 1;
                                ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
                }
        }
 +
 +      return 0;
  }
  
  static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
  /* S/PDIF */
  static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
  {
 -      /* Set the PDIR for Serialiser as output */
 -      mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
 -
 -      /* TXMASK for 24 bits */
 -      mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
 -
        /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
           and LSB first */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
@@@ -834,21 -815,12 +837,21 @@@ static int davinci_mcasp_hw_params(stru
                                        &dev->dma_params[substream->stream];
        int word_length;
        u8 fifo_level;
 +      u8 slots = dev->tdm_slots;
 +      u8 active_serializers;
 +      int channels;
 +      struct snd_interval *pcm_channels = hw_param_interval(params,
 +                                      SNDRV_PCM_HW_PARAM_CHANNELS);
 +      channels = pcm_channels->min;
 +
 +      active_serializers = (channels + slots - 1) / slots;
  
 -      davinci_hw_common_param(dev, substream->stream);
 +      if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
 +              return -EINVAL;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 -              fifo_level = dev->txnumevt;
 +              fifo_level = dev->txnumevt * active_serializers;
        else
 -              fifo_level = dev->rxnumevt;
 +              fifo_level = dev->rxnumevt * active_serializers;
  
        if (dev->op_mode == DAVINCI_MCASP_DIT_MODE)
                davinci_hw_dit_param(dev);
@@@ -967,13 -939,13 +970,13 @@@ static struct snd_soc_dai_driver davinc
                .name           = "davinci-mcasp.0",
                .playback       = {
                        .channels_min   = 2,
 -                      .channels_max   = 2,
 +                      .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
                .capture        = {
                        .channels_min   = 2,
 -                      .channels_max   = 2,
 +                      .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
  
  };
  
 +static const struct snd_soc_component_driver davinci_mcasp_component = {
 +      .name           = "davinci-mcasp",
 +};
 +
  static const struct of_device_id mcasp_dt_ids[] = {
        {
                .compatible = "ti,dm646x-mcasp-audio",
@@@ -1050,16 -1018,8 +1053,16 @@@ static struct snd_platform_data *davinc
                pdata->op_mode = val;
  
        ret = of_property_read_u32(np, "tdm-slots", &val);
 -      if (ret >= 0)
 +      if (ret >= 0) {
 +              if (val < 2 || val > 32) {
 +                      dev_err(&pdev->dev,
 +                              "tdm-slots must be in rage [2-32]\n");
 +                      ret = -EINVAL;
 +                      goto nodata;
 +              }
 +
                pdata->tdm_slots = val;
 +      }
  
        ret = of_property_read_u32(np, "num-serializer", &val);
        if (ret >= 0)
@@@ -1213,8 -1173,7 +1216,8 @@@ static int davinci_mcasp_probe(struct p
  
        dma_data->channel = res->start;
        dev_set_drvdata(&pdev->dev, dev);
 -      ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
 +      ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
 +                                       &davinci_mcasp_dai[pdata->op_mode], 1);
  
        if (ret != 0)
                goto err_release_clk;
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
 -              goto err_unregister_dai;
 +              goto err_unregister_component;
        }
  
        return 0;
  
 -err_unregister_dai:
 -      snd_soc_unregister_dai(&pdev->dev);
 +err_unregister_component:
 +      snd_soc_unregister_component(&pdev->dev);
  err_release_clk:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
  static int davinci_mcasp_remove(struct platform_device *pdev)
  {
  
 -      snd_soc_unregister_dai(&pdev->dev);
 +      snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
  
        pm_runtime_put_sync(&pdev->dev);
diff --combined sound/soc/soc-dapm.c
@@@ -504,27 -504,17 +504,27 @@@ static int dapm_is_shared_kcontrol(stru
        return 0;
  }
  
 -/* create new dapm mixer control */
 -static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
 +/*
 + * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
 + * create it. Either way, add the widget into the control's widget list
 + */
 +static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
 +      int kci, struct snd_soc_dapm_path *path)
  {
        struct snd_soc_dapm_context *dapm = w->dapm;
 -      int i, ret = 0;
 -      size_t name_len, prefix_len;
 -      struct snd_soc_dapm_path *path;
        struct snd_card *card = dapm->card->snd_card;
        const char *prefix;
 +      size_t prefix_len;
 +      int shared;
 +      struct snd_kcontrol *kcontrol;
        struct snd_soc_dapm_widget_list *wlist;
 +      int wlistentries;
        size_t wlistsize;
 +      bool wname_in_long_name, kcname_in_long_name;
 +      size_t name_len;
 +      char *long_name;
 +      const char *name;
 +      int ret;
  
        if (dapm->codec)
                prefix = dapm->codec->name_prefix;
        else
                prefix_len = 0;
  
 -      /* add kcontrol */
 -      for (i = 0; i < w->num_kcontrols; i++) {
 +      shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
 +                                       &kcontrol);
  
 -              /* match name */
 -              list_for_each_entry(path, &w->sources, list_sink) {
 +      if (kcontrol) {
 +              wlist = kcontrol->private_data;
 +              wlistentries = wlist->num_widgets + 1;
 +      } else {
 +              wlist = NULL;
 +              wlistentries = 1;
 +      }
  
 -                      /* mixer/mux paths name must match control name */
 -                      if (path->name != (char *)w->kcontrol_news[i].name)
 -                              continue;
 +      wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
 +                      wlistentries * sizeof(struct snd_soc_dapm_widget *);
 +      wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
 +      if (wlist == NULL) {
 +              dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
 +                      w->name);
 +              return -ENOMEM;
 +      }
 +      wlist->num_widgets = wlistentries;
 +      wlist->widgets[wlistentries - 1] = w;
  
 -                      if (w->kcontrols[i]) {
 -                              path->kcontrol = w->kcontrols[i];
 -                              continue;
 +      if (!kcontrol) {
 +              if (shared) {
 +                      wname_in_long_name = false;
 +                      kcname_in_long_name = true;
 +              } else {
 +                      switch (w->id) {
 +                      case snd_soc_dapm_switch:
 +                      case snd_soc_dapm_mixer:
 +                              wname_in_long_name = true;
 +                              kcname_in_long_name = true;
 +                              break;
 +                      case snd_soc_dapm_mixer_named_ctl:
 +                              wname_in_long_name = false;
 +                              kcname_in_long_name = true;
 +                              break;
 +                      case snd_soc_dapm_mux:
 +                      case snd_soc_dapm_virt_mux:
 +                      case snd_soc_dapm_value_mux:
 +                              wname_in_long_name = true;
 +                              kcname_in_long_name = false;
 +                              break;
 +                      default:
 +                              kfree(wlist);
 +                              return -EINVAL;
                        }
 +              }
  
 -                      wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
 -                                  sizeof(struct snd_soc_dapm_widget *),
 -                      wlist = kzalloc(wlistsize, GFP_KERNEL);
 -                      if (wlist == NULL) {
 -                              dev_err(dapm->dev,
 -                                      "ASoC: can't allocate widget list for %s\n",
 -                                      w->name);
 +              if (wname_in_long_name && kcname_in_long_name) {
 +                      name_len = strlen(w->name) - prefix_len + 1 +
 +                                 strlen(w->kcontrol_news[kci].name) + 1;
 +
 +                      long_name = kmalloc(name_len, GFP_KERNEL);
 +                      if (long_name == NULL) {
 +                              kfree(wlist);
                                return -ENOMEM;
                        }
 -                      wlist->num_widgets = 1;
 -                      wlist->widgets[0] = w;
 -
 -                      /* add dapm control with long name.
 -                       * for dapm_mixer this is the concatenation of the
 -                       * mixer and kcontrol name.
 -                       * for dapm_mixer_named_ctl this is simply the
 -                       * kcontrol name.
 +
 +                      /*
 +                       * The control will get a prefix from the control
 +                       * creation process but we're also using the same
 +                       * prefix for widgets so cut the prefix off the
 +                       * front of the widget name.
                         */
 -                      name_len = strlen(w->kcontrol_news[i].name) + 1;
 -                      if (w->id != snd_soc_dapm_mixer_named_ctl)
 -                              name_len += 1 + strlen(w->name);
 +                      snprintf(long_name, name_len, "%s %s",
 +                               w->name + prefix_len,
 +                               w->kcontrol_news[kci].name);
 +                      long_name[name_len - 1] = '\0';
 +
 +                      name = long_name;
 +              } else if (wname_in_long_name) {
 +                      long_name = NULL;
 +                      name = w->name + prefix_len;
 +              } else {
 +                      long_name = NULL;
 +                      name = w->kcontrol_news[kci].name;
 +              }
  
 -                      path->long_name = kmalloc(name_len, GFP_KERNEL);
 +              kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
 +                                      prefix);
 +              ret = snd_ctl_add(card, kcontrol);
 +              if (ret < 0) {
 +                      dev_err(dapm->dev,
 +                              "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
 +                              w->name, name, ret);
 +                      kfree(wlist);
 +                      kfree(long_name);
 +                      return ret;
 +              }
  
 -                      if (path->long_name == NULL) {
 -                              kfree(wlist);
 -                              return -ENOMEM;
 -                      }
 +              path->long_name = long_name;
 +      }
  
 -                      switch (w->id) {
 -                      default:
 -                              /* The control will get a prefix from
 -                               * the control creation process but
 -                               * we're also using the same prefix
 -                               * for widgets so cut the prefix off
 -                               * the front of the widget name.
 -                               */
 -                              snprintf((char *)path->long_name, name_len,
 -                                       "%s %s", w->name + prefix_len,
 -                                       w->kcontrol_news[i].name);
 -                              break;
 -                      case snd_soc_dapm_mixer_named_ctl:
 -                              snprintf((char *)path->long_name, name_len,
 -                                       "%s", w->kcontrol_news[i].name);
 -                              break;
 -                      }
 +      kcontrol->private_data = wlist;
 +      w->kcontrols[kci] = kcontrol;
 +      path->kcontrol = kcontrol;
  
 -                      ((char *)path->long_name)[name_len - 1] = '\0';
 +      return 0;
 +}
  
 -                      path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
 -                                                    wlist, path->long_name,
 -                                                    prefix);
 -                      ret = snd_ctl_add(card, path->kcontrol);
 -                      if (ret < 0) {
 -                              dev_err(dapm->dev, "ASoC: failed to add widget"
 -                                      " %s dapm kcontrol %s: %d\n",
 -                                      w->name, path->long_name, ret);
 -                              kfree(wlist);
 -                              kfree(path->long_name);
 -                              path->long_name = NULL;
 -                              return ret;
 +/* create new dapm mixer control */
 +static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
 +{
 +      int i, ret;
 +      struct snd_soc_dapm_path *path;
 +
 +      /* add kcontrol */
 +      for (i = 0; i < w->num_kcontrols; i++) {
 +              /* match name */
 +              list_for_each_entry(path, &w->sources, list_sink) {
 +                      /* mixer/mux paths name must match control name */
 +                      if (path->name != (char *)w->kcontrol_news[i].name)
 +                              continue;
 +
 +                      if (w->kcontrols[i]) {
 +                              path->kcontrol = w->kcontrols[i];
 +                              continue;
                        }
 -                      w->kcontrols[i] = path->kcontrol;
 +
 +                      ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
 +                      if (ret < 0)
 +                              return ret;
                }
        }
 -      return ret;
 +
 +      return 0;
  }
  
  /* create new dapm mux control */
  static int dapm_new_mux(struct snd_soc_dapm_widget *w)
  {
        struct snd_soc_dapm_context *dapm = w->dapm;
 -      struct snd_soc_dapm_path *path = NULL;
 -      struct snd_kcontrol *kcontrol;
 -      struct snd_card *card = dapm->card->snd_card;
 -      const char *prefix;
 -      size_t prefix_len;
 +      struct snd_soc_dapm_path *path;
        int ret;
 -      struct snd_soc_dapm_widget_list *wlist;
 -      int shared, wlistentries;
 -      size_t wlistsize;
 -      const char *name;
  
        if (w->num_kcontrols != 1) {
                dev_err(dapm->dev,
                return -EINVAL;
        }
  
 -      shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
 -                                       &kcontrol);
 -      if (kcontrol) {
 -              wlist = kcontrol->private_data;
 -              wlistentries = wlist->num_widgets + 1;
 -      } else {
 -              wlist = NULL;
 -              wlistentries = 1;
 -      }
 -      wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
 -              wlistentries * sizeof(struct snd_soc_dapm_widget *),
 -      wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
 -      if (wlist == NULL) {
 -              dev_err(dapm->dev,
 -                      "ASoC: can't allocate widget list for %s\n", w->name);
 -              return -ENOMEM;
 -      }
 -      wlist->num_widgets = wlistentries;
 -      wlist->widgets[wlistentries - 1] = w;
 -
 -      if (!kcontrol) {
 -              if (dapm->codec)
 -                      prefix = dapm->codec->name_prefix;
 -              else
 -                      prefix = NULL;
 -
 -              if (shared) {
 -                      name = w->kcontrol_news[0].name;
 -                      prefix_len = 0;
 -              } else {
 -                      name = w->name;
 -                      if (prefix)
 -                              prefix_len = strlen(prefix) + 1;
 -                      else
 -                              prefix_len = 0;
 -              }
 -
 -              /*
 -               * The control will get a prefix from the control creation
 -               * process but we're also using the same prefix for widgets so
 -               * cut the prefix off the front of the widget name.
 -               */
 -              kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
 -                                      name + prefix_len, prefix);
 -              ret = snd_ctl_add(card, kcontrol);
 -              if (ret < 0) {
 -                      dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n",
 -                              w->name, ret);
 -                      kfree(wlist);
 -                      return ret;
 -              }
 +      path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
 +                              list_sink);
 +      if (!path) {
 +              dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
 +              return -EINVAL;
        }
  
 -      kcontrol->private_data = wlist;
 -
 -      w->kcontrols[0] = kcontrol;
 +      ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
 +      if (ret < 0)
 +              return ret;
  
        list_for_each_entry(path, &w->sources, list_sink)
 -              path->kcontrol = kcontrol;
 +              path->kcontrol = w->kcontrols[0];
  
        return 0;
  }
@@@ -707,33 -705,14 +707,33 @@@ static int dapm_new_pga(struct snd_soc_
  }
  
  /* reset 'walked' bit for each dapm path */
 -static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
 +static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
 +                                 struct list_head *sink)
  {
        struct snd_soc_dapm_path *p;
  
 -      list_for_each_entry(p, &dapm->card->paths, list)
 -              p->walked = 0;
 +      list_for_each_entry(p, sink, list_source) {
 +              if (p->walked) {
 +                      p->walked = 0;
 +                      dapm_clear_walk_output(dapm, &p->sink->sinks);
 +              }
 +      }
  }
  
 +static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm,
 +                                struct list_head *source)
 +{
 +      struct snd_soc_dapm_path *p;
 +
 +      list_for_each_entry(p, source, list_sink) {
 +              if (p->walked) {
 +                      p->walked = 0;
 +                      dapm_clear_walk_input(dapm, &p->source->sources);
 +              }
 +      }
 +}
 +
 +
  /* We implement power down on suspend by checking the power state of
   * the ALSA card - when we are suspending the ALSA state for the card
   * is set to D3.
@@@ -1016,17 -995,13 +1016,17 @@@ int snd_soc_dapm_dai_get_connected_widg
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        dapm_reset(card);
  
 -      if (stream == SNDRV_PCM_STREAM_PLAYBACK)
 +      if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                paths = is_connected_output_ep(dai->playback_widget, list);
 -      else
 +              dapm_clear_walk_output(&card->dapm,
 +                                     &dai->playback_widget->sinks);
 +      } else {
                paths = is_connected_input_ep(dai->capture_widget, list);
 +              dapm_clear_walk_input(&card->dapm,
 +                                    &dai->capture_widget->sources);
 +      }
  
        trace_snd_soc_dapm_connected(paths, stream);
 -      dapm_clear_walk(&card->dapm);
        mutex_unlock(&card->dapm_mutex);
  
        return paths;
@@@ -1095,9 -1070,9 +1095,9 @@@ int dapm_clock_event(struct snd_soc_dap
  
  #ifdef CONFIG_HAVE_CLK
        if (SND_SOC_DAPM_EVENT_ON(event)) {
-               return clk_enable(w->clk);
+               return clk_prepare_enable(w->clk);
        } else {
-               clk_disable(w->clk);
+               clk_disable_unprepare(w->clk);
                return 0;
        }
  #endif
@@@ -1129,9 -1104,9 +1129,9 @@@ static int dapm_generic_check_power(str
        DAPM_UPDATE_STAT(w, power_checks);
  
        in = is_connected_input_ep(w, NULL);
 -      dapm_clear_walk(w->dapm);
 +      dapm_clear_walk_input(w->dapm, &w->sources);
        out = is_connected_output_ep(w, NULL);
 -      dapm_clear_walk(w->dapm);
 +      dapm_clear_walk_output(w->dapm, &w->sinks);
        return out != 0 && in != 0;
  }
  
@@@ -1154,7 -1129,7 +1154,7 @@@ static int dapm_adc_check_power(struct 
  
        if (w->active) {
                in = is_connected_input_ep(w, NULL);
 -              dapm_clear_walk(w->dapm);
 +              dapm_clear_walk_input(w->dapm, &w->sources);
                return in != 0;
        } else {
                return dapm_generic_check_power(w);
@@@ -1170,7 -1145,7 +1170,7 @@@ static int dapm_dac_check_power(struct 
  
        if (w->active) {
                out = is_connected_output_ep(w, NULL);
 -              dapm_clear_walk(w->dapm);
 +              dapm_clear_walk_output(w->dapm, &w->sinks);
                return out != 0;
        } else {
                return dapm_generic_check_power(w);
@@@ -1202,6 -1177,8 +1202,6 @@@ static int dapm_supply_check_power(stru
                        return 1;
        }
  
 -      dapm_clear_walk(w->dapm);
 -
        return 0;
  }
  
@@@ -1782,9 -1759,9 +1782,9 @@@ static ssize_t dapm_widget_power_read_f
                return -ENOMEM;
  
        in = is_connected_input_ep(w, NULL);
 -      dapm_clear_walk(w->dapm);
 +      dapm_clear_walk_input(w->dapm, &w->sources);
        out = is_connected_output_ep(w, NULL);
 -      dapm_clear_walk(w->dapm);
 +      dapm_clear_walk_output(w->dapm, &w->sinks);
  
        ret = snprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
                       w->name, w->power ? "On" : "Off",
@@@ -3160,6 -3137,7 +3160,6 @@@ snd_soc_dapm_new_control(struct snd_soc
                break;
        }
  
 -      dapm->n_widgets++;
        w->dapm = dapm;
        w->codec = dapm->codec;
        w->platform = dapm->platform;