X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=blobdiff_plain;f=sound%2Fsoc%2Fcodecs%2Frt5651.c;h=7de7850879588495e7696944dfc39d5bb9788c7d;hp=1d4031818966638c7ad994ffd18bf294cc7c79bd;hb=802ee8a48927eef439af92973a0f17ed3590950d;hpb=310b7cec8ea32dcd4e9978423717ce78dd89d45d diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 1d4031818966..7de785087958 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -26,6 +26,7 @@ #include #include +#include #include "rl6231.h" #include "rt5651.h" @@ -285,6 +286,39 @@ static bool rt5651_readable_register(struct device *dev, unsigned int reg) } } +static int rt5651_asrc_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = rt5651->asrc_en; + + return 0; +} + +static int rt5651_asrc_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + + rt5651->asrc_en = ucontrol->value.integer.value[0]; + if (rt5651->asrc_en) { + snd_soc_write(codec, 0x80, 0x4000); + snd_soc_write(codec, 0x81, 0x0302); + snd_soc_write(codec, 0x82, 0x0800); + snd_soc_write(codec, 0x73, 0x1004); + snd_soc_write(codec, 0x83, 0x1000); + snd_soc_write(codec, 0x84, 0x7000); + snd_soc_update_bits(codec, 0x64, 0x0200, 0x0200); + } else { + snd_soc_write(codec, 0x83, 0x0); + snd_soc_write(codec, 0x84, 0x0); + } + return 0; +} + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); @@ -312,6 +346,11 @@ static SOC_ENUM_SINGLE_DECL(rt5651_if2_dac_enum, RT5651_DIG_INF_DATA, static SOC_ENUM_SINGLE_DECL(rt5651_if2_adc_enum, RT5651_DIG_INF_DATA, RT5651_IF2_ADC_SEL_SFT, rt5651_data_select); +static const char * const rt5651_asrc_mode[] = {"Disable", "Enable"}; + +static const SOC_ENUM_SINGLE_DECL(rt5651_asrc_enum, 0, 0, + rt5651_asrc_mode); + static const struct snd_kcontrol_new rt5651_snd_controls[] = { /* Headphone Output Volume */ SOC_DOUBLE_TLV("HP Playback Volume", RT5651_HP_VOL, @@ -352,6 +391,9 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = { RT5651_ADC_L_BST_SFT, RT5651_ADC_R_BST_SFT, 3, 0, adc_bst_tlv), + /* RT5651 ASRC Switch */ + SOC_ENUM_EXT("RT5651 ASRC Switch", rt5651_asrc_enum, + rt5651_asrc_get, rt5651_asrc_put), /* ASRC */ SOC_SINGLE("IF1 ASRC Switch", RT5651_PLL_MODE_1, RT5651_STO1_T_SFT, 1, 0), @@ -920,8 +962,8 @@ static const struct snd_soc_dapm_widget rt5651_dapm_widgets[] = { /* micbias */ SND_SOC_DAPM_SUPPLY("LDO", RT5651_PWR_ANLG1, RT5651_PWR_LDO_BIT, 0, NULL, 0), - SND_SOC_DAPM_MICBIAS("micbias1", RT5651_PWR_ANLG2, - RT5651_PWR_MB1_BIT, 0), + SND_SOC_DAPM_SUPPLY("micbias1", RT5651_PWR_ANLG2, + RT5651_PWR_MB1_BIT, 0, NULL, 0), /* Input Lines */ SND_SOC_DAPM_INPUT("MIC1"), SND_SOC_DAPM_INPUT("MIC2"), @@ -1144,6 +1186,9 @@ static const struct snd_soc_dapm_route rt5651_dapm_routes[] = { {"IN1P", NULL, "LDO"}, {"IN2P", NULL, "LDO"}, {"IN3P", NULL, "LDO"}, + {"BST1", NULL, "micbias1"}, + {"BST2", NULL, "micbias1"}, + {"BST3", NULL, "micbias1"}, {"IN1P", NULL, "MIC1"}, {"IN2P", NULL, "MIC2"}, @@ -1569,9 +1614,13 @@ static int rt5651_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, static int rt5651_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_PREPARE: if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { + if (!IS_ERR(rt5651->mclk)) + clk_prepare_enable(rt5651->mclk); snd_soc_update_bits(codec, RT5651_PWR_ANLG1, RT5651_PWR_VREF1 | RT5651_PWR_MB | RT5651_PWR_BG | RT5651_PWR_VREF2, @@ -1599,6 +1648,10 @@ static int rt5651_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, RT5651_PWR_MIXER, 0x0000); snd_soc_write(codec, RT5651_PWR_ANLG1, 0x0000); snd_soc_write(codec, RT5651_PWR_ANLG2, 0x0000); + if (SND_SOC_BIAS_PREPARE == + snd_soc_codec_get_bias_level(codec)) + if (!IS_ERR(rt5651->mclk)) + clk_disable_unprepare(rt5651->mclk); break; default: @@ -1613,6 +1666,9 @@ static int rt5651_probe(struct snd_soc_codec *codec) struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec); rt5651->codec = codec; + rt5651->mclk = devm_clk_get(codec->dev, "mclk"); + if (PTR_ERR(rt5651->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; snd_soc_update_bits(codec, RT5651_PWR_ANLG1, RT5651_PWR_VREF1 | RT5651_PWR_MB | @@ -1803,9 +1859,15 @@ static int rt5651_i2c_remove(struct i2c_client *i2c) return 0; } +static const struct of_device_id rt5651_of_match[] = { + { .compatible = "realtek,rt5651", }, + { } +}; + static struct i2c_driver rt5651_i2c_driver = { .driver = { .name = "rt5651", + .of_match_table = rt5651_of_match, }, .probe = rt5651_i2c_probe, .remove = rt5651_i2c_remove,