Merge remote-tracking branches 'asoc/fix/rt5659', 'asoc/fix/sigmadsp', 'asoc/fix...
authorMark Brown <broonie@kernel.org>
Wed, 10 Feb 2016 19:23:09 +0000 (19:23 +0000)
committerMark Brown <broonie@kernel.org>
Wed, 10 Feb 2016 19:23:09 +0000 (19:23 +0000)
1  2  3  4  5  6 
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8960.c

@@@@@@@ -360,13 -360,15 -360,13 -360,13 -360,15 -360,15 +360,13 @@@@@@@ static int wm5110_hp_ev(struct snd_soc_
      
      static int wm5110_clear_pga_volume(struct arizona *arizona, int output)
      {
 -  --  struct reg_sequence clear_pga = {
 -  --          ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80
 -  --  };
 +  ++  unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4;
        int ret;
      
 -  --  ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1);
 +  ++  ret = regmap_write(arizona->regmap, reg, 0x80);
        if (ret)
                dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n",
 -  --                  clear_pga.reg, ret);
 +  ++                  reg, ret);
      
        return ret;
      }
@@@@@@@ -437,17 -439,18 -437,17 -437,17 -439,18 -439,18 +437,17 @@@@@@@ static int wm5110_in_pga_get(struct snd
      {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 -  --  struct snd_soc_card *card = dapm->card;
        int ret;
      
        /*
         * PGA Volume is also used as part of the enable sequence, so
         * usage of it should be avoided whilst that is running.
         */
 -  --  mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 +  ++  snd_soc_dapm_mutex_lock(dapm);
      
        ret = snd_soc_get_volsw_range(kcontrol, ucontrol);
      
 -  --  mutex_unlock(&card->dapm_mutex);
 +  ++  snd_soc_dapm_mutex_unlock(dapm);
      
        return ret;
      }
@@@@@@@ -457,17 -460,18 -457,17 -457,17 -460,18 -460,18 +457,17 @@@@@@@ static int wm5110_in_pga_put(struct snd
      {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
 -  --  struct snd_soc_card *card = dapm->card;
        int ret;
      
        /*
         * PGA Volume is also used as part of the enable sequence, so
         * usage of it should be avoided whilst that is running.
         */
 -  --  mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 +  ++  snd_soc_dapm_mutex_lock(dapm);
      
        ret = snd_soc_put_volsw_range(kcontrol, ucontrol);
      
 -  --  mutex_unlock(&card->dapm_mutex);
 +  ++  snd_soc_dapm_mutex_unlock(dapm);
      
        return ret;
      }
@@@@@@@ -571,33 -575,6 -571,33 -571,33 -575,33 -575,33 +571,33 @@@@@@@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10
        SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
        SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
      
 +    #define WM5110_RXANC_INPUT_ROUTES(widget, name) \
 +      { widget, NULL, name " NG Mux" }, \
 +      { name " NG Internal", NULL, "RXANC NG Clock" }, \
 +      { name " NG Internal", NULL, name " Channel" }, \
 +      { name " NG External", NULL, "RXANC NG External Clock" }, \
 +      { name " NG External", NULL, name " Channel" }, \
 +      { name " NG Mux", "None", name " Channel" }, \
 +      { name " NG Mux", "Internal", name " NG Internal" }, \
 +      { name " NG Mux", "External", name " NG External" }, \
 +      { name " Channel", "Left", name " Left Input" }, \
 +      { name " Channel", "Combine", name " Left Input" }, \
 +      { name " Channel", "Right", name " Right Input" }, \
 +      { name " Channel", "Combine", name " Right Input" }, \
 +      { name " Left Input", "IN1", "IN1L PGA" }, \
 +      { name " Right Input", "IN1", "IN1R PGA" }, \
 +      { name " Left Input", "IN2", "IN2L PGA" }, \
 +      { name " Right Input", "IN2", "IN2R PGA" }, \
 +      { name " Left Input", "IN3", "IN3L PGA" }, \
 +      { name " Right Input", "IN3", "IN3R PGA" }, \
 +      { name " Left Input", "IN4", "IN4L PGA" }, \
 +      { name " Right Input", "IN4", "IN4R PGA" }
 +    
 +    #define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \
 +      { widget, NULL, name " ANC Source" }, \
 +      { name " ANC Source", "RXANCL", "RXANCL" }, \
 +      { name " ANC Source", "RXANCR", "RXANCR" }
 +    
      static const struct snd_kcontrol_new wm5110_snd_controls[] = {
      SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
      SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
@@@@@@@ -662,15 -639,6 -662,15 -662,15 -666,15 -666,15 +662,15 @@@@@@@ SOC_SINGLE_TLV("IN4R Digital Volume", A
      SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
      SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
      
 +    SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START,
 +            ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1),
 +    SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1),
 +    SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START,
 +            ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1),
 +    SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1),
 +    SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START,
 +            ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1),
 +    
      ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
      ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
      ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
