Merge remote-tracking branch 'asoc/fix/rt5670' into asoc-linus
authorMark Brown <broonie@kernel.org>
Wed, 4 Mar 2015 20:42:42 +0000 (20:42 +0000)
committerMark Brown <broonie@kernel.org>
Wed, 4 Mar 2015 20:42:42 +0000 (20:42 +0000)
1  2 
sound/soc/codecs/rt5670.c

index e1a4a45c57e229b12dcd174ac8453f8772b6e3b1,b651bc06cfdf599e48b0c4695ab545b19e664052..fd102613d20d8747c7554f5a3882c027fd0024c8
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/pm.h>
 +#include <linux/pm_runtime.h>
  #include <linux/i2c.h>
  #include <linux/platform_device.h>
  #include <linux/acpi.h>
  #include <linux/spi/spi.h>
 +#include <linux/dmi.h>
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
@@@ -225,7 -223,6 +225,6 @@@ static bool rt5670_volatile_register(st
        case RT5670_ADC_EQ_CTRL1:
        case RT5670_EQ_CTRL1:
        case RT5670_ALC_CTRL_1:
-       case RT5670_IRQ_CTRL1:
        case RT5670_IRQ_CTRL2:
        case RT5670_INT_IRQ_ST:
        case RT5670_IL_CMD:
@@@ -500,7 -497,7 +499,7 @@@ static const struct snd_kcontrol_new rt
  static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
  {
 -      struct snd_soc_codec *codec = w->codec;
 +      struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
  
  static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
  {
 +      struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
  
 -      val = snd_soc_read(source->codec, RT5670_GLB_CLK);
 +      val = snd_soc_read(codec, RT5670_GLB_CLK);
        val &= RT5670_SCLK_SRC_MASK;
        if (val == RT5670_SCLK_SRC_PLL1)
                return 1;
  static int is_using_asrc(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
  {
 +      struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg, shift, val;
  
        switch (source->shift) {
                return 0;
        }
  
 -      val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
 +      val = (snd_soc_read(codec, reg) >> shift) & 0xf;
        switch (val) {
        case 1:
        case 2:
@@@ -592,89 -587,6 +591,89 @@@ static int can_use_asrc(struct snd_soc_
        return 0;
  }
  
 +
 +/**
 + * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters
 + * @codec: SoC audio codec device.
 + * @filter_mask: mask of filters.
 + * @clk_src: clock source
 + *
 + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can
 + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
 + * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
 + * ASRC function will track i2s clock and generate a corresponding system clock
 + * for codec. This function provides an API to select the clock source for a
 + * set of filters specified by the mask. And the codec driver will turn on ASRC
 + * for these filters if ASRC is selected as their clock source.
 + */
 +int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
 +                          unsigned int filter_mask, unsigned int clk_src)
 +{
 +      unsigned int asrc2_mask = 0, asrc2_value = 0;
 +      unsigned int asrc3_mask = 0, asrc3_value = 0;
 +
 +      if (clk_src > RT5670_CLK_SEL_SYS3)
 +              return -EINVAL;
 +
 +      if (filter_mask & RT5670_DA_STEREO_FILTER) {
 +              asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK;
 +              asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_DA_STO_CLK_SEL_SFT);
 +      }
 +
 +      if (filter_mask & RT5670_DA_MONO_L_FILTER) {
 +              asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK;
 +              asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_DA_MONOL_CLK_SEL_SFT);
 +      }
 +
 +      if (filter_mask & RT5670_DA_MONO_R_FILTER) {
 +              asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK;
 +              asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_DA_MONOR_CLK_SEL_SFT);
 +      }
 +
 +      if (filter_mask & RT5670_AD_STEREO_FILTER) {
 +              asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK;
 +              asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_AD_STO1_CLK_SEL_SFT);
 +      }
 +
 +      if (filter_mask & RT5670_AD_MONO_L_FILTER) {
 +              asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK;
 +              asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_AD_MONOL_CLK_SEL_SFT);
 +      }
 +
 +      if (filter_mask & RT5670_AD_MONO_R_FILTER)  {
 +              asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK;
 +              asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_AD_MONOR_CLK_SEL_SFT);
 +      }
 +
 +      if (filter_mask & RT5670_UP_RATE_FILTER) {
 +              asrc3_mask |= RT5670_UP_CLK_SEL_MASK;
 +              asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_UP_CLK_SEL_SFT);
 +      }
 +
 +      if (filter_mask & RT5670_DOWN_RATE_FILTER) {
 +              asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK;
 +              asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK)
 +                              | (clk_src <<  RT5670_DOWN_CLK_SEL_SFT);
 +      }
 +
 +      if (asrc2_mask)
 +              snd_soc_update_bits(codec, RT5670_ASRC_2,
 +                                  asrc2_mask, asrc2_value);
 +
 +      if (asrc3_mask)
 +              snd_soc_update_bits(codec, RT5670_ASRC_3,
 +                                  asrc3_mask, asrc3_value);
 +      return 0;
 +}
 +EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src);
 +
  /* Digital Mixer */
  static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
