#include <sound/initval.h>
#include <sound/tlv.h>
+#include <linux/clk.h>
#include "rl6231.h"
#include "rt5651.h"
}
}
+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);
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,
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),
/* 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"),
{"IN1P", NULL, "LDO"},
{"IN2P", NULL, "LDO"},
{"IN3P", NULL, "LDO"},
+ {"BST1", NULL, "micbias1"},
+ {"BST2", NULL, "micbias1"},
+ {"BST3", NULL, "micbias1"},
{"IN1P", NULL, "MIC1"},
{"IN2P", NULL, "MIC2"},
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,
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:
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 |
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,