@@@@@@@ -1027,31 -995,6 -1027,31 -1027,31 -1031,31 -1031,31 +1027,31 @@@@@@@ static const struct soc_enum wm5110_aec
      static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
        SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
      
 +    static const struct snd_kcontrol_new wm5110_anc_input_mux[] = {
 +      SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]),
 +      SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]),
 +      SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]),
 +      SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]),
 +    };
 +    
 +    static const struct snd_kcontrol_new wm5110_anc_ng_mux =
 +      SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum);
 +    
 +    static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
 +      SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]),
 +      SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]),
 +      SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]),
 +      SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]),
 +      SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]),
 +      SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]),
 +      SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]),
 +      SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]),
 +      SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]),
 +      SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]),
 +      SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]),
 +      SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]),
 +    };
 +    
      static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
      SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
                    0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
@@@@@@@ -1242,65 -1185,6 -1242,65 -1242,65 -1246,65 -1246,65 +1242,65 @@@@@@@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZON
                       ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
                       &wm5110_aec_loopback_mux),
      
 +    SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM,
 +                 ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
 +                 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 +    SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
 +    SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
 +    
 +    SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM,
 +                 ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
 +                 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 +    SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
 +    SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
 +    
 +    SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0,
 +               &wm5110_anc_input_mux[0]),
 +    SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0,
 +               &wm5110_anc_input_mux[0]),
 +    SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0,
 +               &wm5110_anc_input_mux[1]),
 +    SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
 +    SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0,
 +               &wm5110_anc_input_mux[2]),
 +    SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0,
 +               &wm5110_anc_input_mux[2]),
 +    SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0,
 +               &wm5110_anc_input_mux[3]),
 +    SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
 +    
 +    SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT,
 +                 0, NULL, 0, arizona_anc_ev,
 +                 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 +    SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT,
 +                 0, NULL, 0, arizona_anc_ev,
 +                 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 +    
 +    SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[0]),
 +    SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[1]),
 +    SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[2]),
 +    SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[3]),
 +    SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[4]),
 +    SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[5]),
 +    SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[6]),
 +    SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[7]),
 +    SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[8]),
 +    SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[9]),
 +    SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[10]),
 +    SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0,
 +               &wm5110_output_anc_src[11]),
 +    
      SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
                     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
      SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@@@@@@ -1806,9 -1690,6 -1806,9 -1806,9 -1810,9 -1810,9 +1806,9 @@@@@@@ static const struct snd_soc_dapm_route 
        { "Slim2 Capture", NULL, "SYSCLK" },
        { "Slim3 Capture", NULL, "SYSCLK" },
      
 +      { "Voice Control DSP", NULL, "DSP3" },
 +      { "Voice Control DSP", NULL, "SYSCLK" },
 +    
        { "IN1L PGA", NULL, "IN1L" },
        { "IN1R PGA", NULL, "IN1R" },
      
        { "SPKDAT2L", NULL, "OUT6L" },
        { "SPKDAT2R", NULL, "OUT6R" },
      
 +      WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"),
 +      WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"),
 +    
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"),
 +      WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"),
 +    
        { "MICSUPP", NULL, "SYSCLK" },
      
        { "DRC1 Signal Activity", NULL, "DRC1L" },