@@@ -1233,7 -1145,7 +1232,7 @@@ static const struct snd_kcontrol_new rt
  static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
  {
 -      struct snd_soc_codec *codec = w->codec;
 +      struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
  
        switch (event) {
  static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
  {
 -      struct snd_soc_codec *codec = w->codec;
 +      struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
  
        switch (event) {
  static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
  {
 -      struct snd_soc_codec *codec = w->codec;
 +      struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
  
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
  static int rt5670_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
  {
 -      struct snd_soc_codec *codec = w->codec;
 +      struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
  
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@@ -2275,13 -2187,6 +2274,13 @@@ static int rt5670_set_dai_sysclk(struc
        if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src)
                return 0;
  
 +      if (rt5670->pdata.jd_mode) {
 +              if (clk_id == RT5670_SCLK_S_PLL1)
 +                      snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
 +              else
 +                      snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
 +              snd_soc_dapm_sync(&codec->dapm);
 +      }
        switch (clk_id) {
        case RT5670_SCLK_S_MCLK:
                reg_val |= RT5670_SCLK_SRC_MCLK;
@@@ -2616,7 -2521,6 +2615,7 @@@ static struct snd_soc_codec_driver soc_
  static const struct regmap_config rt5670_regmap = {
        .reg_bits = 8,
        .val_bits = 16,
 +      .use_single_rw = true,
        .max_register = RT5670_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5670_ranges) *
                                               RT5670_PR_SPACING),
        .volatile_reg = rt5670_volatile_register,
@@@ -2644,17 -2548,6 +2643,17 @@@ static struct acpi_device_id rt5670_acp
  MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
  #endif
  
 +static const struct dmi_system_id dmi_platform_intel_braswell[] = {
 +      {
 +              .ident = "Intel Braswell",
 +              .matches = {
 +                      DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
 +              },
 +      },
 +      {}
 +};
 +
  static int rt5670_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
  {
        if (pdata)
                rt5670->pdata = *pdata;
  
 +      if (dmi_check_system(dmi_platform_intel_braswell)) {
 +              rt5670->pdata.dmic_en = true;
 +              rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
 +              rt5670->pdata.jd_mode = 1;
 +      }
 +
        rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
        if (IS_ERR(rt5670->regmap)) {
                ret = PTR_ERR(rt5670->regmap);
  
        regmap_write(rt5670->regmap, RT5670_RESET, 0);
  
+       regmap_read(rt5670->regmap, RT5670_VENDOR_ID, &val);
+       if (val >= 4)
+               regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0980);
+       else
+               regmap_write(rt5670->regmap, RT5670_GPIO_CTRL3, 0x0d00);
        ret = regmap_register_patch(rt5670->regmap, init_list,
                                    ARRAY_SIZE(init_list));
        if (ret != 0)
        }
  
        if (rt5670->pdata.jd_mode) {
 +              regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK,
 +                                 RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK);
 +              rt5670->sysclk = 0;
 +              rt5670->sysclk_src = RT5670_SCLK_S_RCCLK;
                regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
                                   RT5670_PWR_MB, RT5670_PWR_MB);
                regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2,
  
        }
  
 +      pm_runtime_enable(&i2c->dev);
 +      pm_request_idle(&i2c->dev);
 +
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670,
                        rt5670_dai, ARRAY_SIZE(rt5670_dai));
        if (ret < 0)
                goto err;
  
 +      pm_runtime_put(&i2c->dev);
 +
        return 0;
  err:
 +      pm_runtime_disable(&i2c->dev);
 +
        return ret;
  }
  
  static int rt5670_i2c_remove(struct i2c_client *i2c)
  {
 +      pm_runtime_disable(&i2c->dev);
        snd_soc_unregister_codec(&i2c->dev);
  
        return 0;