Merge remote-tracking branches 'asoc/topic/rt5677', 'asoc/topic/samsung' and 'asoc...
[linux-drm-fsl-dcu.git] / sound / soc / codecs / rt5677.c
index fe5581675983c528055c778a95298e7cef8fc640..31d969ac11920ff419981caee098a234baf4d0f7 100644 (file)
@@ -1060,6 +1060,7 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
        unsigned int asrc5_mask = 0, asrc5_value = 0;
        unsigned int asrc6_mask = 0, asrc6_value = 0;
        unsigned int asrc7_mask = 0, asrc7_value = 0;
+       unsigned int asrc8_mask = 0, asrc8_value = 0;
 
        switch (clk_src) {
        case RT5677_CLK_SEL_SYS:
@@ -1196,10 +1197,108 @@ int rt5677_sel_asrc_clk_src(struct snd_soc_codec *codec,
                regmap_update_bits(rt5677->regmap, RT5677_ASRC_7, asrc7_mask,
                        asrc7_value);
 
+       /* ASRC 8 */
+       if (filter_mask & RT5677_I2S1_SOURCE) {
+               asrc8_mask |= RT5677_I2S1_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S1_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S1_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5677_I2S2_SOURCE) {
+               asrc8_mask |= RT5677_I2S2_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S2_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S2_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5677_I2S3_SOURCE) {
+               asrc8_mask |= RT5677_I2S3_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S3_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S3_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5677_I2S4_SOURCE) {
+               asrc8_mask |= RT5677_I2S4_CLK_SEL_MASK;
+               asrc8_value = (asrc8_value & ~RT5677_I2S4_CLK_SEL_MASK)
+                       | ((clk_src - 1) << RT5677_I2S4_CLK_SEL_SFT);
+       }
+
+       if (asrc8_mask)
+               regmap_update_bits(rt5677->regmap, RT5677_ASRC_8, asrc8_mask,
+                       asrc8_value);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt5677_sel_asrc_clk_src);
 
+static int rt5677_dmic_use_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);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       unsigned int asrc_setting;
+
+       switch (source->shift) {
+       case 11:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >>
+                               RT5677_AD_STO1_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 10:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >>
+                               RT5677_AD_STO2_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 9:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >>
+                               RT5677_AD_STO3_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 8:
+               regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >>
+                       RT5677_AD_STO4_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 7:
+               regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >>
+                       RT5677_AD_MONOL_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       case 6:
+               regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting);
+               asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >>
+                       RT5677_AD_MONOR_CLK_SEL_SFT;
+               if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC &&
+                       asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC)
+                       return 1;
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
@@ -3057,12 +3156,12 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
-       { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
-       { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
-       { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc },
-       { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc },
-       { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
-       { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
+       { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", rt5677_dmic_use_asrc },
+       { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", rt5677_dmic_use_asrc },
+       { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", rt5677_dmic_use_asrc },
+       { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", rt5677_dmic_use_asrc },
+       { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", rt5677_dmic_use_asrc },
+       { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", rt5677_dmic_use_asrc },
        { "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
        { "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
        { "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
@@ -4667,6 +4766,8 @@ static int rt5677_remove(struct snd_soc_codec *codec)
        regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
        if (gpio_is_valid(rt5677->pow_ldo2))
                gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+       if (gpio_is_valid(rt5677->reset_pin))
+               gpio_set_value_cansleep(rt5677->reset_pin, 0);
 
        return 0;
 }
@@ -4682,6 +4783,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
 
                if (gpio_is_valid(rt5677->pow_ldo2))
                        gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
+               if (gpio_is_valid(rt5677->reset_pin))
+                       gpio_set_value_cansleep(rt5677->reset_pin, 0);
        }
 
        return 0;
@@ -4692,10 +4795,13 @@ static int rt5677_resume(struct snd_soc_codec *codec)
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        if (!rt5677->dsp_vad_en) {
-               if (gpio_is_valid(rt5677->pow_ldo2)) {
+               if (gpio_is_valid(rt5677->pow_ldo2))
                        gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
+               if (gpio_is_valid(rt5677->reset_pin))
+                       gpio_set_value_cansleep(rt5677->reset_pin, 1);
+               if (gpio_is_valid(rt5677->pow_ldo2) ||
+                   gpio_is_valid(rt5677->reset_pin))
                        msleep(10);
-               }
 
                regcache_cache_only(rt5677->regmap, false);
                regcache_sync(rt5677->regmap);
@@ -4933,6 +5039,8 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
 
        rt5677->pow_ldo2 = of_get_named_gpio(np,
                                        "realtek,pow-ldo2-gpio", 0);
+       rt5677->reset_pin = of_get_named_gpio(np,
+                                       "realtek,reset-gpio", 0);
 
        /*
         * POW_LDO2 is optional (it may be statically tied on the board).
@@ -4943,6 +5051,9 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
        if (!gpio_is_valid(rt5677->pow_ldo2) &&
                        (rt5677->pow_ldo2 != -ENOENT))
                return rt5677->pow_ldo2;
+       if (!gpio_is_valid(rt5677->reset_pin) &&
+                       (rt5677->reset_pin != -ENOENT))
+               return rt5677->reset_pin;
 
        of_property_read_u8_array(np, "realtek,gpio-config",
                rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
@@ -5044,6 +5155,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                }
        } else {
                rt5677->pow_ldo2 = -EINVAL;
+               rt5677->reset_pin = -EINVAL;
        }
 
        if (gpio_is_valid(rt5677->pow_ldo2)) {
@@ -5055,6 +5167,21 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                                rt5677->pow_ldo2, ret);
                        return ret;
                }
+       }
+
+       if (gpio_is_valid(rt5677->reset_pin)) {
+               ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin,
+                                           GPIOF_OUT_INIT_HIGH,
+                                           "RT5677 RESET");
+               if (ret < 0) {
+                       dev_err(&i2c->dev, "Failed to request RESET %d: %d\n",
+                               rt5677->reset_pin, ret);
+                       return ret;
+               }
+       }
+
+       if (gpio_is_valid(rt5677->pow_ldo2) ||
+           gpio_is_valid(rt5677->reset_pin)) {
                /* Wait a while until I2C bus becomes available. The datasheet
                 * does not specify the exact we should wait but startup
                 * sequence mentiones at least a few milliseconds.