@@@@@@@ -2131,65 -1996,12 -2131,65 -2131,65 -2135,52 -2135,52 +2131,65 @@@@@@@ static struct snd_soc_dai_driver wm5110
                 },
                .ops = &arizona_simple_dai_ops,
        },
 +      {
 +              .name = "wm5110-cpu-voicectrl",
 +              .capture = {
 +                      .stream_name = "Voice Control CPU",
 +                      .channels_min = 1,
 +                      .channels_max = 1,
 +                      .rates = WM5110_RATES,
 +                      .formats = WM5110_FORMATS,
 +              },
 +              .compress_new = snd_soc_new_compress,
 +      },
 +      {
 +              .name = "wm5110-dsp-voicectrl",
 +              .capture = {
 +                      .stream_name = "Voice Control DSP",
 +                      .channels_min = 1,
 +                      .channels_max = 1,
 +                      .rates = WM5110_RATES,
 +                      .formats = WM5110_FORMATS,
 +              },
 +      },
      };
      
 +    static int wm5110_open(struct snd_compr_stream *stream)
 +    {
 +      struct snd_soc_pcm_runtime *rtd = stream->private_data;
 +      struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
 +      struct arizona *arizona = priv->core.arizona;
 +      int n_adsp;
 +    
 +      if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
 +              n_adsp = 2;
 +      } else {
 +              dev_err(arizona->dev,
 +                      "No suitable compressed stream for DAI '%s'\n",
 +                      rtd->codec_dai->name);
 +              return -EINVAL;
 +      }
 +    
 +      return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
 +    }
 +    
 +  ++static irqreturn_t wm5110_adsp2_irq(int irq, void *data)
 +  ++{
 +  ++  struct wm5110_priv *florida = data;
 +  ++  int ret;
 +  ++
 +  ++  ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]);
 +  ++  if (ret == -ENODEV)
 +  ++          return IRQ_NONE;
 +  ++
 +  ++  return IRQ_HANDLED;
 +  ++}
 +  ++
      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);
 +  ++  struct arizona *arizona = priv->core.arizona;
        int i, ret;
      
        priv->core.arizona->dapm = dapm;
        arizona_init_gpio(codec);
        arizona_init_mono(codec);
      
 +  ++  ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1,
 +  ++                            "ADSP2 Compressed IRQ", wm5110_adsp2_irq,
 +  ++                            priv);
 +  ++  if (ret != 0) {
 +  ++          dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret);
 +  ++          return ret;
 +  ++  }
 +  ++
        for (i = 0; i < WM5110_NUM_ADSP; ++i) {
                ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
                if (ret)
@@@@@@@ -2226,15 -2030,12 -2226,15 -2226,15 -2209,12 -2209,12 +2226,15 @@@@@@@ err_adsp2_codec_probe
        for (--i; i >= 0; --i)
                wm_adsp2_codec_remove(&priv->core.adsp[i], codec);
      
 +  ++  arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
 +  ++
        return ret;
      }
      
      static int wm5110_codec_remove(struct snd_soc_codec *codec)
      {
        struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec);
 +  ++  struct arizona *arizona = priv->core.arizona;
        int i;
      
        for (i = 0; i < WM5110_NUM_ADSP; ++i)
      
        priv->core.arizona->dapm = NULL;
      
 +  ++  arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv);
 +  ++
        return 0;
      }
      
@@@@@@@ -2289,20 -2088,6 -2289,20 -2289,20 -2267,18 -2267,18 +2289,20 @@@@@@@ static struct snd_soc_codec_driver soc_
        .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
      };
      
 +    static struct snd_compr_ops wm5110_compr_ops = {
 +      .open = wm5110_open,
 +      .free = wm_adsp_compr_free,
 +      .set_params = wm_adsp_compr_set_params,
 +      .get_caps = wm_adsp_compr_get_caps,
 +      .trigger = wm_adsp_compr_trigger,
 +  ++  .pointer = wm_adsp_compr_pointer,
 +  ++  .copy = wm_adsp_compr_copy,
 +    };
 +    
 +    static struct snd_soc_platform_driver wm5110_compr_platform = {
 +      .compr_ops = &wm5110_compr_ops,
 +    };
 +    
      static int wm5110_probe(struct platform_device *pdev)
      {
        struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
        pm_runtime_enable(&pdev->dev);
        pm_runtime_idle(&pdev->dev);
      
 -      return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
 +      ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
 +      if (ret < 0) {
 +              dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
 +              goto error;
 +      }
 +    
 +      ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
                                      wm5110_dai, ARRAY_SIZE(wm5110_dai));
 +      if (ret < 0) {
 +              dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
 +              snd_soc_unregister_platform(&pdev->dev);
 +      }
 +    
 +    error:
 +      return ret;
      }
      
      static int wm5110_remove(struct platform_device *pdev)
      {
++++ +  snd_soc_unregister_platform(&pdev->dev);
        snd_soc_unregister_codec(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
      
@@@@@@@ -147,13 -147,6 -147,13 -147,13 -147,6 -147,6 +147,13 @@@@@@@ static const char *wm8960_3d_upper_cuto
      static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"};
      static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
      static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
 +  ++static const char *wm8960_adc_data_output_sel[] = {
 +  ++  "Left Data = Left ADC;  Right Data = Right ADC",
 +  ++  "Left Data = Left ADC;  Right Data = Left ADC",
 +  ++  "Left Data = Right ADC; Right Data = Right ADC",
 +  ++  "Left Data = Right ADC; Right Data = Left ADC",
 +  ++};
 +  ++static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
      
      static const struct soc_enum wm8960_enum[] = {
        SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
        SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff),
        SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc),
        SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
 +  ++  SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel),
 +  ++  SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix),
      };
      
      static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
@@@@@@@ -238,15 -229,15 -238,15 -238,15 -229,15 -229,15 +238,15 @@@@@@@ SOC_DOUBLE_R_TLV("Capture Volume", WM89
      SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
        6, 1, 0),
      SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
 -      7, 1, 0),
 +      7, 1, 1),
      
----- SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
+++++ SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
               WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv),
----- SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
+++++ SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
               WM8960_INBMIX1, 1, 7, 0, lineinboost_tlv),
----- SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
+++++ SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
               WM8960_INBMIX2, 4, 7, 0, lineinboost_tlv),
----- SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
+++++ SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
               WM8960_INBMIX2, 1, 7, 0, lineinboost_tlv),
      SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT1 Volume",
                WM8960_RINPATH, 4, 3, 0, micboost_tlv),
@@@@@@@ -304,9 -295,6 -304,9 -304,9 -295,6 -295,6 +304,9 @@@@@@@ SOC_SINGLE_TLV("Right Output Mixer Boos
               WM8960_BYPASS2, 4, 7, 1, bypass_tlv),
      SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume",
               WM8960_ROUTMIX, 4, 7, 1, bypass_tlv),
 +  ++
 +  ++SOC_ENUM("ADC Data Output Select", wm8960_enum[6]),
 +  ++SOC_ENUM("DAC Mono Mix", wm8960_enum[7]),
      };
      
      static const struct snd_kcontrol_new wm8960_lin_boost[] = {
@@@@@@@ -413,8 -401,8 -413,8 -413,8 -401,8 -401,8 +413,8 @@@@@@@ static const struct snd_soc_dapm_route 
        { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
        { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },
      
 -  --  { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", },
 -  --  { "Left Input Mixer", NULL, "LINPUT1", },  /* Really Boost Switch */
 +  ++  { "Left Input Mixer", "Boost Switch", "Left Boost Mixer" },
 +  ++  { "Left Input Mixer", "Boost Switch", "LINPUT1" },  /* Really Boost Switch */
        { "Left Input Mixer", NULL, "LINPUT2" },
        { "Left Input Mixer", NULL, "LINPUT3" },
      
        { "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" },
        { "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" },
      
 -  --  { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
 -  --  { "Right Input Mixer", NULL, "RINPUT1", },  /* Really Boost Switch */
 +  ++  { "Right Input Mixer", "Boost Switch", "Right Boost Mixer" },
 +  ++  { "Right Input Mixer", "Boost Switch", "RINPUT1" },  /* Really Boost Switch */
        { "Right Input Mixer", NULL, "RINPUT2" },
        { "Right Input Mixer", NULL, "RINPUT3" },
      
        { "Right ADC", NULL, "Right Input Mixer" },
      
        { "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
 -  --  { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer",
 +  ++  { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" },
        { "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
      
        { "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" },
 -  --  { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
 +  ++  { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" },
        { "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
      
        { "LOUT1 PGA", NULL, "Left Output Mixer" },
@@@@@@@ -643,29 -631,29 -643,29 -643,29 -631,29 -631,31 +643,31 @@@@@@@ static int wm8960_configure_clocking(st
                return -EINVAL;
        }
      
-----   /* check if the sysclk frequency is available. */
-----   for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
-----           if (sysclk_divs[i] == -1)
-----                   continue;
-----           sysclk = freq_out / sysclk_divs[i];
-----           for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
-----                   if (sysclk == dac_divs[j] * lrclk) {
+++++   if (wm8960->clk_id != WM8960_SYSCLK_PLL) {
+++++           /* check if the sysclk frequency is available. */
+++++           for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
+++++                   if (sysclk_divs[i] == -1)
+++++                           continue;
+++++                   sysclk = freq_out / sysclk_divs[i];
+++++                   for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
+++++                           if (sysclk != dac_divs[j] * lrclk)
+++++                                   continue;
                                for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
                                        if (sysclk == bclk * bclk_divs[k] / 10)
                                                break;
                                if (k != ARRAY_SIZE(bclk_divs))
                                        break;
                        }
+++++                   if (j != ARRAY_SIZE(dac_divs))
+++++                           break;
                }
-----           if (j != ARRAY_SIZE(dac_divs))
-----                   break;
-----   }
      
-----   if (i != ARRAY_SIZE(sysclk_divs)) {
-----           goto configure_clock;
-----   } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
-----           dev_err(codec->dev, "failed to configure clock\n");
-----           return -EINVAL;
+++++           if (i != ARRAY_SIZE(sysclk_divs)) {
+++++                   goto configure_clock;
+++++           } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
+++++                   dev_err(codec->dev, "failed to configure clock\n");
+++++                   return -EINVAL;
+++++           }
        }
        /* get a available pll out frequency and set pll */
        for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {