diff options
Diffstat (limited to 'sound/soc/codecs')
52 files changed, 8455 insertions, 281 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1cd6ab344d67..c67667bb970f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -92,6 +92,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C + select SND_SOC_NAU8810 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_HDMI_CODEC select SND_SOC_PCM1681 if I2C @@ -112,6 +113,8 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5645 if I2C select SND_SOC_RT5651 if I2C select SND_SOC_RT5659 if I2C + select SND_SOC_RT5660 if I2C + select SND_SOC_RT5663 if I2C select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C && SPI_MASTER select SND_SOC_SGTL5000 if I2C @@ -645,6 +648,8 @@ config SND_SOC_RL6231 default y if SND_SOC_RT5645=y default y if SND_SOC_RT5651=y default y if SND_SOC_RT5659=y + default y if SND_SOC_RT5660=y + default y if SND_SOC_RT5663=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y default m if SND_SOC_RT5514=m @@ -653,6 +658,8 @@ config SND_SOC_RL6231 default m if SND_SOC_RT5645=m default m if SND_SOC_RT5651=m default m if SND_SOC_RT5659=m + default m if SND_SOC_RT5660=m + default m if SND_SOC_RT5663=m default m if SND_SOC_RT5670=m default m if SND_SOC_RT5677=m @@ -665,6 +672,7 @@ config SND_SOC_RL6347A config SND_SOC_RT286 tristate + select SND_SOC_RT5663 depends on I2C config SND_SOC_RT298 @@ -697,6 +705,12 @@ config SND_SOC_RT5651 config SND_SOC_RT5659 tristate +config SND_SOC_RT5660 + tristate + +config SND_SOC_RT5663 + tristate + config SND_SOC_RT5670 tristate @@ -1064,6 +1078,10 @@ config SND_SOC_MC13783 config SND_SOC_ML26124 tristate +config SND_SOC_NAU8810 + tristate "Nuvoton Technology Corporation NAU88C10 CODEC" + depends on I2C + config SND_SOC_NAU8825 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 58036af2c7d9..958cd4912fbc 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -86,6 +86,7 @@ snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o +snd-soc-nau8810-objs := nau8810.o snd-soc-nau8825-objs := nau8825.o snd-soc-hdmi-codec-objs := hdmi-codec.o snd-soc-pcm1681-objs := pcm1681.o @@ -112,6 +113,8 @@ snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o snd-soc-rt5659-objs := rt5659.o +snd-soc-rt5660-objs := rt5660.o +snd-soc-rt5663-objs := rt5663.o snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o snd-soc-rt5677-spi-objs := rt5677-spi.o @@ -307,6 +310,7 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o +obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o @@ -333,6 +337,8 @@ obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o +obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o +obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 3056487ed5a9..935ff7cb71c5 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2408,28 +2408,28 @@ static void ab8500_codec_of_probe(struct device *dev, struct device_node *np, { u32 value; - if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL)) + if (of_property_read_bool(np, "stericsson,amic1-type-single-ended")) codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED; else codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL; - if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL)) + if (of_property_read_bool(np, "stericsson,amic2-type-single-ended")) codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED; else codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL; /* Has a non-standard Vamic been requested? */ - if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL)) + if (of_property_read_bool(np, "stericsson,amic1a-bias-vamic2")) codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2; else codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1; - if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL)) + if (of_property_read_bool(np, "stericsson,amic1b-bias-vamic2")) codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2; else codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1; - if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL)) + if (of_property_read_bool(np, "stericsson,amic2-bias-vamic1")) codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1; else codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2; diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index bdca8793e630..1a9d233c94d0 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -163,7 +163,10 @@ static struct snd_soc_dai_driver ak4104_dai = { .stream_name = "Playback", .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_192000, + .rates = SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ecfdbfcae366..846ca079845f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -109,7 +109,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, break; } - return 0; + return arizona_out_ev(w, kcontrol, event); } static irqreturn_t arizona_thermal_warn(int irq, void *data) @@ -159,12 +159,14 @@ static irqreturn_t arizona_thermal_shutdown(int irq, void *data) static const struct snd_soc_dapm_widget arizona_spkl = SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM, ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD); static const struct snd_soc_dapm_widget arizona_spkr = SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM, ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev, - SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU); + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD); int arizona_init_spk(struct snd_soc_codec *codec) { @@ -864,6 +866,7 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -877,6 +880,18 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, priv->out_up_pending++; priv->out_up_delay += 17; break; + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: + priv->out_up_pending++; + switch (arizona->type) { + case WM5102: + case WM8997: + break; + default: + priv->out_up_delay += 10; + break; + } + break; default: break; } @@ -889,8 +904,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, case ARIZONA_OUT2R_ENA_SHIFT: case ARIZONA_OUT3L_ENA_SHIFT: case ARIZONA_OUT3R_ENA_SHIFT: + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: priv->out_up_pending--; - if (!priv->out_up_pending) { + if (!priv->out_up_pending && priv->out_up_delay) { + dev_dbg(codec->dev, "Power up delay: %d\n", + priv->out_up_delay); msleep(priv->out_up_delay); priv->out_up_delay = 0; } @@ -911,6 +930,21 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, priv->out_down_pending++; priv->out_down_delay++; break; + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: + priv->out_down_pending++; + switch (arizona->type) { + case WM5102: + case WM8997: + break; + case WM8998: + case WM1814: + priv->out_down_delay += 5; + break; + default: + priv->out_down_delay++; + break; + } default: break; } @@ -923,8 +957,12 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w, case ARIZONA_OUT2R_ENA_SHIFT: case ARIZONA_OUT3L_ENA_SHIFT: case ARIZONA_OUT3R_ENA_SHIFT: + case ARIZONA_OUT4L_ENA_SHIFT: + case ARIZONA_OUT4R_ENA_SHIFT: priv->out_down_pending--; - if (!priv->out_down_pending) { + if (!priv->out_down_pending && priv->out_down_delay) { + dev_dbg(codec->dev, "Power down delay: %d\n", + priv->out_down_delay); msleep(priv->out_down_delay); priv->out_down_delay = 0; } @@ -1920,8 +1958,8 @@ static struct { struct arizona_fll_cfg { int n; - int theta; - int lambda; + unsigned int theta; + unsigned int lambda; int refdiv; int outdiv; int fratio; @@ -2188,13 +2226,13 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, ARIZONA_FLL1_CTRL_UPD | cfg->n); } -static int arizona_is_enabled_fll(struct arizona_fll *fll) +static int arizona_is_enabled_fll(struct arizona_fll *fll, int base) { struct arizona *arizona = fll->arizona; unsigned int reg; int ret; - ret = regmap_read(arizona->regmap, fll->base + 1, ®); + ret = regmap_read(arizona->regmap, base + 1, ®); if (ret != 0) { arizona_fll_err(fll, "Failed to read current state: %d\n", ret); @@ -2208,21 +2246,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; bool use_sync = false; - int already_enabled = arizona_is_enabled_fll(fll); + int already_enabled = arizona_is_enabled_fll(fll, fll->base); + int sync_enabled = arizona_is_enabled_fll(fll, fll->base + 0x10); struct arizona_fll_cfg cfg; int i; unsigned int val; if (already_enabled < 0) return already_enabled; + if (sync_enabled < 0) + return sync_enabled; if (already_enabled) { /* Facilitate smooth refclk across the transition */ - regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, - ARIZONA_FLL1_GAIN_MASK, 0); regmap_update_bits(fll->arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); udelay(32); + regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, + ARIZONA_FLL1_GAIN_MASK, 0); } /* @@ -2233,6 +2274,10 @@ static int arizona_enable_fll(struct arizona_fll *fll) fll->ref_src != fll->sync_src) { arizona_calc_fll(fll, &cfg, fll->ref_freq, false); + /* Ref path hardcodes lambda to 65536 when sync is on */ + if (fll->sync_src >= 0 && cfg.lambda) + cfg.theta = (cfg.theta * (1 << 16)) / cfg.lambda; + arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src, false); if (fll->sync_src >= 0) { @@ -2255,6 +2300,9 @@ static int arizona_enable_fll(struct arizona_fll *fll) return -EINVAL; } + if (already_enabled && !!sync_enabled != use_sync) + arizona_fll_warn(fll, "Synchroniser changed on active FLL\n"); + /* * Increase the bandwidth if we're not using a low frequency * sync source. @@ -2268,14 +2316,14 @@ static int arizona_enable_fll(struct arizona_fll *fll) ARIZONA_FLL1_SYNC_BW); if (!already_enabled) - pm_runtime_get(arizona->dev); + pm_runtime_get_sync(arizona->dev); - regmap_update_bits_async(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (use_sync) regmap_update_bits_async(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); + regmap_update_bits_async(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (already_enabled) regmap_update_bits_async(arizona->regmap, fll->base + 1, diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 69da1ef3a17c..850aa338ba29 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -190,20 +190,21 @@ extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_DSP_ROUTES(name) \ { name, NULL, name " Preloader"}, \ - { name " Preloader", NULL, name " Aux 1" }, \ - { name " Preloader", NULL, name " Aux 2" }, \ - { name " Preloader", NULL, name " Aux 3" }, \ - { name " Preloader", NULL, name " Aux 4" }, \ - { name " Preloader", NULL, name " Aux 5" }, \ - { name " Preloader", NULL, name " Aux 6" }, \ + { name " Preloader", NULL, "SYSCLK" }, \ + { name, NULL, name " Aux 1" }, \ + { name, NULL, name " Aux 2" }, \ + { name, NULL, name " Aux 3" }, \ + { name, NULL, name " Aux 4" }, \ + { name, NULL, name " Aux 5" }, \ + { name, NULL, name " Aux 6" }, \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 1"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 2"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 3"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 4"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 5"), \ ARIZONA_MIXER_INPUT_ROUTES(name " Aux 6"), \ - ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \ - ARIZONA_MIXER_ROUTES(name " Preloader", name "R") + ARIZONA_MIXER_ROUTES(name, name "L"), \ + ARIZONA_MIXER_ROUTES(name, name "R") #define ARIZONA_EQ_CONTROL(xname, xbase) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 01b573ab7036..71ba5605495f 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -794,7 +794,7 @@ struct cs42l73_mclk_div { u8 mmcc; }; -static struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = { +static const struct cs42l73_mclk_div cs42l73_mclk_coeffs[] = { /* MCLK, Sample Rate, xMMCC[5:0] */ {5644800, 11025, 0x30}, {5644800, 22050, 0x20}, @@ -844,7 +844,7 @@ struct cs42l73_mclkx_div { u8 mclkdiv; }; -static struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = { +static const struct cs42l73_mclkx_div cs42l73_mclkx_coeffs[] = { {5644800, 1, 0}, /* 5644800 */ {6000000, 1, 0}, /* 6000000 */ {6144000, 1, 0}, /* 6144000 */ diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 779a7bfff1c3..5b22564f037c 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -746,6 +746,16 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { { "IN2L", NULL, "SYSCLK" }, { "IN2R", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "MICBIAS1", NULL, "MICVDD" }, { "MICBIAS2", NULL, "MICVDD" }, @@ -804,7 +814,6 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { { "AIF3 Capture", NULL, "SYSCLK" }, { "Voice Control DSP", NULL, "DSP3" }, - { "Voice Control DSP", NULL, "SYSCLK" }, { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -813,7 +822,6 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { { "IN2R PGA", NULL, "IN2R" }, { "Audio Trace DSP", NULL, "DSP2" }, - { "Audio Trace DSP", NULL, "SYSCLK" }, ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index e244e08b7da1..cb47fb595ff4 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -466,7 +466,7 @@ struct cs53l30_mclk_div { u8 mclk_int_scale; }; -static struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = { +static const struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = { /* NOTE: Enable MCLK_INT_SCALE to save power. */ /* MCLK, Sample Rate, asp_rate, internal_fs_ratio, mclk_int_scale */ @@ -511,7 +511,7 @@ struct cs53l30_mclkx_div { u8 mclkdiv; }; -static struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = { +static const struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = { {5644800, 1, CS53L30_MCLK_DIV_BY_1}, {6000000, 1, CS53L30_MCLK_DIV_BY_1}, {6144000, 1, CS53L30_MCLK_DIV_BY_1}, @@ -1000,8 +1000,8 @@ static int cs53l30_i2c_probe(struct i2c_client *client, /* Check if MCLK provided */ cs53l30->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(cs53l30->mclk)) { - if (PTR_ERR(cs53l30->mclk) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + if (PTR_ERR(cs53l30->mclk) != -ENOENT) { + ret = PTR_ERR(cs53l30->mclk); goto error; } /* Otherwise mark the mclk pointer to NULL */ diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 7cfb5da5378d..12da55882c06 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -750,11 +750,18 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK, 0); - /* Slave mode, if SRM not enabled no need for status checks */ + /* If SRM not enabled then nothing more to do */ pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL); if (!(pll_ctrl & DA7213_PLL_SRM_EN)) return 0; + /* Assist 32KHz mode PLL lock */ + if (pll_ctrl & DA7213_PLL_32K_MODE) { + snd_soc_write(codec, 0xF0, 0x8B); + snd_soc_write(codec, 0xF2, 0x03); + snd_soc_write(codec, 0xF0, 0x00); + } + /* Check SRM has locked */ do { pll_status = snd_soc_read(codec, DA7213_PLL_STATUS); @@ -771,6 +778,14 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w, return 0; case SND_SOC_DAPM_POST_PMD: + /* Revert 32KHz PLL lock udpates if applied previously */ + pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL); + if (pll_ctrl & DA7213_PLL_32K_MODE) { + snd_soc_write(codec, 0xF0, 0x8B); + snd_soc_write(codec, 0xF2, 0x01); + snd_soc_write(codec, 0xF0, 0x00); + } + /* PC free-running */ snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK, @@ -1247,8 +1262,8 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - /* By default only 32 BCLK per WCLK is supported */ - dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_32; + /* By default only 64 BCLK per WCLK is supported */ + dai_clk_mode |= DA7213_DAI_BCLKS_PER_WCLK_64; snd_soc_write(codec, DA7213_DAI_CLK_MODE, dai_clk_mode); snd_soc_update_bits(codec, DA7213_DAI_CTRL, DA7213_DAI_FORMAT_MASK, @@ -1297,10 +1312,13 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, switch (clk_id) { case DA7213_CLKSRC_MCLK: - da7213->mclk_squarer_en = false; + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_MCLK_SQR_EN, 0); break; case DA7213_CLKSRC_MCLK_SQR: - da7213->mclk_squarer_en = true; + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_MCLK_SQR_EN, + DA7213_PLL_MCLK_SQR_EN); break; default: dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); @@ -1324,7 +1342,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, return 0; } -/* Supported PLL input frequencies are 5MHz - 54MHz. */ +/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, int source, unsigned int fref, unsigned int fout) { @@ -1336,22 +1354,26 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, u32 freq_ref; u64 frac_div; - /* Reset PLL configuration */ - snd_soc_write(codec, DA7213_PLL_CTRL, 0); - - pll_ctrl = 0; - /* Workout input divider based on MCLK rate */ if (da7213->mclk_rate == 32768) { + if (!da7213->master) { + dev_err(codec->dev, + "32KHz only valid if codec is clock master\n"); + return -EINVAL; + } + /* 32KHz PLL Mode */ indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ; indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL; + source = DA7213_SYSCLK_PLL_32KHZ; freq_ref = 3750000; - pll_ctrl |= DA7213_PLL_32K_MODE; + } else { - /* 5 - 54MHz MCLK */ if (da7213->mclk_rate < 5000000) { - goto pll_err; + dev_err(codec->dev, + "PLL input clock %d below valid range\n", + da7213->mclk_rate); + return -EINVAL; } else if (da7213->mclk_rate <= 9000000) { indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ; indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL; @@ -1365,32 +1387,44 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ; indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL; } else { - goto pll_err; + dev_err(codec->dev, + "PLL input clock %d above valid range\n", + da7213->mclk_rate); + return -EINVAL; } freq_ref = (da7213->mclk_rate / indiv); } - pll_ctrl |= indiv_bits; + pll_ctrl = indiv_bits; - /* PLL Bypass mode */ - if (source == DA7213_SYSCLK_MCLK) { - snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + /* Configure PLL */ + switch (source) { + case DA7213_SYSCLK_MCLK: + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_INDIV_MASK | + DA7213_PLL_MODE_MASK, pll_ctrl); return 0; - } + case DA7213_SYSCLK_PLL: + break; + case DA7213_SYSCLK_PLL_SRM: + pll_ctrl |= DA7213_PLL_SRM_EN; + fout = DA7213_PLL_FREQ_OUT_94310400; + break; + case DA7213_SYSCLK_PLL_32KHZ: + if (da7213->mclk_rate != 32768) { + dev_err(codec->dev, + "32KHz mode only valid with 32KHz MCLK\n"); + return -EINVAL; + } - /* - * If Codec is slave and SRM enabled, - * freq_out is (98304000 + 90316800)/2 = 94310400 - */ - if (!da7213->master && da7213->srm_en) { + pll_ctrl |= DA7213_PLL_32K_MODE | DA7213_PLL_SRM_EN; fout = DA7213_PLL_FREQ_OUT_94310400; - pll_ctrl |= DA7213_PLL_SRM_EN; + break; + default: + dev_err(codec->dev, "Invalid PLL config\n"); + return -EINVAL; } - /* Enable MCLK squarer if required */ - if (da7213->mclk_squarer_en) - pll_ctrl |= DA7213_PLL_MCLK_SQR_EN; - /* Calculate dividers for PLL */ pll_integer = fout / freq_ref; frac_div = (u64)(fout % freq_ref) * 8192ULL; @@ -1405,14 +1439,19 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, /* Enable PLL */ pll_ctrl |= DA7213_PLL_EN; - snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl); + snd_soc_update_bits(codec, DA7213_PLL_CTRL, + DA7213_PLL_INDIV_MASK | DA7213_PLL_MODE_MASK, + pll_ctrl); + + /* Assist 32KHz mode PLL lock */ + if (source == DA7213_SYSCLK_PLL_32KHZ) { + snd_soc_write(codec, 0xF0, 0x8B); + snd_soc_write(codec, 0xF1, 0x03); + snd_soc_write(codec, 0xF1, 0x01); + snd_soc_write(codec, 0xF0, 0x00); + } return 0; - -pll_err: - dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", - da7213->mclk_rate); - return -EINVAL; } /* DAI operations */ @@ -1454,11 +1493,10 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { - /* MCLK */ + case SND_SOC_BIAS_PREPARE: + /* Enable MCLK for transition to ON state */ + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { if (da7213->mclk) { ret = clk_prepare_enable(da7213->mclk); if (ret) { @@ -1467,21 +1505,24 @@ static int da7213_set_bias_level(struct snd_soc_codec *codec, return ret; } } - + } + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { /* Enable VMID reference & master bias */ snd_soc_update_bits(codec, DA7213_REFERENCES, DA7213_VMID_EN | DA7213_BIAS_EN, DA7213_VMID_EN | DA7213_BIAS_EN); + } else { + /* Remove MCLK */ + if (da7213->mclk) + clk_disable_unprepare(da7213->mclk); } break; case SND_SOC_BIAS_OFF: /* Disable VMID reference & master bias */ snd_soc_update_bits(codec, DA7213_REFERENCES, DA7213_VMID_EN | DA7213_BIAS_EN, 0); - - /* MCLK */ - if (da7213->mclk) - clk_disable_unprepare(da7213->mclk); break; } return 0; @@ -1605,9 +1646,6 @@ static int da7213_probe(struct snd_soc_codec *codec) DA7213_ALC_CALIB_MODE_MAN, 0); da7213->alc_calib_auto = true; - /* Default to using SRM for slave mode */ - da7213->srm_en = true; - /* Default PC counter to free-running */ snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK, DA7213_PC_FREERUN_MASK); diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index fbb7a356a501..16ef56f77cd4 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -172,6 +172,7 @@ #define DA7213_PLL_32K_MODE (0x1 << 5) #define DA7213_PLL_SRM_EN (0x1 << 6) #define DA7213_PLL_EN (0x1 << 7) +#define DA7213_PLL_MODE_MASK (0x7 << 5) /* DA7213_DAI_CLK_MODE = 0x28 */ #define DA7213_DAI_BCLKS_PER_WCLK_32 (0x0 << 0) @@ -499,8 +500,6 @@ #define DA7213_ALC_AVG_ITERATIONS 5 /* PLL related */ -#define DA7213_SYSCLK_MCLK 0 -#define DA7213_SYSCLK_PLL 1 #define DA7213_PLL_FREQ_OUT_90316800 90316800 #define DA7213_PLL_FREQ_OUT_98304000 98304000 #define DA7213_PLL_FREQ_OUT_94310400 94310400 @@ -515,6 +514,13 @@ enum da7213_clk_src { DA7213_CLKSRC_MCLK_SQR, }; +enum da7213_sys_clk { + DA7213_SYSCLK_MCLK = 0, + DA7213_SYSCLK_PLL, + DA7213_SYSCLK_PLL_SRM, + DA7213_SYSCLK_PLL_32KHZ +}; + /* Codec private data */ struct da7213_priv { struct regmap *regmap; @@ -522,8 +528,6 @@ struct da7213_priv { unsigned int mclk_rate; int clk_src; bool master; - bool mclk_squarer_en; - bool srm_en; bool alc_calib_auto; bool alc_en; struct da7213_platform_data *pdata; diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index dcdda6c15cf7..c69e97654fc6 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -1819,7 +1819,7 @@ static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (da7218->mclk_rate == freq) return 0; - if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) { + if ((freq < 2000000) || (freq > 54000000)) { dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; @@ -1866,11 +1866,8 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, u32 freq_ref; u64 frac_div; - /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ - if (da7218->mclk_rate == 32768) { - indiv_bits = DA7218_PLL_INDIV_9_TO_18_MHZ; - indiv = DA7218_PLL_INDIV_9_TO_18_MHZ_VAL; - } else if (da7218->mclk_rate < 2000000) { + /* Verify 2MHz - 54MHz MCLK provided, and set input divider */ + if (da7218->mclk_rate < 2000000) { dev_err(codec->dev, "PLL input clock %d below valid range\n", da7218->mclk_rate); return -EINVAL; @@ -1911,9 +1908,6 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, case DA7218_SYSCLK_PLL_SRM: pll_ctrl |= DA7218_PLL_MODE_SRM; break; - case DA7218_SYSCLK_PLL_32KHZ: - pll_ctrl |= DA7218_PLL_MODE_32KHZ; - break; default: dev_err(codec->dev, "Invalid PLL config\n"); return -EINVAL; @@ -2589,20 +2583,22 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { - /* MCLK */ + case SND_SOC_BIAS_PREPARE: + /* Enable MCLK for transition to ON state */ + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { if (da7218->mclk) { ret = clk_prepare_enable(da7218->mclk); if (ret) { - dev_err(codec->dev, - "Failed to enable mclk\n"); + dev_err(codec->dev, "Failed to enable mclk\n"); return ret; } } + } + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { /* Master bias */ snd_soc_update_bits(codec, DA7218_REFERENCES, DA7218_BIAS_EN_MASK, @@ -2612,6 +2608,10 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, DA7218_LDO_CTRL, DA7218_LDO_EN_MASK, DA7218_LDO_EN_MASK); + } else { + /* Remove MCLK */ + if (da7218->mclk) + clk_disable_unprepare(da7218->mclk); } break; case SND_SOC_BIAS_OFF: @@ -2625,10 +2625,6 @@ static int da7218_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, DA7218_REFERENCES, DA7218_BIAS_EN_MASK, 0); } - - /* MCLK */ - if (da7218->mclk) - clk_disable_unprepare(da7218->mclk); break; } diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h index 477cd37723cf..4f7ec21069a4 100644 --- a/sound/soc/codecs/da7218.h +++ b/sound/soc/codecs/da7218.h @@ -888,7 +888,6 @@ #define DA7218_PLL_MODE_BYPASS (0x0 << 6) #define DA7218_PLL_MODE_NORMAL (0x1 << 6) #define DA7218_PLL_MODE_SRM (0x2 << 6) -#define DA7218_PLL_MODE_32KHZ (0x3 << 6) /* DA7218_PLL_FRAC_TOP = 0x92 */ #define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT 0 @@ -1371,7 +1370,6 @@ enum da7218_sys_clk { DA7218_SYSCLK_MCLK = 0, DA7218_SYSCLK_PLL, DA7218_SYSCLK_PLL_SRM, - DA7218_SYSCLK_PLL_32KHZ }; enum da7218_dev_id { diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index f0057cd223a4..2b8914dd5990 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/property.h> #include <linux/pm_wakeirq.h> @@ -114,13 +115,38 @@ static void da7219_aad_hptest_work(struct work_struct *work) struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); u16 tonegen_freq_hptest; - u8 accdet_cfg8; - int report = 0; + u8 pll_srm_sts, gain_ramp_ctrl, accdet_cfg8; + int report = 0, ret = 0; /* Lock DAPM and any Kcontrols that are affected by this test */ snd_soc_dapm_mutex_lock(dapm); mutex_lock(&da7219->lock); + /* Ensure MCLK is available for HP test procedure */ + if (da7219->mclk) { + ret = clk_prepare_enable(da7219->mclk); + if (ret) { + dev_err(codec->dev, "Failed to enable mclk - %d\n", ret); + mutex_unlock(&da7219->lock); + snd_soc_dapm_mutex_unlock(dapm); + return; + } + } + + /* + * If MCLK not present, then we're using the internal oscillator and + * require different frequency settings to achieve the same result. + */ + pll_srm_sts = snd_soc_read(codec, DA7219_PLL_SRM_STS); + if (pll_srm_sts & DA7219_PLL_SRM_STS_MCLK) + tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); + else + tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC); + + /* Ensure gain ramping at fastest rate */ + gain_ramp_ctrl = snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL); + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, DA7219_GAIN_RAMP_RATE_X8); + /* Bypass cache so it saves current settings */ regcache_cache_bypass(da7219->regmap, true); @@ -183,9 +209,15 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_write(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); + /* + * If we're running from the internal oscillator then give audio paths + * time to settle before running test. + */ + if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)) + msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY); + /* Configure & start Tone Generator */ snd_soc_write(codec, DA7219_TONE_GEN_ON_PER, DA7219_BEEP_ON_PER_MASK); - tonegen_freq_hptest = cpu_to_le16(DA7219_AAD_HPTEST_RAMP_FREQ); regmap_raw_write(da7219->regmap, DA7219_TONE_GEN_FREQ1_L, &tonegen_freq_hptest, sizeof(tonegen_freq_hptest)); snd_soc_update_bits(codec, DA7219_TONE_GEN_CFG2, @@ -244,12 +276,26 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_8, DA7219_HPTEST_EN_MASK, 0); + /* + * If we're running from the internal oscillator then give audio paths + * time to settle before allowing headphones to be driven as required. + */ + if (!(pll_srm_sts & DA7219_PLL_SRM_STS_MCLK)) + msleep(DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY); + + /* Restore gain ramping rate */ + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, gain_ramp_ctrl); + /* Drive Headphones/lineout */ snd_soc_update_bits(codec, DA7219_HP_L_CTRL, DA7219_HP_L_AMP_OE_MASK, DA7219_HP_L_AMP_OE_MASK); snd_soc_update_bits(codec, DA7219_HP_R_CTRL, DA7219_HP_R_AMP_OE_MASK, DA7219_HP_R_AMP_OE_MASK); + /* Remove MCLK, if previously enabled */ + if (da7219->mclk) + clk_disable_unprepare(da7219->mclk); + mutex_unlock(&da7219->lock); snd_soc_dapm_mutex_unlock(dapm); @@ -751,6 +797,62 @@ static void da7219_aad_handle_pdata(struct snd_soc_codec *codec) /* + * Suspend/Resume + */ + +void da7219_aad_suspend(struct snd_soc_codec *codec) +{ + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + struct da7219_aad_priv *da7219_aad = da7219->aad; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + u8 micbias_ctrl; + + if (da7219_aad->jack) { + /* Disable jack detection during suspend */ + snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, + DA7219_ACCDET_EN_MASK, 0); + + /* + * If we have a 4-pole jack inserted, then micbias will be + * enabled. We can disable micbias here, and keep a note to + * re-enable it on resume. If jack removal occurred during + * suspend then this will be dealt with through the IRQ handler. + */ + if (da7219_aad->jack_inserted) { + micbias_ctrl = snd_soc_read(codec, DA7219_MICBIAS_CTRL); + if (micbias_ctrl & DA7219_MICBIAS1_EN_MASK) { + snd_soc_dapm_disable_pin(dapm, "Mic Bias"); + snd_soc_dapm_sync(dapm); + da7219_aad->micbias_resume_enable = true; + } + } + } +} + +void da7219_aad_resume(struct snd_soc_codec *codec) +{ + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + struct da7219_aad_priv *da7219_aad = da7219->aad; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + if (da7219_aad->jack) { + /* Re-enable micbias if previously enabled for 4-pole jack */ + if (da7219_aad->jack_inserted && + da7219_aad->micbias_resume_enable) { + snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); + snd_soc_dapm_sync(dapm); + da7219_aad->micbias_resume_enable = false; + } + + /* Re-enable jack detection */ + snd_soc_update_bits(codec, DA7219_ACCDET_CONFIG_1, + DA7219_ACCDET_EN_MASK, + DA7219_ACCDET_EN_MASK); + } +} + + +/* * Init/Exit */ diff --git a/sound/soc/codecs/da7219-aad.h b/sound/soc/codecs/da7219-aad.h index 4fccf677cd06..117a3d7ccd31 100644 --- a/sound/soc/codecs/da7219-aad.h +++ b/sound/soc/codecs/da7219-aad.h @@ -176,8 +176,10 @@ #define DA7219_AAD_MICBIAS_CHK_DELAY 10 #define DA7219_AAD_MICBIAS_CHK_RETRIES 5 -#define DA7219_AAD_HPTEST_RAMP_FREQ 0x28 -#define DA7219_AAD_HPTEST_PERIOD 65 +#define DA7219_AAD_HPTEST_RAMP_FREQ 0x28 +#define DA7219_AAD_HPTEST_RAMP_FREQ_INT_OSC 0x4D +#define DA7219_AAD_HPTEST_PERIOD 65 +#define DA7219_AAD_HPTEST_INT_OSC_PATH_DELAY 20 enum da7219_aad_event_regs { DA7219_AAD_IRQ_REG_A = 0, @@ -199,12 +201,17 @@ struct da7219_aad_priv { struct work_struct hptest_work; struct snd_soc_jack *jack; + bool micbias_resume_enable; bool jack_inserted; }; /* AAD control */ void da7219_aad_jack_det(struct snd_soc_codec *codec, struct snd_soc_jack *jack); +/* Suspend/Resume */ +void da7219_aad_suspend(struct snd_soc_codec *codec); +void da7219_aad_resume(struct snd_soc_codec *codec); + /* Init/Exit */ int da7219_aad_init(struct snd_soc_codec *codec); void da7219_aad_exit(struct snd_soc_codec *codec); diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index b6411bd3c4f2..1152aa5e7c39 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -801,7 +801,7 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, ++i; msleep(50); } - } while ((i < DA7219_SRM_CHECK_RETRIES) & (!srm_lock)); + } while ((i < DA7219_SRM_CHECK_RETRIES) && (!srm_lock)); if (!srm_lock) dev_warn(codec->dev, "SRM failed to lock\n"); @@ -1482,6 +1482,8 @@ static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_codec *codec) if (!pdata) return NULL; + pdata->wakeup_source = device_property_read_bool(dev, "wakeup-source"); + if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0) pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32); else @@ -1508,11 +1510,10 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - case SND_SOC_BIAS_PREPARE: break; - case SND_SOC_BIAS_STANDBY: - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { - /* MCLK */ + case SND_SOC_BIAS_PREPARE: + /* Enable MCLK for transition to ON state */ + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_STANDBY) { if (da7219->mclk) { ret = clk_prepare_enable(da7219->mclk); if (ret) { @@ -1521,22 +1522,28 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec, return ret; } } + } + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) /* Master bias */ snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, DA7219_BIAS_EN_MASK); + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_PREPARE) { + /* Remove MCLK */ + if (da7219->mclk) + clk_disable_unprepare(da7219->mclk); } break; case SND_SOC_BIAS_OFF: - /* Only disable master bias if jack detection not active */ - if (!da7219->aad->jack) + /* Only disable master bias if we're not a wake-up source */ + if (!da7219->wakeup_source) snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, 0); - /* MCLK */ - if (da7219->mclk) - clk_disable_unprepare(da7219->mclk); break; } @@ -1599,6 +1606,8 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec) if (pdata) { u8 micbias_lvl = 0; + da7219->wakeup_source = pdata->wakeup_source; + /* Mic Bias voltages */ switch (pdata->micbias_lvl) { case DA7219_MICBIAS_1_6V: @@ -1733,11 +1742,11 @@ static int da7219_suspend(struct snd_soc_codec *codec) { struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); - snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); + /* Suspend AAD if we're not a wake-up source */ + if (!da7219->wakeup_source) + da7219_aad_suspend(codec); - /* Put device into standby mode if jack detection disabled */ - if (!da7219->aad->jack) - snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, 0); + snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -1746,13 +1755,12 @@ static int da7219_resume(struct snd_soc_codec *codec) { struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); - /* Put device into active mode if previously pushed to standby */ - if (!da7219->aad->jack) - snd_soc_write(codec, DA7219_SYSTEM_ACTIVE, - DA7219_SYSTEM_ACTIVE_MASK); - snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Resume AAD if previously suspended */ + if (!da7219->wakeup_source) + da7219_aad_resume(codec); + return 0; } #else @@ -1922,7 +1930,8 @@ static int da7219_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct da7219_priv *da7219; - int ret; + unsigned int system_active, system_status; + int i, ret; da7219 = devm_kzalloc(&i2c->dev, sizeof(struct da7219_priv), GFP_KERNEL); @@ -1938,6 +1947,37 @@ static int da7219_i2c_probe(struct i2c_client *i2c, return ret; } + regcache_cache_bypass(da7219->regmap, true); + + /* Disable audio paths if still active from previous start */ + regmap_read(da7219->regmap, DA7219_SYSTEM_ACTIVE, &system_active); + if (system_active) { + regmap_write(da7219->regmap, DA7219_GAIN_RAMP_CTRL, + DA7219_GAIN_RAMP_RATE_NOMINAL); + regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_INPUT, 0x00); + regmap_write(da7219->regmap, DA7219_SYSTEM_MODES_OUTPUT, 0x01); + + for (i = 0; i < DA7219_SYS_STAT_CHECK_RETRIES; ++i) { + regmap_read(da7219->regmap, DA7219_SYSTEM_STATUS, + &system_status); + if (!system_status) + break; + + msleep(DA7219_SYS_STAT_CHECK_DELAY); + } + } + + /* Soft reset codec */ + regmap_write_bits(da7219->regmap, DA7219_ACCDET_CONFIG_1, + DA7219_ACCDET_EN_MASK, 0); + regmap_write_bits(da7219->regmap, DA7219_CIF_CTRL, + DA7219_CIF_REG_SOFT_RESET_MASK, + DA7219_CIF_REG_SOFT_RESET_MASK); + regmap_write_bits(da7219->regmap, DA7219_SYSTEM_ACTIVE, + DA7219_SYSTEM_ACTIVE_MASK, 0); + + regcache_cache_bypass(da7219->regmap, false); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da7219, &da7219_dai, 1); if (ret < 0) { diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index ff2a2f02ce40..66d3bad86739 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -224,6 +224,7 @@ #define DA7219_PLL_SRM_STATE_MASK (0xF << 0) #define DA7219_PLL_SRM_STATUS_SHIFT 4 #define DA7219_PLL_SRM_STATUS_MASK (0xF << 4) +#define DA7219_PLL_SRM_STS_MCLK (0x1 << 4) #define DA7219_PLL_SRM_STS_SRM_LOCK (0x1 << 7) /* DA7219_DIG_ROUTING_DAI = 0x2A */ @@ -576,6 +577,8 @@ /* DA7219_GAIN_RAMP_CTRL = 0x92 */ #define DA7219_GAIN_RAMP_RATE_SHIFT 0 #define DA7219_GAIN_RAMP_RATE_MASK (0x3 << 0) +#define DA7219_GAIN_RAMP_RATE_X8 (0x0 << 0) +#define DA7219_GAIN_RAMP_RATE_NOMINAL (0x1 << 0) #define DA7219_GAIN_RAMP_RATE_MAX 4 /* DA7219_PC_COUNT = 0x94 */ @@ -770,6 +773,10 @@ /* SRM */ #define DA7219_SRM_CHECK_RETRIES 8 +/* System Controller */ +#define DA7219_SYS_STAT_CHECK_RETRIES 6 +#define DA7219_SYS_STAT_CHECK_DELAY 50 + enum da7219_clk_src { DA7219_CLKSRC_MCLK = 0, DA7219_CLKSRC_MCLK_SQR, @@ -796,6 +803,7 @@ struct da7219_priv { struct da7219_aad_priv *aad; struct da7219_pdata *pdata; + bool wakeup_source; struct regulator_bulk_data supplies[DA7219_NUM_SUPPLIES]; struct regmap *regmap; struct mutex lock; diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 4e181b270d95..c602c4960924 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -614,7 +614,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, (!pin->eld.eld_valid)) { dev_warn(&hdac->hdac.dev, - "Failed: montior present? %d ELD valid?: %d for pin: %d\n", + "Failed: monitor present? %d ELD valid?: %d for pin: %d\n", pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); return 0; diff --git a/sound/soc/codecs/l3.c b/sound/soc/codecs/l3.c index 5353af58862c..a10ea3c716c6 100644 --- a/sound/soc/codecs/l3.c +++ b/sound/soc/codecs/l3.c @@ -20,6 +20,8 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> +#include <linux/device.h> +#include <linux/gpio.h> #include <sound/l3.h> @@ -32,11 +34,11 @@ static void sendbyte(struct l3_pins *adap, unsigned int byte) int i; for (i = 0; i < 8; i++) { - adap->setclk(0); + adap->setclk(adap, 0); udelay(adap->data_hold); - adap->setdat(byte & 1); + adap->setdat(adap, byte & 1); udelay(adap->data_setup); - adap->setclk(1); + adap->setclk(adap, 1); udelay(adap->clock_high); byte >>= 1; } @@ -55,10 +57,10 @@ static void sendbytes(struct l3_pins *adap, const u8 *buf, for (i = 0; i < len; i++) { if (i) { udelay(adap->mode_hold); - adap->setmode(0); + adap->setmode(adap, 0); udelay(adap->mode); } - adap->setmode(1); + adap->setmode(adap, 1); udelay(adap->mode_setup); sendbyte(adap, buf[i]); } @@ -66,26 +68,71 @@ static void sendbytes(struct l3_pins *adap, const u8 *buf, int l3_write(struct l3_pins *adap, u8 addr, u8 *data, int len) { - adap->setclk(1); - adap->setdat(1); - adap->setmode(1); + adap->setclk(adap, 1); + adap->setdat(adap, 1); + adap->setmode(adap, 1); udelay(adap->mode); - adap->setmode(0); + adap->setmode(adap, 0); udelay(adap->mode_setup); sendbyte(adap, addr); udelay(adap->mode_hold); sendbytes(adap, data, len); - adap->setclk(1); - adap->setdat(1); - adap->setmode(0); + adap->setclk(adap, 1); + adap->setdat(adap, 1); + adap->setmode(adap, 0); return len; } EXPORT_SYMBOL_GPL(l3_write); + +static void l3_set_clk(struct l3_pins *adap, int val) +{ + gpio_set_value(adap->gpio_clk, val); +} + +static void l3_set_data(struct l3_pins *adap, int val) +{ + gpio_set_value(adap->gpio_data, val); +} + +static void l3_set_mode(struct l3_pins *adap, int val) +{ + gpio_set_value(adap->gpio_mode, val); +} + +int l3_set_gpio_ops(struct device *dev, struct l3_pins *adap) +{ + int ret; + + if (!adap->use_gpios) + return -EINVAL; + + ret = devm_gpio_request_one(dev, adap->gpio_data, + GPIOF_OUT_INIT_LOW, "l3_data"); + if (ret < 0) + return ret; + adap->setdat = l3_set_data; + + ret = devm_gpio_request_one(dev, adap->gpio_clk, + GPIOF_OUT_INIT_LOW, "l3_clk"); + if (ret < 0) + return ret; + adap->setclk = l3_set_clk; + + ret = devm_gpio_request_one(dev, adap->gpio_mode, + GPIOF_OUT_INIT_LOW, "l3_mode"); + if (ret < 0) + return ret; + adap->setmode = l3_set_mode; + + return 0; +} +EXPORT_SYMBOL_GPL(l3_set_gpio_ops); + MODULE_DESCRIPTION("L3 bit-banging driver"); MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c index cf0a39bb631a..781be9ba8dba 100644 --- a/sound/soc/codecs/max98371.c +++ b/sound/soc/codecs/max98371.c @@ -412,6 +412,7 @@ static int max98371_i2c_remove(struct i2c_client *client) static const struct i2c_device_id max98371_i2c_id[] = { { "max98371", 0 }, + { } }; MODULE_DEVICE_TABLE(i2c, max98371_i2c_id); @@ -425,7 +426,6 @@ MODULE_DEVICE_TABLE(of, max98371_of_match); static struct i2c_driver max98371_i2c_driver = { .driver = { .name = "max98371", - .owner = THIS_MODULE, .pm = NULL, .of_match_table = of_match_ptr(max98371_of_match), }, diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index c9673235078d..42e2e407e287 100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c @@ -38,11 +38,10 @@ static DECLARE_TLV_DB_SCALE(max9860_capture_tlv, -600, 200, 0); static DECLARE_TLV_DB_SCALE(max9860_mic_tlv, 2000, 100, 1); static DECLARE_TLV_DB_SCALE(max9860_adc_left_tlv, -1200, 100, 1); static DECLARE_TLV_DB_SCALE(max9860_adc_right_tlv, -1200, 100, 1); -static const unsigned int max98088_micboost_tlv[] = { - TLV_DB_RANGE_HEAD(2), +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(max98088_micboost_tlv, 0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0), 2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0), -}; +); static const struct snd_kcontrol_new max9867_snd_controls[] = { SOC_DOUBLE_R("Master Playback Volume", MAX9867_LEFTVOL, diff --git a/sound/soc/codecs/max98926.c b/sound/soc/codecs/max98926.c index 5830a81e535a..1eff7e0b092e 100644 --- a/sound/soc/codecs/max98926.c +++ b/sound/soc/codecs/max98926.c @@ -347,7 +347,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, max98926_set_sense_data(max98926); break; default: - dev_err(codec->dev, "DAI clock mode unsupported"); + dev_err(codec->dev, "DAI clock mode unsupported\n"); return -EINVAL; } @@ -364,7 +364,7 @@ static int max98926_dai_set_fmt(struct snd_soc_dai *codec_dai, invert = MAX98926_DAI_BCI_MASK | MAX98926_DAI_WCI_MASK; break; default: - dev_err(codec->dev, "DAI invert mode unsupported"); + dev_err(codec->dev, "DAI invert mode unsupported\n"); return -EINVAL; } @@ -408,7 +408,7 @@ static int max98926_dai_hw_params(struct snd_pcm_substream *substream, max98926->ch_size = 32; break; default: - dev_dbg(codec->dev, "format unsupported %d", + dev_dbg(codec->dev, "format unsupported %d\n", params_format(params)); return -EINVAL; } diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c new file mode 100644 index 000000000000..e45518629968 --- /dev/null +++ b/sound/soc/codecs/nau8810.c @@ -0,0 +1,884 @@ +/* + * nau8810.c -- NAU8810 ALSA Soc Audio driver + * + * Copyright 2016 Nuvoton Technology Corp. + * + * Author: David Lin <ctlin0@nuvoton.com> + * + * Based on WM8974.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "nau8810.h" + +#define NAU_PLL_FREQ_MAX 100000000 +#define NAU_PLL_FREQ_MIN 90000000 +#define NAU_PLL_REF_MAX 33000000 +#define NAU_PLL_REF_MIN 8000000 +#define NAU_PLL_OPTOP_MIN 6 + + +static const int nau8810_mclk_scaler[] = { 10, 15, 20, 30, 40, 60, 80, 120 }; + +static const struct reg_default nau8810_reg_defaults[] = { + { NAU8810_REG_POWER1, 0x0000 }, + { NAU8810_REG_POWER2, 0x0000 }, + { NAU8810_REG_POWER3, 0x0000 }, + { NAU8810_REG_IFACE, 0x0050 }, + { NAU8810_REG_COMP, 0x0000 }, + { NAU8810_REG_CLOCK, 0x0140 }, + { NAU8810_REG_SMPLR, 0x0000 }, + { NAU8810_REG_DAC, 0x0000 }, + { NAU8810_REG_DACGAIN, 0x00FF }, + { NAU8810_REG_ADC, 0x0100 }, + { NAU8810_REG_ADCGAIN, 0x00FF }, + { NAU8810_REG_EQ1, 0x012C }, + { NAU8810_REG_EQ2, 0x002C }, + { NAU8810_REG_EQ3, 0x002C }, + { NAU8810_REG_EQ4, 0x002C }, + { NAU8810_REG_EQ5, 0x002C }, + { NAU8810_REG_DACLIM1, 0x0032 }, + { NAU8810_REG_DACLIM2, 0x0000 }, + { NAU8810_REG_NOTCH1, 0x0000 }, + { NAU8810_REG_NOTCH2, 0x0000 }, + { NAU8810_REG_NOTCH3, 0x0000 }, + { NAU8810_REG_NOTCH4, 0x0000 }, + { NAU8810_REG_ALC1, 0x0038 }, + { NAU8810_REG_ALC2, 0x000B }, + { NAU8810_REG_ALC3, 0x0032 }, + { NAU8810_REG_NOISEGATE, 0x0000 }, + { NAU8810_REG_PLLN, 0x0008 }, + { NAU8810_REG_PLLK1, 0x000C }, + { NAU8810_REG_PLLK2, 0x0093 }, + { NAU8810_REG_PLLK3, 0x00E9 }, + { NAU8810_REG_ATTEN, 0x0000 }, + { NAU8810_REG_INPUT_SIGNAL, 0x0003 }, + { NAU8810_REG_PGAGAIN, 0x0010 }, + { NAU8810_REG_ADCBOOST, 0x0100 }, + { NAU8810_REG_OUTPUT, 0x0002 }, + { NAU8810_REG_SPKMIX, 0x0001 }, + { NAU8810_REG_SPKGAIN, 0x0039 }, + { NAU8810_REG_MONOMIX, 0x0001 }, + { NAU8810_REG_POWER4, 0x0000 }, + { NAU8810_REG_TSLOTCTL1, 0x0000 }, + { NAU8810_REG_TSLOTCTL2, 0x0020 }, + { NAU8810_REG_DEVICE_REVID, 0x0000 }, + { NAU8810_REG_I2C_DEVICEID, 0x001A }, + { NAU8810_REG_ADDITIONID, 0x00CA }, + { NAU8810_REG_RESERVE, 0x0124 }, + { NAU8810_REG_OUTCTL, 0x0001 }, + { NAU8810_REG_ALC1ENHAN1, 0x0010 }, + { NAU8810_REG_ALC1ENHAN2, 0x0000 }, + { NAU8810_REG_MISCCTL, 0x0000 }, + { NAU8810_REG_OUTTIEOFF, 0x0000 }, + { NAU8810_REG_AGCP2POUT, 0x0000 }, + { NAU8810_REG_AGCPOUT, 0x0000 }, + { NAU8810_REG_AMTCTL, 0x0000 }, + { NAU8810_REG_OUTTIEOFFMAN, 0x0000 }, +}; + +static bool nau8810_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8810_REG_RESET ... NAU8810_REG_SMPLR: + case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN: + case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN: + case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5: + case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2: + case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4: + case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN: + case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN: + case NAU8810_REG_ADCBOOST: + case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX: + case NAU8810_REG_SPKGAIN: + case NAU8810_REG_MONOMIX: + case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2: + case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE: + case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2: + case NAU8810_REG_MISCCTL: + case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN: + return true; + default: + return false; + } +} + +static bool nau8810_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8810_REG_RESET ... NAU8810_REG_SMPLR: + case NAU8810_REG_DAC ... NAU8810_REG_DACGAIN: + case NAU8810_REG_ADC ... NAU8810_REG_ADCGAIN: + case NAU8810_REG_EQ1 ... NAU8810_REG_EQ5: + case NAU8810_REG_DACLIM1 ... NAU8810_REG_DACLIM2: + case NAU8810_REG_NOTCH1 ... NAU8810_REG_NOTCH4: + case NAU8810_REG_ALC1 ... NAU8810_REG_ATTEN: + case NAU8810_REG_INPUT_SIGNAL ... NAU8810_REG_PGAGAIN: + case NAU8810_REG_ADCBOOST: + case NAU8810_REG_OUTPUT ... NAU8810_REG_SPKMIX: + case NAU8810_REG_SPKGAIN: + case NAU8810_REG_MONOMIX: + case NAU8810_REG_POWER4 ... NAU8810_REG_TSLOTCTL2: + case NAU8810_REG_OUTCTL ... NAU8810_REG_ALC1ENHAN2: + case NAU8810_REG_MISCCTL: + case NAU8810_REG_OUTTIEOFF ... NAU8810_REG_OUTTIEOFFMAN: + return true; + default: + return false; + } +} + +static bool nau8810_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NAU8810_REG_RESET: + case NAU8810_REG_DEVICE_REVID ... NAU8810_REG_RESERVE: + return true; + default: + return false; + } +} + +/* The EQ parameters get function is to get the 5 band equalizer control. + * The regmap raw read can't work here because regmap doesn't provide + * value format for value width of 9 bits. Therefore, the driver reads data + * from cache and makes value format according to the endianness of + * bytes type control element. + */ +static int nau8810_eq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + int i, reg, reg_val; + u16 *val; + + val = (u16 *)ucontrol->value.bytes.data; + reg = NAU8810_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + regmap_read(nau8810->regmap, reg + i, ®_val); + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + reg_val = cpu_to_be16(reg_val); + memcpy(val + i, ®_val, sizeof(reg_val)); + } + + return 0; +} + +/* The EQ parameters put function is to make configuration of 5 band equalizer + * control. These configuration includes central frequency, equalizer gain, + * cut-off frequency, bandwidth control, and equalizer path. + * The regmap raw write can't work here because regmap doesn't provide + * register and value format for register with address 7 bits and value 9 bits. + * Therefore, the driver makes value format according to the endianness of + * bytes type control element and writes data to codec. + */ +static int nau8810_eq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *params = (void *)kcontrol->private_value; + void *data; + u16 *val, value; + int i, reg, ret; + + data = kmemdup(ucontrol->value.bytes.data, + params->max, GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + val = (u16 *)data; + reg = NAU8810_REG_EQ1; + for (i = 0; i < params->max / sizeof(u16); i++) { + /* conversion of 16-bit integers between native CPU format + * and big endian format + */ + value = be16_to_cpu(*(val + i)); + ret = regmap_write(nau8810->regmap, reg + i, value); + if (ret) { + dev_err(codec->dev, "EQ configuration fail, register: %x ret: %d\n", + reg + i, ret); + kfree(data); + return ret; + } + } + kfree(data); + + return 0; +} + +static const char * const nau8810_companding[] = { + "Off", "NC", "u-law", "A-law" }; + +static const struct soc_enum nau8810_companding_adc_enum = + SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_ADCCM_SFT, + ARRAY_SIZE(nau8810_companding), nau8810_companding); + +static const struct soc_enum nau8810_companding_dac_enum = + SOC_ENUM_SINGLE(NAU8810_REG_COMP, NAU8810_DACCM_SFT, + ARRAY_SIZE(nau8810_companding), nau8810_companding); + +static const char * const nau8810_deemp[] = { + "None", "32kHz", "44.1kHz", "48kHz" }; + +static const struct soc_enum nau8810_deemp_enum = + SOC_ENUM_SINGLE(NAU8810_REG_DAC, NAU8810_DEEMP_SFT, + ARRAY_SIZE(nau8810_deemp), nau8810_deemp); + +static const char * const nau8810_eqmode[] = {"Capture", "Playback" }; + +static const struct soc_enum nau8810_eqmode_enum = + SOC_ENUM_SINGLE(NAU8810_REG_EQ1, NAU8810_EQM_SFT, + ARRAY_SIZE(nau8810_eqmode), nau8810_eqmode); + +static const char * const nau8810_alc[] = {"Normal", "Limiter" }; + +static const struct soc_enum nau8810_alc_enum = + SOC_ENUM_SINGLE(NAU8810_REG_ALC3, NAU8810_ALCM_SFT, + ARRAY_SIZE(nau8810_alc), nau8810_alc); + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); +static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); + +static const struct snd_kcontrol_new nau8810_snd_controls[] = { + SOC_ENUM("ADC Companding", nau8810_companding_adc_enum), + SOC_ENUM("DAC Companding", nau8810_companding_dac_enum), + SOC_ENUM("DAC De-emphasis", nau8810_deemp_enum), + + SOC_ENUM("EQ Function", nau8810_eqmode_enum), + SND_SOC_BYTES_EXT("EQ Parameters", 10, + nau8810_eq_get, nau8810_eq_put), + + SOC_SINGLE("DAC Inversion Switch", NAU8810_REG_DAC, + NAU8810_DACPL_SFT, 1, 0), + SOC_SINGLE_TLV("Playback Volume", NAU8810_REG_DACGAIN, + NAU8810_DACGAIN_SFT, 0xff, 0, digital_tlv), + + SOC_SINGLE("High Pass Filter Switch", NAU8810_REG_ADC, + NAU8810_HPFEN_SFT, 1, 0), + SOC_SINGLE("High Pass Cut Off", NAU8810_REG_ADC, + NAU8810_HPF_SFT, 0x7, 0), + + SOC_SINGLE("ADC Inversion Switch", NAU8810_REG_ADC, + NAU8810_ADCPL_SFT, 1, 0), + SOC_SINGLE_TLV("Capture Volume", NAU8810_REG_ADCGAIN, + NAU8810_ADCGAIN_SFT, 0xff, 0, digital_tlv), + + SOC_SINGLE_TLV("EQ1 Volume", NAU8810_REG_EQ1, + NAU8810_EQ1GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ2 Volume", NAU8810_REG_EQ2, + NAU8810_EQ2GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ3 Volume", NAU8810_REG_EQ3, + NAU8810_EQ3GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ4 Volume", NAU8810_REG_EQ4, + NAU8810_EQ4GC_SFT, 0x18, 1, eq_tlv), + SOC_SINGLE_TLV("EQ5 Volume", NAU8810_REG_EQ5, + NAU8810_EQ5GC_SFT, 0x18, 1, eq_tlv), + + SOC_SINGLE("DAC Limiter Switch", NAU8810_REG_DACLIM1, + NAU8810_DACLIMEN_SFT, 1, 0), + SOC_SINGLE("DAC Limiter Decay", NAU8810_REG_DACLIM1, + NAU8810_DACLIMDCY_SFT, 0xf, 0), + SOC_SINGLE("DAC Limiter Attack", NAU8810_REG_DACLIM1, + NAU8810_DACLIMATK_SFT, 0xf, 0), + SOC_SINGLE("DAC Limiter Threshold", NAU8810_REG_DACLIM2, + NAU8810_DACLIMTHL_SFT, 0x7, 0), + SOC_SINGLE("DAC Limiter Boost", NAU8810_REG_DACLIM2, + NAU8810_DACLIMBST_SFT, 0xf, 0), + + SOC_ENUM("ALC Mode", nau8810_alc_enum), + SOC_SINGLE("ALC Enable Switch", NAU8810_REG_ALC1, + NAU8810_ALCEN_SFT, 1, 0), + SOC_SINGLE("ALC Max Volume", NAU8810_REG_ALC1, + NAU8810_ALCMXGAIN_SFT, 0x7, 0), + SOC_SINGLE("ALC Min Volume", NAU8810_REG_ALC1, + NAU8810_ALCMINGAIN_SFT, 0x7, 0), + SOC_SINGLE("ALC ZC Switch", NAU8810_REG_ALC2, + NAU8810_ALCZC_SFT, 1, 0), + SOC_SINGLE("ALC Hold", NAU8810_REG_ALC2, + NAU8810_ALCHT_SFT, 0xf, 0), + SOC_SINGLE("ALC Target", NAU8810_REG_ALC2, + NAU8810_ALCSL_SFT, 0xf, 0), + SOC_SINGLE("ALC Decay", NAU8810_REG_ALC3, + NAU8810_ALCDCY_SFT, 0xf, 0), + SOC_SINGLE("ALC Attack", NAU8810_REG_ALC3, + NAU8810_ALCATK_SFT, 0xf, 0), + SOC_SINGLE("ALC Noise Gate Switch", NAU8810_REG_NOISEGATE, + NAU8810_ALCNEN_SFT, 1, 0), + SOC_SINGLE("ALC Noise Gate Threshold", NAU8810_REG_NOISEGATE, + NAU8810_ALCNTH_SFT, 0x7, 0), + + SOC_SINGLE("PGA ZC Switch", NAU8810_REG_PGAGAIN, + NAU8810_PGAZC_SFT, 1, 0), + SOC_SINGLE_TLV("PGA Volume", NAU8810_REG_PGAGAIN, + NAU8810_PGAGAIN_SFT, 0x3f, 0, inpga_tlv), + + SOC_SINGLE("Speaker ZC Switch", NAU8810_REG_SPKGAIN, + NAU8810_SPKZC_SFT, 1, 0), + SOC_SINGLE("Speaker Mute Switch", NAU8810_REG_SPKGAIN, + NAU8810_SPKMT_SFT, 1, 0), + SOC_SINGLE_TLV("Speaker Volume", NAU8810_REG_SPKGAIN, + NAU8810_SPKGAIN_SFT, 0x3f, 0, spk_tlv), + + SOC_SINGLE("Capture Boost(+20dB)", NAU8810_REG_ADCBOOST, + NAU8810_PGABST_SFT, 1, 0), + SOC_SINGLE("Mono Mute Switch", NAU8810_REG_MONOMIX, + NAU8810_MOUTMXMT_SFT, 1, 0), + + SOC_SINGLE("DAC Oversampling Rate(128x) Switch", NAU8810_REG_DAC, + NAU8810_DACOS_SFT, 1, 0), + SOC_SINGLE("ADC Oversampling Rate(128x) Switch", NAU8810_REG_ADC, + NAU8810_ADCOS_SFT, 1, 0), +}; + +/* Speaker Output Mixer */ +static const struct snd_kcontrol_new nau8810_speaker_mixer_controls[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_SPKMIX, + NAU8810_BYPSPK_SFT, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_SPKMIX, + NAU8810_DACSPK_SFT, 1, 0), +}; + +/* Mono Output Mixer */ +static const struct snd_kcontrol_new nau8810_mono_mixer_controls[] = { + SOC_DAPM_SINGLE("Line Bypass Switch", NAU8810_REG_MONOMIX, + NAU8810_BYPMOUT_SFT, 1, 0), + SOC_DAPM_SINGLE("PCM Playback Switch", NAU8810_REG_MONOMIX, + NAU8810_DACMOUT_SFT, 1, 0), +}; + +/* PGA Mute */ +static const struct snd_kcontrol_new nau8810_inpga_mute[] = { + SOC_DAPM_SINGLE("PGA Mute Switch", NAU8810_REG_PGAGAIN, + NAU8810_PGAMT_SFT, 1, 0), +}; + +/* Input PGA */ +static const struct snd_kcontrol_new nau8810_inpga[] = { + SOC_DAPM_SINGLE("MicN Switch", NAU8810_REG_INPUT_SIGNAL, + NAU8810_NMICPGA_SFT, 1, 0), + SOC_DAPM_SINGLE("MicP Switch", NAU8810_REG_INPUT_SIGNAL, + NAU8810_PMICPGA_SFT, 1, 0), +}; + +/* Mic Input boost vol */ +static const struct snd_kcontrol_new nau8810_mic_boost_controls = + SOC_DAPM_SINGLE("Mic Volume", NAU8810_REG_ADCBOOST, + NAU8810_PMICBSTGAIN_SFT, 0x7, 0); + +/* Loopback Switch */ +static const struct snd_kcontrol_new nau8810_loopback = + SOC_DAPM_SINGLE("Switch", NAU8810_REG_COMP, + NAU8810_ADDAP_SFT, 1, 0); + +static int check_mclk_select_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); + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + unsigned int value; + + regmap_read(nau8810->regmap, NAU8810_REG_CLOCK, &value); + return (value & NAU8810_CLKM_MASK); +} + +static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = { + SND_SOC_DAPM_MIXER("Speaker Mixer", NAU8810_REG_POWER3, + NAU8810_SPKMX_EN_SFT, 0, &nau8810_speaker_mixer_controls[0], + ARRAY_SIZE(nau8810_speaker_mixer_controls)), + SND_SOC_DAPM_MIXER("Mono Mixer", NAU8810_REG_POWER3, + NAU8810_MOUTMX_EN_SFT, 0, &nau8810_mono_mixer_controls[0], + ARRAY_SIZE(nau8810_mono_mixer_controls)), + SND_SOC_DAPM_DAC("DAC", "HiFi Playback", NAU8810_REG_POWER3, + NAU8810_DAC_EN_SFT, 0), + SND_SOC_DAPM_ADC("ADC", "HiFi Capture", NAU8810_REG_POWER2, + NAU8810_ADC_EN_SFT, 0), + SND_SOC_DAPM_PGA("SpkN Out", NAU8810_REG_POWER3, + NAU8810_NSPK_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("SpkP Out", NAU8810_REG_POWER3, + NAU8810_PSPK_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono Out", NAU8810_REG_POWER3, + NAU8810_MOUT_EN_SFT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("Input PGA", NAU8810_REG_POWER2, + NAU8810_PGA_EN_SFT, 0, nau8810_inpga, + ARRAY_SIZE(nau8810_inpga)), + SND_SOC_DAPM_MIXER("Input Boost Stage", NAU8810_REG_POWER2, + NAU8810_BST_EN_SFT, 0, nau8810_inpga_mute, + ARRAY_SIZE(nau8810_inpga_mute)), + + SND_SOC_DAPM_SUPPLY("Mic Bias", NAU8810_REG_POWER1, + NAU8810_MICBIAS_EN_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", NAU8810_REG_POWER1, + NAU8810_PLL_EN_SFT, 0, NULL, 0), + + SND_SOC_DAPM_SWITCH("Digital Loopback", SND_SOC_NOPM, 0, 0, + &nau8810_loopback), + + SND_SOC_DAPM_INPUT("MICN"), + SND_SOC_DAPM_INPUT("MICP"), + SND_SOC_DAPM_OUTPUT("MONOOUT"), + SND_SOC_DAPM_OUTPUT("SPKOUTP"), + SND_SOC_DAPM_OUTPUT("SPKOUTN"), +}; + +static const struct snd_soc_dapm_route nau8810_dapm_routes[] = { + {"DAC", NULL, "PLL", check_mclk_select_pll}, + + /* Mono output mixer */ + {"Mono Mixer", "PCM Playback Switch", "DAC"}, + {"Mono Mixer", "Line Bypass Switch", "Input Boost Stage"}, + + /* Speaker output mixer */ + {"Speaker Mixer", "PCM Playback Switch", "DAC"}, + {"Speaker Mixer", "Line Bypass Switch", "Input Boost Stage"}, + + /* Outputs */ + {"Mono Out", NULL, "Mono Mixer"}, + {"MONOOUT", NULL, "Mono Out"}, + {"SpkN Out", NULL, "Speaker Mixer"}, + {"SpkP Out", NULL, "Speaker Mixer"}, + {"SPKOUTN", NULL, "SpkN Out"}, + {"SPKOUTP", NULL, "SpkP Out"}, + + /* Input Boost Stage */ + {"ADC", NULL, "Input Boost Stage"}, + {"ADC", NULL, "PLL", check_mclk_select_pll}, + {"Input Boost Stage", NULL, "Input PGA"}, + {"Input Boost Stage", NULL, "MICP"}, + + /* Input PGA */ + {"Input PGA", NULL, "Mic Bias"}, + {"Input PGA", "MicN Switch", "MICN"}, + {"Input PGA", "MicP Switch", "MICP"}, + + /* Digital Looptack */ + {"Digital Loopback", "Switch", "ADC"}, + {"DAC", NULL, "Digital Loopback"}, +}; + +static int nau8810_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + + nau8810->clk_id = clk_id; + nau8810->sysclk = freq; + dev_dbg(nau8810->dev, "master sysclk %dHz, source %s\n", + freq, clk_id == NAU8810_SCLK_PLL ? "PLL" : "MCLK"); + + return 0; +} + +static int nau88l0_calc_pll(unsigned int pll_in, + unsigned int fs, struct nau8810_pll *pll_param) +{ + u64 f2, f2_max, pll_ratio; + int i, scal_sel; + + if (pll_in > NAU_PLL_REF_MAX || pll_in < NAU_PLL_REF_MIN) + return -EINVAL; + + f2_max = 0; + scal_sel = ARRAY_SIZE(nau8810_mclk_scaler); + for (i = 0; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) { + f2 = 256 * fs * 4 * nau8810_mclk_scaler[i] / 10; + if (f2 > NAU_PLL_FREQ_MIN && f2 < NAU_PLL_FREQ_MAX && + f2_max < f2) { + f2_max = f2; + scal_sel = i; + } + } + if (ARRAY_SIZE(nau8810_mclk_scaler) == scal_sel) + return -EINVAL; + pll_param->mclk_scaler = scal_sel; + f2 = f2_max; + + /* Calculate the PLL 4-bit integer input and the PLL 24-bit fractional + * input; round up the 24+4bit. + */ + pll_ratio = div_u64(f2 << 28, pll_in); + pll_param->pre_factor = 0; + if (((pll_ratio >> 28) & 0xF) < NAU_PLL_OPTOP_MIN) { + pll_ratio <<= 1; + pll_param->pre_factor = 1; + } + pll_param->pll_int = (pll_ratio >> 28) & 0xF; + pll_param->pll_frac = ((pll_ratio & 0xFFFFFFF) >> 4); + + return 0; +} + +static int nau8810_set_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct regmap *map = nau8810->regmap; + struct nau8810_pll *pll_param = &nau8810->pll; + int ret, fs; + + fs = freq_out / 256; + ret = nau88l0_calc_pll(freq_in, fs, pll_param); + if (ret < 0) { + dev_err(nau8810->dev, "Unsupported input clock %d\n", freq_in); + return ret; + } + dev_info(nau8810->dev, "pll_int=%x pll_frac=%x mclk_scaler=%x pre_factor=%x\n", + pll_param->pll_int, pll_param->pll_frac, pll_param->mclk_scaler, + pll_param->pre_factor); + + regmap_update_bits(map, NAU8810_REG_PLLN, + NAU8810_PLLMCLK_DIV2 | NAU8810_PLLN_MASK, + (pll_param->pre_factor ? NAU8810_PLLMCLK_DIV2 : 0) | + pll_param->pll_int); + regmap_write(map, NAU8810_REG_PLLK1, + (pll_param->pll_frac >> NAU8810_PLLK1_SFT) & + NAU8810_PLLK1_MASK); + regmap_write(map, NAU8810_REG_PLLK2, + (pll_param->pll_frac >> NAU8810_PLLK2_SFT) & + NAU8810_PLLK2_MASK); + regmap_write(map, NAU8810_REG_PLLK3, + pll_param->pll_frac & NAU8810_PLLK3_MASK); + regmap_update_bits(map, NAU8810_REG_CLOCK, NAU8810_MCLKSEL_MASK, + pll_param->mclk_scaler << NAU8810_MCLKSEL_SFT); + regmap_update_bits(map, NAU8810_REG_CLOCK, + NAU8810_CLKM_MASK, NAU8810_CLKM_PLL); + + return 0; +} + +static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + u16 ctrl1_val = 0, ctrl2_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + ctrl2_val |= NAU8810_CLKIO_MASTER; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + ctrl1_val |= NAU8810_AIFMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + ctrl1_val |= NAU8810_AIFMT_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + ctrl1_val |= NAU8810_AIFMT_PCM_A; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + ctrl1_val |= NAU8810_BCLKP_IB | NAU8810_FSP_IF; + break; + case SND_SOC_DAIFMT_IB_NF: + ctrl1_val |= NAU8810_BCLKP_IB; + break; + case SND_SOC_DAIFMT_NB_IF: + ctrl1_val |= NAU8810_FSP_IF; + break; + default: + return -EINVAL; + } + + regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE, + NAU8810_AIFMT_MASK | NAU8810_FSP_IF | + NAU8810_BCLKP_IB, ctrl1_val); + regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK, + NAU8810_CLKIO_MASK, ctrl2_val); + + return 0; +} + +static int nau8810_mclk_clkdiv(struct nau8810 *nau8810, int rate) +{ + int i, sclk, imclk = rate * 256, div = 0; + + if (!nau8810->sysclk) { + dev_err(nau8810->dev, "Make mclk div configuration fail because of invalid system clock\n"); + return -EINVAL; + } + + /* Configure the master clock prescaler div to make system + * clock to approximate the internal master clock (IMCLK); + * and large or equal to IMCLK. + */ + for (i = 1; i < ARRAY_SIZE(nau8810_mclk_scaler); i++) { + sclk = (nau8810->sysclk * 10) / + nau8810_mclk_scaler[i]; + if (sclk < imclk) + break; + div = i; + } + dev_dbg(nau8810->dev, + "master clock prescaler %x for fs %d\n", div, rate); + + /* master clock from MCLK and disable PLL */ + regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK, + NAU8810_MCLKSEL_MASK, (div << NAU8810_MCLKSEL_SFT)); + regmap_update_bits(nau8810->regmap, NAU8810_REG_CLOCK, + NAU8810_CLKM_MASK, NAU8810_CLKM_MCLK); + + return 0; +} + +static int nau8810_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + int val_len = 0, val_rate = 0, ret = 0; + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= NAU8810_WLEN_20; + break; + case 24: + val_len |= NAU8810_WLEN_24; + break; + case 32: + val_len |= NAU8810_WLEN_32; + break; + } + + switch (params_rate(params)) { + case 8000: + val_rate |= NAU8810_SMPLR_8K; + break; + case 11025: + val_rate |= NAU8810_SMPLR_12K; + break; + case 16000: + val_rate |= NAU8810_SMPLR_16K; + break; + case 22050: + val_rate |= NAU8810_SMPLR_24K; + break; + case 32000: + val_rate |= NAU8810_SMPLR_32K; + break; + case 44100: + case 48000: + break; + } + + regmap_update_bits(nau8810->regmap, NAU8810_REG_IFACE, + NAU8810_WLEN_MASK, val_len); + regmap_update_bits(nau8810->regmap, NAU8810_REG_SMPLR, + NAU8810_SMPLR_MASK, val_rate); + + /* If the master clock is from MCLK, provide the runtime FS for driver + * to get the master clock prescaler configuration. + */ + if (nau8810->clk_id == NAU8810_SCLK_MCLK) { + ret = nau8810_mclk_clkdiv(nau8810, params_rate(params)); + if (ret < 0) + dev_err(nau8810->dev, "MCLK div configuration fail\n"); + } + + return ret; +} + +static int nau8810_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct nau8810 *nau8810 = snd_soc_codec_get_drvdata(codec); + struct regmap *map = nau8810->regmap; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_REFIMP_MASK, NAU8810_REFIMP_80K); + break; + + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_IOBUF_EN | NAU8810_ABIAS_EN, + NAU8810_IOBUF_EN | NAU8810_ABIAS_EN); + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + regcache_sync(map); + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_REFIMP_MASK, NAU8810_REFIMP_3K); + mdelay(100); + } + regmap_update_bits(map, NAU8810_REG_POWER1, + NAU8810_REFIMP_MASK, NAU8810_REFIMP_300K); + break; + + case SND_SOC_BIAS_OFF: + regmap_write(map, NAU8810_REG_POWER1, 0); + regmap_write(map, NAU8810_REG_POWER2, 0); + regmap_write(map, NAU8810_REG_POWER3, 0); + break; + } + + return 0; +} + + +#define NAU8810_RATES (SNDRV_PCM_RATE_8000_48000) + +#define NAU8810_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static const struct snd_soc_dai_ops nau8810_ops = { + .hw_params = nau8810_pcm_hw_params, + .set_fmt = nau8810_set_dai_fmt, + .set_sysclk = nau8810_set_sysclk, + .set_pll = nau8810_set_pll, +}; + +static struct snd_soc_dai_driver nau8810_dai = { + .name = "nau8810-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, /* Only 1 channel of data */ + .rates = NAU8810_RATES, + .formats = NAU8810_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, /* Only 1 channel of data */ + .rates = NAU8810_RATES, + .formats = NAU8810_FORMATS, + }, + .ops = &nau8810_ops, + .symmetric_rates = 1, +}; + +static const struct regmap_config nau8810_regmap_config = { + .reg_bits = 7, + .val_bits = 9, + + .max_register = NAU8810_REG_MAX, + .readable_reg = nau8810_readable_reg, + .writeable_reg = nau8810_writeable_reg, + .volatile_reg = nau8810_volatile_reg, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = nau8810_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(nau8810_reg_defaults), +}; + +static struct snd_soc_codec_driver nau8810_codec_driver = { + .set_bias_level = nau8810_set_bias_level, + .suspend_bias_off = true, + + .component_driver = { + .controls = nau8810_snd_controls, + .num_controls = ARRAY_SIZE(nau8810_snd_controls), + .dapm_widgets = nau8810_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(nau8810_dapm_widgets), + .dapm_routes = nau8810_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(nau8810_dapm_routes), + }, +}; + +static int nau8810_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct device *dev = &i2c->dev; + struct nau8810 *nau8810 = dev_get_platdata(dev); + + if (!nau8810) { + nau8810 = devm_kzalloc(dev, sizeof(*nau8810), GFP_KERNEL); + if (!nau8810) + return -ENOMEM; + } + i2c_set_clientdata(i2c, nau8810); + + nau8810->regmap = devm_regmap_init_i2c(i2c, &nau8810_regmap_config); + if (IS_ERR(nau8810->regmap)) + return PTR_ERR(nau8810->regmap); + nau8810->dev = dev; + + regmap_write(nau8810->regmap, NAU8810_REG_RESET, 0x00); + + return snd_soc_register_codec(dev, + &nau8810_codec_driver, &nau8810_dai, 1); +} + +static int nau8810_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + + return 0; +} + +static const struct i2c_device_id nau8810_i2c_id[] = { + { "nau8810", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nau8810_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id nau8810_of_match[] = { + { .compatible = "nuvoton,nau8810", }, + { } +}; +MODULE_DEVICE_TABLE(of, nau8810_of_match); +#endif + +static struct i2c_driver nau8810_i2c_driver = { + .driver = { + .name = "nau8810", + .of_match_table = of_match_ptr(nau8810_of_match), + }, + .probe = nau8810_i2c_probe, + .remove = nau8810_i2c_remove, + .id_table = nau8810_i2c_id, +}; + +module_i2c_driver(nau8810_i2c_driver); + +MODULE_DESCRIPTION("ASoC NAU8810 driver"); +MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/nau8810.h b/sound/soc/codecs/nau8810.h new file mode 100644 index 000000000000..df882658ca91 --- /dev/null +++ b/sound/soc/codecs/nau8810.h @@ -0,0 +1,281 @@ +/* + * NAU8810 ALSA SoC audio driver + * + * Copyright 2016 Nuvoton Technology Corp. + * Author: David Lin <ctlin0@nuvoton.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __NAU8810_H__ +#define __NAU8810_H__ + +#define NAU8810_REG_RESET 0x00 +#define NAU8810_REG_POWER1 0x01 +#define NAU8810_REG_POWER2 0x02 +#define NAU8810_REG_POWER3 0x03 +#define NAU8810_REG_IFACE 0x04 +#define NAU8810_REG_COMP 0x05 +#define NAU8810_REG_CLOCK 0x06 +#define NAU8810_REG_SMPLR 0x07 +#define NAU8810_REG_DAC 0x0A +#define NAU8810_REG_DACGAIN 0x0B +#define NAU8810_REG_ADC 0x0E +#define NAU8810_REG_ADCGAIN 0x0F +#define NAU8810_REG_EQ1 0x12 +#define NAU8810_REG_EQ2 0x13 +#define NAU8810_REG_EQ3 0x14 +#define NAU8810_REG_EQ4 0x15 +#define NAU8810_REG_EQ5 0x16 +#define NAU8810_REG_DACLIM1 0x18 +#define NAU8810_REG_DACLIM2 0x19 +#define NAU8810_REG_NOTCH1 0x1B +#define NAU8810_REG_NOTCH2 0x1C +#define NAU8810_REG_NOTCH3 0x1D +#define NAU8810_REG_NOTCH4 0x1E +#define NAU8810_REG_ALC1 0x20 +#define NAU8810_REG_ALC2 0x21 +#define NAU8810_REG_ALC3 0x22 +#define NAU8810_REG_NOISEGATE 0x23 +#define NAU8810_REG_PLLN 0x24 +#define NAU8810_REG_PLLK1 0x25 +#define NAU8810_REG_PLLK2 0x26 +#define NAU8810_REG_PLLK3 0x27 +#define NAU8810_REG_ATTEN 0x28 +#define NAU8810_REG_INPUT_SIGNAL 0x2C +#define NAU8810_REG_PGAGAIN 0x2D +#define NAU8810_REG_ADCBOOST 0x2F +#define NAU8810_REG_OUTPUT 0x31 +#define NAU8810_REG_SPKMIX 0x32 +#define NAU8810_REG_SPKGAIN 0x36 +#define NAU8810_REG_MONOMIX 0x38 +#define NAU8810_REG_POWER4 0x3A +#define NAU8810_REG_TSLOTCTL1 0x3B +#define NAU8810_REG_TSLOTCTL2 0x3C +#define NAU8810_REG_DEVICE_REVID 0x3E +#define NAU8810_REG_I2C_DEVICEID 0x3F +#define NAU8810_REG_ADDITIONID 0x40 +#define NAU8810_REG_RESERVE 0x41 +#define NAU8810_REG_OUTCTL 0x45 +#define NAU8810_REG_ALC1ENHAN1 0x46 +#define NAU8810_REG_ALC1ENHAN2 0x47 +#define NAU8810_REG_MISCCTL 0x49 +#define NAU8810_REG_OUTTIEOFF 0x4B +#define NAU8810_REG_AGCP2POUT 0x4C +#define NAU8810_REG_AGCPOUT 0x4D +#define NAU8810_REG_AMTCTL 0x4E +#define NAU8810_REG_OUTTIEOFFMAN 0x4F +#define NAU8810_REG_MAX NAU8810_REG_OUTTIEOFFMAN + + +/* NAU8810_REG_POWER1 (0x1) */ +#define NAU8810_DCBUF_EN (0x1 << 8) +#define NAU8810_PLL_EN_SFT 5 +#define NAU8810_MICBIAS_EN_SFT 4 +#define NAU8810_ABIAS_EN (0x1 << 3) +#define NAU8810_IOBUF_EN (0x1 << 2) +#define NAU8810_REFIMP_MASK 0x3 +#define NAU8810_REFIMP_DIS 0x0 +#define NAU8810_REFIMP_80K 0x1 +#define NAU8810_REFIMP_300K 0x2 +#define NAU8810_REFIMP_3K 0x3 + +/* NAU8810_REG_POWER2 (0x2) */ +#define NAU8810_BST_EN_SFT 4 +#define NAU8810_PGA_EN_SFT 2 +#define NAU8810_ADC_EN_SFT 0 + +/* NAU8810_REG_POWER3 (0x3) */ +#define NAU8810_DAC_EN_SFT 0 +#define NAU8810_SPKMX_EN_SFT 2 +#define NAU8810_MOUTMX_EN_SFT 3 +#define NAU8810_PSPK_EN_SFT 5 +#define NAU8810_NSPK_EN_SFT 6 +#define NAU8810_MOUT_EN_SFT 7 + +/* NAU8810_REG_IFACE (0x4) */ +#define NAU8810_AIFMT_SFT 3 +#define NAU8810_AIFMT_MASK (0x3 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_RIGHT (0x0 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_LEFT (0x1 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_I2S (0x2 << NAU8810_AIFMT_SFT) +#define NAU8810_AIFMT_PCM_A (0x3 << NAU8810_AIFMT_SFT) +#define NAU8810_WLEN_SFT 5 +#define NAU8810_WLEN_MASK (0x3 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_16 (0x0 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_20 (0x1 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_24 (0x2 << NAU8810_WLEN_SFT) +#define NAU8810_WLEN_32 (0x3 << NAU8810_WLEN_SFT) +#define NAU8810_FSP_IF (0x1 << 7) +#define NAU8810_BCLKP_IB (0x1 << 8) + +/* NAU8810_REG_COMP (0x5) */ +#define NAU8810_ADDAP_SFT 0 +#define NAU8810_ADCCM_SFT 1 +#define NAU8810_DACCM_SFT 3 + +/* NAU8810_REG_CLOCK (0x6) */ +#define NAU8810_CLKIO_MASK 0x1 +#define NAU8810_CLKIO_SLAVE 0x0 +#define NAU8810_CLKIO_MASTER 0x1 +#define NAU8810_BCLKSEL_SFT 2 +#define NAU8810_BCLKSEL_MASK (0x7 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_1 (0x0 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_2 (0x1 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_4 (0x2 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_8 (0x3 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_16 (0x4 << NAU8810_BCLKSEL_SFT) +#define NAU8810_BCLKDIV_32 (0x5 << NAU8810_BCLKSEL_SFT) +#define NAU8810_MCLKSEL_SFT 5 +#define NAU8810_MCLKSEL_MASK (0x7 << NAU8810_MCLKSEL_SFT) +#define NAU8810_CLKM_SFT 8 +#define NAU8810_CLKM_MASK (0x1 << NAU8810_CLKM_SFT) +#define NAU8810_CLKM_MCLK (0x0 << NAU8810_CLKM_SFT) +#define NAU8810_CLKM_PLL (0x1 << NAU8810_CLKM_SFT) + +/* NAU8810_REG_SMPLR (0x7) */ +#define NAU8810_SMPLR_SFT 1 +#define NAU8810_SMPLR_MASK (0x7 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_48K (0x0 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_32K (0x1 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_24K (0x2 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_16K (0x3 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_12K (0x4 << NAU8810_SMPLR_SFT) +#define NAU8810_SMPLR_8K (0x5 << NAU8810_SMPLR_SFT) + +/* NAU8810_REG_DAC (0xA) */ +#define NAU8810_DACPL_SFT 0 +#define NAU8810_DACOS_SFT 3 +#define NAU8810_DEEMP_SFT 4 + +/* NAU8810_REG_DACGAIN (0xB) */ +#define NAU8810_DACGAIN_SFT 0 + +/* NAU8810_REG_ADC (0xE) */ +#define NAU8810_ADCPL_SFT 0 +#define NAU8810_ADCOS_SFT 3 +#define NAU8810_HPF_SFT 4 +#define NAU8810_HPFEN_SFT 8 + +/* NAU8810_REG_ADCGAIN (0xF) */ +#define NAU8810_ADCGAIN_SFT 0 + +/* NAU8810_REG_EQ1 (0x12) */ +#define NAU8810_EQ1GC_SFT 0 +#define NAU8810_EQ1CF_SFT 5 +#define NAU8810_EQM_SFT 8 + +/* NAU8810_REG_EQ2 (0x13) */ +#define NAU8810_EQ2GC_SFT 0 +#define NAU8810_EQ2CF_SFT 5 +#define NAU8810_EQ2BW_SFT 8 + +/* NAU8810_REG_EQ3 (0x14) */ +#define NAU8810_EQ3GC_SFT 0 +#define NAU8810_EQ3CF_SFT 5 +#define NAU8810_EQ3BW_SFT 8 + +/* NAU8810_REG_EQ4 (0x15) */ +#define NAU8810_EQ4GC_SFT 0 +#define NAU8810_EQ4CF_SFT 5 +#define NAU8810_EQ4BW_SFT 8 + +/* NAU8810_REG_EQ5 (0x16) */ +#define NAU8810_EQ5GC_SFT 0 +#define NAU8810_EQ5CF_SFT 5 + +/* NAU8810_REG_DACLIM1 (0x18) */ +#define NAU8810_DACLIMATK_SFT 0 +#define NAU8810_DACLIMDCY_SFT 4 +#define NAU8810_DACLIMEN_SFT 8 + +/* NAU8810_REG_DACLIM2 (0x19) */ +#define NAU8810_DACLIMBST_SFT 0 +#define NAU8810_DACLIMTHL_SFT 4 + +/* NAU8810_REG_ALC1 (0x20) */ +#define NAU8810_ALCMINGAIN_SFT 0 +#define NAU8810_ALCMXGAIN_SFT 3 +#define NAU8810_ALCEN_SFT 8 + +/* NAU8810_REG_ALC2 (0x21) */ +#define NAU8810_ALCSL_SFT 0 +#define NAU8810_ALCHT_SFT 4 +#define NAU8810_ALCZC_SFT 8 + +/* NAU8810_REG_ALC3 (0x22) */ +#define NAU8810_ALCATK_SFT 0 +#define NAU8810_ALCDCY_SFT 4 +#define NAU8810_ALCM_SFT 8 + +/* NAU8810_REG_NOISEGATE (0x23) */ +#define NAU8810_ALCNTH_SFT 0 +#define NAU8810_ALCNEN_SFT 3 + +/* NAU8810_REG_PLLN (0x24) */ +#define NAU8810_PLLN_MASK 0xF +#define NAU8810_PLLMCLK_DIV2 (0x1 << 4) + +/* NAU8810_REG_PLLK1 (0x25) */ +#define NAU8810_PLLK1_SFT 18 +#define NAU8810_PLLK1_MASK 0x3F + +/* NAU8810_REG_PLLK2 (0x26) */ +#define NAU8810_PLLK2_SFT 9 +#define NAU8810_PLLK2_MASK 0x1FF + +/* NAU8810_REG_PLLK3 (0x27) */ +#define NAU8810_PLLK3_MASK 0x1FF + +/* NAU8810_REG_INPUT_SIGNAL (0x2C) */ +#define NAU8810_PMICPGA_SFT 0 +#define NAU8810_NMICPGA_SFT 1 + +/* NAU8810_REG_PGAGAIN (0x2D) */ +#define NAU8810_PGAGAIN_SFT 0 +#define NAU8810_PGAMT_SFT 6 +#define NAU8810_PGAZC_SFT 7 + +/* NAU8810_REG_ADCBOOST (0x2F) */ +#define NAU8810_PMICBSTGAIN_SFT 4 +#define NAU8810_PGABST_SFT 8 + +/* NAU8810_REG_SPKMIX (0x32) */ +#define NAU8810_DACSPK_SFT 0 +#define NAU8810_BYPSPK_SFT 1 + +/* NAU8810_REG_SPKGAIN (0x36) */ +#define NAU8810_SPKGAIN_SFT 0 +#define NAU8810_SPKMT_SFT 6 +#define NAU8810_SPKZC_SFT 7 + +/* NAU8810_REG_MONOMIX (0x38) */ +#define NAU8810_DACMOUT_SFT 0 +#define NAU8810_BYPMOUT_SFT 1 +#define NAU8810_MOUTMXMT_SFT 6 + + +/* System Clock Source */ +enum { + NAU8810_SCLK_MCLK, + NAU8810_SCLK_PLL, +}; + +struct nau8810_pll { + int pre_factor; + int mclk_scaler; + int pll_frac; + int pll_int; +}; + +struct nau8810 { + struct device *dev; + struct regmap *regmap; + struct nau8810_pll pll; + int sysclk; + int clk_id; +}; + +#endif diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 822791eb9574..e643be91d762 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -212,31 +212,6 @@ static const unsigned short logtable[256] = { 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 }; -static struct snd_soc_dai *nau8825_get_codec_dai(struct nau8825 *nau8825) -{ - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(nau8825->dapm); - struct snd_soc_component *component = &codec->component; - struct snd_soc_dai *codec_dai, *_dai; - - list_for_each_entry_safe(codec_dai, _dai, &component->dai_list, list) { - if (!strncmp(codec_dai->name, NUVOTON_CODEC_DAI, - strlen(NUVOTON_CODEC_DAI))) - return codec_dai; - } - return NULL; -} - -static bool nau8825_dai_is_active(struct nau8825 *nau8825) -{ - struct snd_soc_dai *codec_dai = nau8825_get_codec_dai(nau8825); - - if (codec_dai) { - if (codec_dai->playback_active || codec_dai->capture_active) - return true; - } - return false; -} - /** * nau8825_sema_acquire - acquire the semaphore of nau88l25 * @nau8825: component to register the codec private data with @@ -250,19 +225,26 @@ static bool nau8825_dai_is_active(struct nau8825 *nau8825) * Acquires the semaphore without jiffies. If no more tasks are allowed * to acquire the semaphore, calling this function will put the task to * sleep until the semaphore is released. - * It returns if the semaphore was acquired. + * If the semaphore is not released within the specified number of jiffies, + * this function returns -ETIME. + * If the sleep is interrupted by a signal, this function will return -EINTR. + * It returns 0 if the semaphore was acquired successfully. */ -static void nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) +static int nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) { int ret; - if (timeout) + if (timeout) { ret = down_timeout(&nau8825->xtalk_sem, timeout); - else + if (ret < 0) + dev_warn(nau8825->dev, "Acquire semaphone timeout\n"); + } else { ret = down_interruptible(&nau8825->xtalk_sem); + if (ret < 0) + dev_warn(nau8825->dev, "Acquire semaphone fail\n"); + } - if (ret < 0) - dev_warn(nau8825->dev, "Acquire semaphone fail\n"); + return ret; } /** @@ -1205,6 +1187,8 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int val_len = 0; + nau8825_sema_acquire(nau8825, 2 * HZ); + switch (params_width(params)) { case 16: val_len |= NAU8825_I2S_DL_16; @@ -1225,6 +1209,9 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL1, NAU8825_I2S_DL_MASK, val_len); + /* Release the semaphone. */ + nau8825_sema_release(nau8825); + return 0; } @@ -1234,6 +1221,8 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int ctrl1_val = 0, ctrl2_val = 0; + nau8825_sema_acquire(nau8825, 2 * HZ); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: ctrl2_val |= NAU8825_I2S_MS_MASTER; @@ -1282,6 +1271,9 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, NAU8825_I2S_MS_MASK, ctrl2_val); + /* Release the semaphone. */ + nau8825_sema_release(nau8825); + return 0; } @@ -1611,8 +1603,11 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) * cess and restore changes if process * is ongoing when ejection. */ + int ret; nau8825->xtalk_protect = true; - nau8825_sema_acquire(nau8825, 0); + ret = nau8825_sema_acquire(nau8825, 0); + if (ret < 0) + nau8825->xtalk_protect = false; } /* Startup cross talk detection process */ nau8825->xtalk_state = NAU8825_XTALK_PREPARE; @@ -1912,7 +1907,7 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs, /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional * input based on FDCO, FREF and FLL ratio. */ - fvco = div_u64(fvco << 16, fref * fll_param->ratio); + fvco = div_u64(fvco_max << 16, fref * fll_param->ratio); fll_param->fll_int = (fvco >> 16) & 0x3FF; fll_param->fll_frac = fvco & 0xFFFF; return 0; @@ -2238,23 +2233,14 @@ static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec) static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec) { struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); + int ret; regcache_cache_only(nau8825->regmap, false); regcache_sync(nau8825->regmap); - if (nau8825_is_jack_inserted(nau8825->regmap)) { - /* If the jack is inserted, we need to check whether the play- - * back is active before suspend. If active, the driver has to - * raise the protection for cross talk function to avoid the - * playback recovers before cross talk process finish. Other- - * wise, the playback will be interfered by cross talk func- - * tion. It is better to apply hardware related parameters - * before starting playback or record. - */ - if (nau8825_dai_is_active(nau8825)) { - nau8825->xtalk_protect = true; - nau8825_sema_acquire(nau8825, 0); - } - } + nau8825->xtalk_protect = true; + ret = nau8825_sema_acquire(nau8825, 0); + if (ret < 0) + nau8825->xtalk_protect = false; enable_irq(nau8825->irq); return 0; diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 77ff8ebe6dfb..09103aab0cb2 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -236,7 +236,7 @@ static snd_pcm_uframes_t rt5514_spi_pcm_pointer( return bytes_to_frames(runtime, rt5514_dsp->dma_offset); } -static struct snd_pcm_ops rt5514_spi_pcm_ops = { +static const struct snd_pcm_ops rt5514_spi_pcm_ops = { .open = rt5514_spi_pcm_open, .hw_params = rt5514_spi_hw_params, .hw_free = rt5514_spi_hw_free, diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index e0606a58da98..f24b7cfd3a89 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -278,7 +278,7 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv, 8, 8, TLV_DB_SCALE_ITEM(1700, 0, 0) ); -static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -352,10 +352,10 @@ static const struct snd_kcontrol_new rt5514_snd_controls[] = { SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST, RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv), SOC_DOUBLE_R_TLV("ADC1 Capture Volume", RT5514_DOWNFILTER0_CTRL1, - RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, + RT5514_DOWNFILTER0_CTRL2, RT5514_AD_GAIN_SFT, 63, 0, adc_vol_tlv), SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1, - RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, + RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 63, 0, adc_vol_tlv), SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0, rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put), diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 68883c68e999..229de0e2c88c 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -196,8 +196,8 @@ #define RT5514_AD_AD_MIX_BIT 10 #define RT5514_AD_AD_MUTE (0x1 << 7) #define RT5514_AD_AD_MUTE_BIT 7 -#define RT5514_AD_GAIN_MASK (0x7f << 0) -#define RT5514_AD_GAIN_SFT 0 +#define RT5514_AD_GAIN_MASK (0x3f << 1) +#define RT5514_AD_GAIN_SFT 1 /* RT5514_ANA_CTRL_MICBST (0x2220) */ #define RT5514_SEL_BSTL_MASK (0xf << 4) diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index e92a1490fa68..d1f273b24991 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -294,8 +294,7 @@ static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ -static unsigned int bst_tlv[] = { - TLV_DB_RANGE_HEAD(7), +static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(bst_tlv, 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), @@ -303,7 +302,7 @@ static unsigned int bst_tlv[] = { 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), -}; +); static const struct snd_kcontrol_new rt5616_snd_controls[] = { /* Headphone Output Volume */ @@ -1267,14 +1266,14 @@ static int rt5616_resume(struct snd_soc_codec *codec) #define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -struct snd_soc_dai_ops rt5616_aif_dai_ops = { +static struct snd_soc_dai_ops rt5616_aif_dai_ops = { .hw_params = rt5616_hw_params, .set_fmt = rt5616_set_dai_fmt, .set_sysclk = rt5616_set_dai_sysclk, .set_pll = rt5616_set_dai_pll, }; -struct snd_soc_dai_driver rt5616_dai[] = { +static struct snd_soc_dai_driver rt5616_dai[] = { { .name = "rt5616-aif1", .id = RT5616_AIF1, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index fbe3af14bd13..3cc1135fc2cd 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1870,6 +1870,9 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai, case RT5640_SCLK_S_PLL1: reg_val |= RT5640_SCLK_SRC_PLL1; break; + case RT5640_SCLK_S_RCCLK: + reg_val |= RT5640_SCLK_SRC_RCCLK; + break; default: dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); return -EINVAL; diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 58b664b06c16..90c88711c72a 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -984,6 +984,7 @@ #define RT5640_SCLK_SRC_SFT 14 #define RT5640_SCLK_SRC_MCLK (0x0 << 14) #define RT5640_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5640_SCLK_SRC_RCCLK (0x2 << 14) #define RT5640_PLL1_SRC_MASK (0x3 << 12) #define RT5640_PLL1_SRC_SFT 12 #define RT5640_PLL1_SRC_MCLK (0x0 << 12) diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index 59ddaf34705b..db54550aed60 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/clk.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -3565,7 +3566,9 @@ static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) static int rt5659_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + int ret; switch (level) { case SND_SOC_BIAS_PREPARE: @@ -3582,6 +3585,17 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec, RT5659_PWR_FV1 | RT5659_PWR_FV2); break; + case SND_SOC_BIAS_STANDBY: + if (dapm->bias_level == SND_SOC_BIAS_OFF) { + ret = clk_prepare_enable(rt5659->mclk); + if (ret) { + dev_err(codec->dev, + "failed to enable MCLK: %d\n", ret); + return ret; + } + } + break; + case SND_SOC_BIAS_OFF: regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1, RT5659_PWR_LDO, 0); @@ -3591,6 +3605,7 @@ static int rt5659_set_bias_level(struct snd_soc_codec *codec, RT5659_PWR_MB | RT5659_PWR_VREF2); regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC, RT5659_DIG_GATE_CTRL, 0); + clk_disable_unprepare(rt5659->mclk); break; default: @@ -4022,6 +4037,15 @@ static int rt5659_i2c_probe(struct i2c_client *i2c, regmap_write(rt5659->regmap, RT5659_RESET, 0); + /* Check if MCLK provided */ + rt5659->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(rt5659->mclk)) { + if (PTR_ERR(rt5659->mclk) != -ENOENT) + return PTR_ERR(rt5659->mclk); + /* Otherwise mark the mclk pointer to NULL */ + rt5659->mclk = NULL; + } + rt5659_calibrate(rt5659); /* line in diff mode*/ @@ -4165,6 +4189,9 @@ static int rt5659_i2c_probe(struct i2c_client *i2c, if (ret) dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + /* Enable IRQ output for GPIO1 pin any way */ + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP1_PIN_MASK, RT5659_GP1_PIN_IRQ); } return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659, diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h index d31c9e5bcec8..8f1aeef08489 100644 --- a/sound/soc/codecs/rt5659.h +++ b/sound/soc/codecs/rt5659.h @@ -180,9 +180,9 @@ #define RT5659_IRQ_CTRL_1 0x00b6 #define RT5659_IRQ_CTRL_2 0x00b7 #define RT5659_IRQ_CTRL_3 0x00b8 -#define RT5659_IRQ_CTRL_4 0x00b9 -#define RT5659_IRQ_CTRL_5 0x00ba -#define RT5659_IRQ_CTRL_6 0x00bb +#define RT5659_IRQ_CTRL_4 0x00ba +#define RT5659_IRQ_CTRL_5 0x00bb +#define RT5659_IRQ_CTRL_6 0x00bc #define RT5659_INT_ST_1 0x00be #define RT5659_INT_ST_2 0x00bf #define RT5659_GPIO_CTRL_1 0x00c0 @@ -1796,6 +1796,7 @@ struct rt5659_priv { struct gpio_desc *gpiod_reset; struct snd_soc_jack *hs_jack; struct delayed_work jack_detect_work; + struct clk *mclk; int sysclk; int sysclk_src; diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c new file mode 100644 index 000000000000..9f0933ced804 --- /dev/null +++ b/sound/soc/codecs/rt5660.c @@ -0,0 +1,1353 @@ +/* + * rt5660.c -- RT5660 ALSA SoC audio codec driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rl6231.h" +#include "rt5660.h" + +#define RT5660_DEVICE_ID 0x6338 + +#define RT5660_PR_RANGE_BASE (0xff + 1) +#define RT5660_PR_SPACING 0x100 + +#define RT5660_PR_BASE (RT5660_PR_RANGE_BASE + (0 * RT5660_PR_SPACING)) + +static const struct regmap_range_cfg rt5660_ranges[] = { + { .name = "PR", .range_min = RT5660_PR_BASE, + .range_max = RT5660_PR_BASE + 0xf3, + .selector_reg = RT5660_PRIV_INDEX, + .selector_mask = 0xff, + .selector_shift = 0x0, + .window_start = RT5660_PRIV_DATA, + .window_len = 0x1, }, +}; + +static const struct reg_sequence rt5660_patch[] = { + { RT5660_ALC_PGA_CTRL2, 0x44c3 }, + { RT5660_PR_BASE + 0x3d, 0x2600 }, +}; + +static const struct reg_default rt5660_reg[] = { + { 0x00, 0x0000 }, + { 0x01, 0xc800 }, + { 0x02, 0xc8c8 }, + { 0x0d, 0x1010 }, + { 0x0e, 0x1010 }, + { 0x19, 0xafaf }, + { 0x1c, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x27, 0x6060 }, + { 0x29, 0x8080 }, + { 0x2a, 0x4242 }, + { 0x2f, 0x0000 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x007f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x007f }, + { 0x45, 0xe000 }, + { 0x46, 0x003e }, + { 0x48, 0xf800 }, + { 0x4a, 0x0004 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x01ff }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x01ff }, + { 0x61, 0x0000 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c0 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x70, 0x8000 }, + { 0x73, 0x7000 }, + { 0x74, 0x3c00 }, + { 0x75, 0x2800 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x8c, 0x0228 }, + { 0x8d, 0xa000 }, + { 0x8e, 0x0000 }, + { 0x92, 0x0000 }, + { 0x93, 0x3000 }, + { 0xa1, 0x0059 }, + { 0xa2, 0x0001 }, + { 0xa3, 0x5c80 }, + { 0xa4, 0x0146 }, + { 0xa5, 0x1f1f }, + { 0xa6, 0x78c6 }, + { 0xa7, 0xe5ec }, + { 0xa8, 0xba61 }, + { 0xa9, 0x3c78 }, + { 0xaa, 0x8ae2 }, + { 0xab, 0xe5ec }, + { 0xac, 0xc600 }, + { 0xad, 0xba61 }, + { 0xae, 0x17ed }, + { 0xb0, 0x2080 }, + { 0xb1, 0x0000 }, + { 0xb3, 0x001f }, + { 0xb4, 0x020c }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xb7, 0x4000 }, + { 0xbb, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x0100 }, + { 0xc0, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xd3, 0xa220 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xe0, 0x8000 }, + { 0xe1, 0x0200 }, + { 0xe2, 0x8000 }, + { 0xe3, 0x0200 }, + { 0xe4, 0x0f20 }, + { 0xe5, 0x001f }, + { 0xe6, 0x020c }, + { 0xe7, 0x1f00 }, + { 0xe8, 0x0000 }, + { 0xe9, 0x4000 }, + { 0xea, 0x00a6 }, + { 0xeb, 0x04c3 }, + { 0xec, 0x27c8 }, + { 0xed, 0x7418 }, + { 0xee, 0xbf50 }, + { 0xef, 0x0045 }, + { 0xf0, 0x0007 }, + { 0xfa, 0x0000 }, + { 0xfd, 0x0000 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6338 }, +}; + +static bool rt5660_volatile_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++) + if ((reg >= rt5660_ranges[i].window_start && + reg <= rt5660_ranges[i].window_start + + rt5660_ranges[i].window_len) || + (reg >= rt5660_ranges[i].range_min && + reg <= rt5660_ranges[i].range_max)) + return true; + + switch (reg) { + case RT5660_RESET: + case RT5660_PRIV_DATA: + case RT5660_EQ_CTRL1: + case RT5660_IRQ_CTRL2: + case RT5660_INT_IRQ_ST: + case RT5660_VENDOR_ID: + case RT5660_VENDOR_ID1: + case RT5660_VENDOR_ID2: + return true; + default: + return false; + } +} + +static bool rt5660_readable_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5660_ranges); i++) + if ((reg >= rt5660_ranges[i].window_start && + reg <= rt5660_ranges[i].window_start + + rt5660_ranges[i].window_len) || + (reg >= rt5660_ranges[i].range_min && + reg <= rt5660_ranges[i].range_max)) + return true; + + switch (reg) { + case RT5660_RESET: + case RT5660_SPK_VOL: + case RT5660_LOUT_VOL: + case RT5660_IN1_IN2: + case RT5660_IN3_IN4: + case RT5660_DAC1_DIG_VOL: + case RT5660_STO1_ADC_DIG_VOL: + case RT5660_ADC_BST_VOL1: + case RT5660_STO1_ADC_MIXER: + case RT5660_AD_DA_MIXER: + case RT5660_STO_DAC_MIXER: + case RT5660_DIG_INF1_DATA: + case RT5660_REC_L1_MIXER: + case RT5660_REC_L2_MIXER: + case RT5660_REC_R1_MIXER: + case RT5660_REC_R2_MIXER: + case RT5660_LOUT_MIXER: + case RT5660_SPK_MIXER: + case RT5660_SPO_MIXER: + case RT5660_SPO_CLSD_RATIO: + case RT5660_OUT_L_GAIN1: + case RT5660_OUT_L_GAIN2: + case RT5660_OUT_L1_MIXER: + case RT5660_OUT_R_GAIN1: + case RT5660_OUT_R_GAIN2: + case RT5660_OUT_R1_MIXER: + case RT5660_PWR_DIG1: + case RT5660_PWR_DIG2: + case RT5660_PWR_ANLG1: + case RT5660_PWR_ANLG2: + case RT5660_PWR_MIXER: + case RT5660_PWR_VOL: + case RT5660_PRIV_INDEX: + case RT5660_PRIV_DATA: + case RT5660_I2S1_SDP: + case RT5660_ADDA_CLK1: + case RT5660_ADDA_CLK2: + case RT5660_DMIC_CTRL1: + case RT5660_GLB_CLK: + case RT5660_PLL_CTRL1: + case RT5660_PLL_CTRL2: + case RT5660_CLSD_AMP_OC_CTRL: + case RT5660_CLSD_AMP_CTRL: + case RT5660_LOUT_AMP_CTRL: + case RT5660_SPK_AMP_SPKVDD: + case RT5660_MICBIAS: + case RT5660_CLSD_OUT_CTRL1: + case RT5660_CLSD_OUT_CTRL2: + case RT5660_DIPOLE_MIC_CTRL1: + case RT5660_DIPOLE_MIC_CTRL2: + case RT5660_DIPOLE_MIC_CTRL3: + case RT5660_DIPOLE_MIC_CTRL4: + case RT5660_DIPOLE_MIC_CTRL5: + case RT5660_DIPOLE_MIC_CTRL6: + case RT5660_DIPOLE_MIC_CTRL7: + case RT5660_DIPOLE_MIC_CTRL8: + case RT5660_DIPOLE_MIC_CTRL9: + case RT5660_DIPOLE_MIC_CTRL10: + case RT5660_DIPOLE_MIC_CTRL11: + case RT5660_DIPOLE_MIC_CTRL12: + case RT5660_EQ_CTRL1: + case RT5660_EQ_CTRL2: + case RT5660_DRC_AGC_CTRL1: + case RT5660_DRC_AGC_CTRL2: + case RT5660_DRC_AGC_CTRL3: + case RT5660_DRC_AGC_CTRL4: + case RT5660_DRC_AGC_CTRL5: + case RT5660_JD_CTRL: + case RT5660_IRQ_CTRL1: + case RT5660_IRQ_CTRL2: + case RT5660_INT_IRQ_ST: + case RT5660_GPIO_CTRL1: + case RT5660_GPIO_CTRL2: + case RT5660_WIND_FILTER_CTRL1: + case RT5660_SV_ZCD1: + case RT5660_SV_ZCD2: + case RT5660_DRC1_LM_CTRL1: + case RT5660_DRC1_LM_CTRL2: + case RT5660_DRC2_LM_CTRL1: + case RT5660_DRC2_LM_CTRL2: + case RT5660_MULTI_DRC_CTRL: + case RT5660_DRC2_CTRL1: + case RT5660_DRC2_CTRL2: + case RT5660_DRC2_CTRL3: + case RT5660_DRC2_CTRL4: + case RT5660_DRC2_CTRL5: + case RT5660_ALC_PGA_CTRL1: + case RT5660_ALC_PGA_CTRL2: + case RT5660_ALC_PGA_CTRL3: + case RT5660_ALC_PGA_CTRL4: + case RT5660_ALC_PGA_CTRL5: + case RT5660_ALC_PGA_CTRL6: + case RT5660_ALC_PGA_CTRL7: + case RT5660_GEN_CTRL1: + case RT5660_GEN_CTRL2: + case RT5660_GEN_CTRL3: + case RT5660_VENDOR_ID: + case RT5660_VENDOR_ID1: + case RT5660_VENDOR_ID2: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(rt5660_out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_dac_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_adc_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(rt5660_bst_tlv, -1200, 75, 0); + +static const struct snd_kcontrol_new rt5660_snd_controls[] = { + /* Speaker Output Volume */ + SOC_SINGLE("Speaker Playback Switch", RT5660_SPK_VOL, RT5660_L_MUTE_SFT, + 1, 1), + SOC_SINGLE_TLV("Speaker Playback Volume", RT5660_SPK_VOL, + RT5660_L_VOL_SFT, 39, 1, rt5660_out_vol_tlv), + + /* OUTPUT Control */ + SOC_DOUBLE("OUT Playback Switch", RT5660_LOUT_VOL, RT5660_L_MUTE_SFT, + RT5660_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("OUT Playback Volume", RT5660_LOUT_VOL, RT5660_L_VOL_SFT, + RT5660_R_VOL_SFT, 39, 1, rt5660_out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5660_DAC1_DIG_VOL, + RT5660_DAC_L1_VOL_SFT, RT5660_DAC_R1_VOL_SFT, 87, 0, + rt5660_dac_vol_tlv), + + /* IN1/IN2/IN3 Control */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT1, 69, + 0, rt5660_bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5660_IN1_IN2, RT5660_BST_SFT2, 69, + 0, rt5660_bst_tlv), + SOC_SINGLE_TLV("IN3 Boost Volume", RT5660_IN3_IN4, RT5660_BST_SFT3, 69, + 0, rt5660_bst_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5660_STO1_ADC_DIG_VOL, + RT5660_L_MUTE_SFT, RT5660_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5660_STO1_ADC_DIG_VOL, + RT5660_ADC_L_VOL_SFT, RT5660_ADC_R_VOL_SFT, 63, 0, + rt5660_adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5660_ADC_BST_VOL1, + RT5660_STO1_ADC_L_BST_SFT, RT5660_STO1_ADC_R_BST_SFT, 3, 0, + rt5660_adc_bst_tlv), +}; + +/** + * rt5660_set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + */ +static int rt5660_set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + int idx, rate; + + rate = rt5660->sysclk / rl6231_get_pre_div(rt5660->regmap, + RT5660_ADDA_CLK1, RT5660_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rate); + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else + snd_soc_update_bits(codec, RT5660_DMIC_CTRL1, + RT5660_DMIC_CLK_MASK, idx << RT5660_DMIC_CLK_SFT); + + return idx; +} + +static int rt5660_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(codec, RT5660_GLB_CLK); + val &= RT5660_SCLK_SRC_MASK; + if (val == RT5660_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5660_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5660_STO1_ADC_MIXER, + RT5660_M_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER, + RT5660_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER, + RT5660_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5660_AD_DA_MIXER, + RT5660_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5660_AD_DA_MIXER, + RT5660_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_R1_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5660_STO_DAC_MIXER, + RT5660_M_DAC_L1_STO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5660_rec_l_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_L2_MIXER, + RT5660_M_BST3_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_L2_MIXER, + RT5660_M_BST2_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_L2_MIXER, + RT5660_M_BST1_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("OUT MIXL Switch", RT5660_REC_L2_MIXER, + RT5660_M_OM_L_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_rec_r_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_REC_R2_MIXER, + RT5660_M_BST3_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5660_REC_R2_MIXER, + RT5660_M_BST2_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_REC_R2_MIXER, + RT5660_M_BST1_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("OUT MIXR Switch", RT5660_REC_R2_MIXER, + RT5660_M_OM_R_RM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_spk_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_SPK_MIXER, + RT5660_M_BST3_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPK_MIXER, + RT5660_M_BST1_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_SPK_MIXER, + RT5660_M_DACL_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RT5660_SPK_MIXER, + RT5660_M_DACR_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIXL Switch", RT5660_SPK_MIXER, + RT5660_M_OM_L_SM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_out_l_mix[] = { + SOC_DAPM_SINGLE("BST3 Switch", RT5660_OUT_L1_MIXER, + RT5660_M_BST3_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_L1_MIXER, + RT5660_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_L1_MIXER, + RT5660_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIXL Switch", RT5660_OUT_L1_MIXER, + RT5660_M_RM_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_L1_MIXER, + RT5660_M_DAC_R_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_L1_MIXER, + RT5660_M_DAC_L_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5660_OUT_R1_MIXER, + RT5660_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_OUT_R1_MIXER, + RT5660_M_BST1_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIXR Switch", RT5660_OUT_R1_MIXER, + RT5660_M_RM_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DACR Switch", RT5660_OUT_R1_MIXER, + RT5660_M_DAC_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_OUT_R1_MIXER, + RT5660_M_DAC_L_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_spo_mix[] = { + SOC_DAPM_SINGLE("DACR Switch", RT5660_SPO_MIXER, + RT5660_M_DAC_R_SPM_SFT, 1, 1), + SOC_DAPM_SINGLE("DACL Switch", RT5660_SPO_MIXER, + RT5660_M_DAC_L_SPM_SFT, 1, 1), + SOC_DAPM_SINGLE("SPKVOL Switch", RT5660_SPO_MIXER, + RT5660_M_SV_SPM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5660_SPO_MIXER, + RT5660_M_BST1_SPM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5660_lout_mix[] = { + SOC_DAPM_SINGLE("DAC Switch", RT5660_LOUT_MIXER, + RT5660_M_DAC1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTMIX Switch", RT5660_LOUT_MIXER, + RT5660_M_LOVOL_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new spk_vol_control = + SOC_DAPM_SINGLE("Switch", RT5660_SPK_VOL, + RT5660_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_l_vol_control = + SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL, + RT5660_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_vol_control = + SOC_DAPM_SINGLE("Switch", RT5660_LOUT_VOL, + RT5660_VOL_R_SFT, 1, 1); + +/* Interface data select */ +static const char * const rt5660_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static const SOC_ENUM_SINGLE_DECL(rt5660_if1_dac_enum, + RT5660_DIG_INF1_DATA, RT5660_IF1_DAC_IN_SFT, rt5660_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5660_if1_adc_enum, + RT5660_DIG_INF1_DATA, RT5660_IF1_ADC_IN_SFT, rt5660_data_select); + +static const struct snd_kcontrol_new rt5660_if1_dac_swap_mux = + SOC_DAPM_ENUM("IF1 DAC Swap Source", rt5660_if1_dac_enum); + +static const struct snd_kcontrol_new rt5660_if1_adc_swap_mux = + SOC_DAPM_ENUM("IF1 ADC Swap Source", rt5660_if1_adc_enum); + +static int rt5660_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL, + RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK, + RT5660_LOUT_CO_EN | RT5660_LOUT_CB_PU); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5660_LOUT_AMP_CTRL, + RT5660_LOUT_CO_MASK | RT5660_LOUT_CB_MASK, + RT5660_LOUT_CO_DIS | RT5660_LOUT_CB_PD); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5660_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5660_PWR_ANLG1, + RT5660_PWR_LDO2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL1", RT5660_PWR_ANLG2, + RT5660_PWR_PLL_BIT, 0, NULL, 0), + + /* MICBIAS */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5660_PWR_ANLG2, + RT5660_PWR_MB1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5660_PWR_ANLG2, + RT5660_PWR_MB2_BIT, 0, NULL, 0), + + /* Input Side */ + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN3P"), + SND_SOC_DAPM_INPUT("IN3N"), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + rt5660_set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC Power", RT5660_DMIC_CTRL1, + RT5660_DMIC_1_EN_SFT, 0, NULL, 0), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", RT5660_PWR_ANLG2, RT5660_PWR_BST1_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("BST2", RT5660_PWR_ANLG2, RT5660_PWR_BST2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("BST3", RT5660_PWR_ANLG2, RT5660_PWR_BST3_BIT, 0, + NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL", RT5660_PWR_MIXER, RT5660_PWR_RM_L_BIT, + 0, rt5660_rec_l_mix, ARRAY_SIZE(rt5660_rec_l_mix)), + SND_SOC_DAPM_MIXER("RECMIXR", RT5660_PWR_MIXER, RT5660_PWR_RM_R_BIT, + 0, rt5660_rec_r_mix, ARRAY_SIZE(rt5660_rec_r_mix)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC L power", RT5660_PWR_DIG1, + RT5660_PWR_ADC_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC R power", RT5660_PWR_DIG1, + RT5660_PWR_ADC_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC clock", RT5660_PR_BASE + RT5660_CHOP_DAC_ADC, + 12, 0, NULL, 0), + + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("adc stereo1 filter", RT5660_PWR_DIG2, + RT5660_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5660_sto1_adc_l_mix, ARRAY_SIZE(rt5660_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5660_sto1_adc_r_mix, ARRAY_SIZE(rt5660_sto1_adc_r_mix)), + + /* ADC */ + SND_SOC_DAPM_ADC("Stereo1 ADC MIXL", NULL, RT5660_STO1_ADC_DIG_VOL, + RT5660_L_MUTE_SFT, 1), + SND_SOC_DAPM_ADC("Stereo1 ADC MIXR", NULL, RT5660_STO1_ADC_DIG_VOL, + RT5660_R_MUTE_SFT, 1), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5660_PWR_DIG1, RT5660_PWR_I2S1_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("IF1 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5660_if1_dac_swap_mux), + SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("IF1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5660_if1_adc_swap_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, rt5660_dac_l_mix, + ARRAY_SIZE(rt5660_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, rt5660_dac_r_mix, + ARRAY_SIZE(rt5660_dac_r_mix)), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5660_PWR_DIG2, + RT5660_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5660_sto_dac_l_mix, ARRAY_SIZE(rt5660_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5660_sto_dac_r_mix, ARRAY_SIZE(rt5660_sto_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, RT5660_PWR_DIG1, + RT5660_PWR_DAC_L1_BIT, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, RT5660_PWR_DIG1, + RT5660_PWR_DAC_R1_BIT, 0), + + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("SPK MIX", RT5660_PWR_MIXER, RT5660_PWR_SM_BIT, + 0, rt5660_spk_mix, ARRAY_SIZE(rt5660_spk_mix)), + SND_SOC_DAPM_MIXER("OUT MIXL", RT5660_PWR_MIXER, RT5660_PWR_OM_L_BIT, + 0, rt5660_out_l_mix, ARRAY_SIZE(rt5660_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5660_PWR_MIXER, RT5660_PWR_OM_R_BIT, + 0, rt5660_out_r_mix, ARRAY_SIZE(rt5660_out_r_mix)), + + /* Output Volume */ + SND_SOC_DAPM_SWITCH("SPKVOL", RT5660_PWR_VOL, + RT5660_PWR_SV_BIT, 0, &spk_vol_control), + SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("LOUTVOL", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_SWITCH("LOUTVOL L", SND_SOC_NOPM, + RT5660_PWR_LV_L_BIT, 0, &lout_l_vol_control), + SND_SOC_DAPM_SWITCH("LOUTVOL R", SND_SOC_NOPM, + RT5660_PWR_LV_R_BIT, 0, &lout_r_vol_control), + + /* HPO/LOUT/Mono Mixer */ + SND_SOC_DAPM_MIXER("SPO MIX", SND_SOC_NOPM, 0, + 0, rt5660_spo_mix, ARRAY_SIZE(rt5660_spo_mix)), + SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, + rt5660_lout_mix, ARRAY_SIZE(rt5660_lout_mix)), + SND_SOC_DAPM_SUPPLY("VREF HP", RT5660_GEN_CTRL1, + RT5660_PWR_VREF_HP_SFT, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("LOUT amp", 1, RT5660_PWR_ANLG1, + RT5660_PWR_HA_BIT, 0, rt5660_lout_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("SPK amp", 1, RT5660_PWR_DIG1, + RT5660_PWR_CLS_D_BIT, 0, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("SPO"), +}; + +static const struct snd_soc_dapm_route rt5660_dapm_routes[] = { + { "MICBIAS1", NULL, "LDO2" }, + { "MICBIAS2", NULL, "LDO2" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST2", NULL, "IN2P" }, + { "BST3", NULL, "IN3P" }, + { "BST3", NULL, "IN3N" }, + + { "RECMIXL", "BST3 Switch", "BST3" }, + { "RECMIXL", "BST2 Switch", "BST2" }, + { "RECMIXL", "BST1 Switch", "BST1" }, + { "RECMIXL", "OUT MIXL Switch", "OUT MIXL" }, + + { "RECMIXR", "BST3 Switch", "BST3" }, + { "RECMIXR", "BST2 Switch", "BST2" }, + { "RECMIXR", "BST1 Switch", "BST1" }, + { "RECMIXR", "OUT MIXR Switch", "OUT MIXR" }, + + { "ADC L", NULL, "RECMIXL" }, + { "ADC L", NULL, "ADC L power" }, + { "ADC L", NULL, "ADC clock" }, + { "ADC R", NULL, "RECMIXR" }, + { "ADC R", NULL, "ADC R power" }, + { "ADC R", NULL, "ADC clock" }, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC L1", NULL, "DMIC Power"}, + {"DMIC R1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC Power"}, + + { "Sto1 ADC MIXL", "ADC1 Switch", "ADC L" }, + { "Sto1 ADC MIXL", "ADC2 Switch", "DMIC L1" }, + { "Sto1 ADC MIXR", "ADC1 Switch", "ADC R" }, + { "Sto1 ADC MIXR", "ADC2 Switch", "DMIC R1" }, + + { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" }, + { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" }, + { "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + + { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" }, + { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" }, + { "adc stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + + { "IF1 ADC", NULL, "Stereo1 ADC MIXL" }, + { "IF1 ADC", NULL, "Stereo1 ADC MIXR" }, + { "IF1 ADC", NULL, "I2S1" }, + + { "IF1 ADC Swap Mux", "L/R", "IF1 ADC" }, + { "IF1 ADC Swap Mux", "R/L", "IF1 ADC" }, + { "IF1 ADC Swap Mux", "L/L", "IF1 ADC" }, + { "IF1 ADC Swap Mux", "R/R", "IF1 ADC" }, + { "AIF1TX", NULL, "IF1 ADC Swap Mux" }, + + { "IF1 DAC", NULL, "AIF1RX" }, + { "IF1 DAC", NULL, "I2S1" }, + + { "IF1 DAC Swap Mux", "L/R", "IF1 DAC" }, + { "IF1 DAC Swap Mux", "R/L", "IF1 DAC" }, + { "IF1 DAC Swap Mux", "L/L", "IF1 DAC" }, + { "IF1 DAC Swap Mux", "R/R", "IF1 DAC" }, + + { "IF1 DAC L", NULL, "IF1 DAC Swap Mux" }, + { "IF1 DAC R", NULL, "IF1 DAC Swap Mux" }, + + { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL" }, + { "DAC1 MIXL", "DAC1 Switch", "IF1 DAC L" }, + { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR" }, + { "DAC1 MIXR", "DAC1 Switch", "IF1 DAC R" }, + + { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXL", NULL, "dac stereo1 filter" }, + { "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXR", NULL, "dac stereo1 filter" }, + { "dac stereo1 filter", NULL, "PLL1", rt5660_is_sys_clk_from_pll }, + + { "DAC L1", NULL, "Stereo DAC MIXL" }, + { "DAC R1", NULL, "Stereo DAC MIXR" }, + + { "SPK MIX", "BST3 Switch", "BST3" }, + { "SPK MIX", "BST1 Switch", "BST1" }, + { "SPK MIX", "DACL Switch", "DAC L1" }, + { "SPK MIX", "DACR Switch", "DAC R1" }, + { "SPK MIX", "OUTMIXL Switch", "OUT MIXL" }, + + { "OUT MIXL", "BST3 Switch", "BST3" }, + { "OUT MIXL", "BST2 Switch", "BST2" }, + { "OUT MIXL", "BST1 Switch", "BST1" }, + { "OUT MIXL", "RECMIXL Switch", "RECMIXL" }, + { "OUT MIXL", "DACR Switch", "DAC R1" }, + { "OUT MIXL", "DACL Switch", "DAC L1" }, + + { "OUT MIXR", "BST2 Switch", "BST2" }, + { "OUT MIXR", "BST1 Switch", "BST1" }, + { "OUT MIXR", "RECMIXR Switch", "RECMIXR" }, + { "OUT MIXR", "DACR Switch", "DAC R1" }, + { "OUT MIXR", "DACL Switch", "DAC L1" }, + + { "SPO MIX", "DACR Switch", "DAC R1" }, + { "SPO MIX", "DACL Switch", "DAC L1" }, + { "SPO MIX", "SPKVOL Switch", "SPKVOL" }, + { "SPO MIX", "BST1 Switch", "BST1" }, + + { "SPKVOL", "Switch", "SPK MIX" }, + { "LOUTVOL L", "Switch", "OUT MIXL" }, + { "LOUTVOL R", "Switch", "OUT MIXR" }, + + { "LOUTVOL", NULL, "LOUTVOL L" }, + { "LOUTVOL", NULL, "LOUTVOL R" }, + + { "DAC 1", NULL, "DAC L1" }, + { "DAC 1", NULL, "DAC R1" }, + + { "LOUT MIX", "DAC Switch", "DAC 1" }, + { "LOUT MIX", "OUTMIX Switch", "LOUTVOL" }, + + { "LOUT amp", NULL, "LOUT MIX" }, + { "LOUT amp", NULL, "VREF HP" }, + { "LOUTL", NULL, "LOUT amp" }, + { "LOUTR", NULL, "LOUT amp" }, + + { "SPK amp", NULL, "SPO MIX" }, + { "SPO", NULL, "SPK amp" }, +}; + +static int rt5660_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, bclk_ms, frame_size; + + rt5660->lrck[dai->id] = params_rate(params); + pre_div = rl6231_get_clk_info(rt5660->sysclk, rt5660->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5660->lrck[dai->id], dai->id); + return -EINVAL; + } + + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return frame_size; + } + + if (frame_size > 32) + bclk_ms = 1; + else + bclk_ms = 0; + + rt5660->bclk[dai->id] = rt5660->lrck[dai->id] * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5660->bclk[dai->id], rt5660->lrck[dai->id]); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= RT5660_I2S_DL_20; + break; + case 24: + val_len |= RT5660_I2S_DL_24; + break; + case 8: + val_len |= RT5660_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5660_AIF1: + mask_clk = RT5660_I2S_BCLK_MS1_MASK | RT5660_I2S_PD1_MASK; + val_clk = bclk_ms << RT5660_I2S_BCLK_MS1_SFT | + pre_div << RT5660_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5660_I2S1_SDP, RT5660_I2S_DL_MASK, + val_len); + snd_soc_update_bits(codec, RT5660_ADDA_CLK1, mask_clk, val_clk); + break; + + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5660->master[dai->id] = 1; + break; + + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5660_I2S_MS_S; + rt5660->master[dai->id] = 0; + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5660_I2S_BP_INV; + break; + + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5660_I2S_DF_LEFT; + break; + + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5660_I2S_DF_PCM_A; + break; + + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5660_I2S_DF_PCM_B; + break; + + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5660_AIF1: + snd_soc_update_bits(codec, RT5660_I2S1_SDP, + RT5660_I2S_MS_MASK | RT5660_I2S_BP_MASK | + RT5660_I2S_DF_MASK, reg_val); + break; + + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + return 0; +} + +static int rt5660_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5660->sysclk && clk_id == rt5660->sysclk_src) + return 0; + + switch (clk_id) { + case RT5660_SCLK_S_MCLK: + reg_val |= RT5660_SCLK_SRC_MCLK; + break; + + case RT5660_SCLK_S_PLL1: + reg_val |= RT5660_SCLK_SRC_PLL1; + break; + + case RT5660_SCLK_S_RCCLK: + reg_val |= RT5660_SCLK_SRC_RCCLK; + break; + + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5660_GLB_CLK, RT5660_SCLK_SRC_MASK, + reg_val); + + rt5660->sysclk = freq; + rt5660->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5660_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (source == rt5660->pll_src && freq_in == rt5660->pll_in && + freq_out == rt5660->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5660->pll_in = 0; + rt5660->pll_out = 0; + snd_soc_update_bits(codec, RT5660_GLB_CLK, + RT5660_SCLK_SRC_MASK, RT5660_SCLK_SRC_MCLK); + return 0; + } + + switch (source) { + case RT5660_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5660_GLB_CLK, + RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_MCLK); + break; + + case RT5660_PLL1_S_BCLK: + snd_soc_update_bits(codec, RT5660_GLB_CLK, + RT5660_PLL1_SRC_MASK, RT5660_PLL1_SRC_BCLK1); + break; + + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5660_PLL_CTRL1, + pll_code.n_code << RT5660_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5660_PLL_CTRL2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5660_PLL_M_SFT | + pll_code.m_bp << RT5660_PLL_M_BP_SFT); + + rt5660->pll_in = freq_in; + rt5660->pll_out = freq_out; + rt5660->pll_src = source; + + return 0; +} + +static int rt5660_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + + case SND_SOC_BIAS_PREPARE: + snd_soc_update_bits(codec, RT5660_GEN_CTRL1, + RT5660_DIG_GATE_CTRL, RT5660_DIG_GATE_CTRL); + + if (IS_ERR(rt5660->mclk)) + break; + + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { + clk_disable_unprepare(rt5660->mclk); + } else { + ret = clk_prepare_enable(rt5660->mclk); + if (ret) + return ret; + } + break; + + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, RT5660_PWR_ANLG1, + RT5660_PWR_VREF1 | RT5660_PWR_MB | + RT5660_PWR_BG | RT5660_PWR_VREF2, + RT5660_PWR_VREF1 | RT5660_PWR_MB | + RT5660_PWR_BG | RT5660_PWR_VREF2); + usleep_range(10000, 15000); + snd_soc_update_bits(codec, RT5660_PWR_ANLG1, + RT5660_PWR_FV1 | RT5660_PWR_FV2, + RT5660_PWR_FV1 | RT5660_PWR_FV2); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, RT5660_GEN_CTRL1, + RT5660_DIG_GATE_CTRL, 0); + break; + + default: + break; + } + + return 0; +} + +static int rt5660_probe(struct snd_soc_codec *codec) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + + rt5660->codec = codec; + + return 0; +} + +static int rt5660_remove(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, RT5660_RESET, 0); +} + +#ifdef CONFIG_PM +static int rt5660_suspend(struct snd_soc_codec *codec) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5660->regmap, true); + regcache_mark_dirty(rt5660->regmap); + + return 0; +} + +static int rt5660_resume(struct snd_soc_codec *codec) +{ + struct rt5660_priv *rt5660 = snd_soc_codec_get_drvdata(codec); + + if (rt5660->pdata.poweroff_codec_in_suspend) + usleep_range(350000, 400000); + + regcache_cache_only(rt5660->regmap, false); + regcache_sync(rt5660->regmap); + + return 0; +} +#else +#define rt5660_suspend NULL +#define rt5660_resume NULL +#endif + +#define RT5660_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5660_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5660_aif_dai_ops = { + .hw_params = rt5660_hw_params, + .set_fmt = rt5660_set_dai_fmt, + .set_sysclk = rt5660_set_dai_sysclk, + .set_pll = rt5660_set_dai_pll, +}; + +static struct snd_soc_dai_driver rt5660_dai[] = { + { + .name = "rt5660-aif1", + .id = RT5660_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5660_STEREO_RATES, + .formats = RT5660_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5660_STEREO_RATES, + .formats = RT5660_FORMATS, + }, + .ops = &rt5660_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5660 = { + .probe = rt5660_probe, + .remove = rt5660_remove, + .suspend = rt5660_suspend, + .resume = rt5660_resume, + .set_bias_level = rt5660_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = rt5660_snd_controls, + .num_controls = ARRAY_SIZE(rt5660_snd_controls), + .dapm_widgets = rt5660_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5660_dapm_widgets), + .dapm_routes = rt5660_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5660_dapm_routes), + }, +}; + +static const struct regmap_config rt5660_regmap = { + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + + .max_register = RT5660_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5660_ranges) * + RT5660_PR_SPACING), + .volatile_reg = rt5660_volatile_register, + .readable_reg = rt5660_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5660_reg, + .num_reg_defaults = ARRAY_SIZE(rt5660_reg), + .ranges = rt5660_ranges, + .num_ranges = ARRAY_SIZE(rt5660_ranges), +}; + +static const struct i2c_device_id rt5660_i2c_id[] = { + { "rt5660", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id); + +static const struct of_device_id rt5660_of_match[] = { + { .compatible = "realtek,rt5660", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5660_of_match); + +static const struct acpi_device_id rt5660_acpi_match[] = { + { "10EC5660", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match); + +static int rt5660_parse_dt(struct rt5660_priv *rt5660, struct device *dev) +{ + rt5660->pdata.in1_diff = device_property_read_bool(dev, + "realtek,in1-differential"); + rt5660->pdata.in3_diff = device_property_read_bool(dev, + "realtek,in3-differential"); + rt5660->pdata.poweroff_codec_in_suspend = device_property_read_bool(dev, + "realtek,poweroff-in-suspend"); + device_property_read_u32(dev, "realtek,dmic1-data-pin", + &rt5660->pdata.dmic1_data_pin); + + return 0; +} + +static int rt5660_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5660_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5660_priv *rt5660; + int ret; + unsigned int val; + + rt5660 = devm_kzalloc(&i2c->dev, sizeof(struct rt5660_priv), + GFP_KERNEL); + + if (rt5660 == NULL) + return -ENOMEM; + + /* Check if MCLK provided */ + rt5660->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (PTR_ERR(rt5660->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + i2c_set_clientdata(i2c, rt5660); + + if (pdata) + rt5660->pdata = *pdata; + else if (i2c->dev.of_node) + rt5660_parse_dt(rt5660, &i2c->dev); + + rt5660->regmap = devm_regmap_init_i2c(i2c, &rt5660_regmap); + if (IS_ERR(rt5660->regmap)) { + ret = PTR_ERR(rt5660->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5660->regmap, RT5660_VENDOR_ID2, &val); + if (val != RT5660_DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt5660\n", val); + return -ENODEV; + } + + regmap_write(rt5660->regmap, RT5660_RESET, 0); + + ret = regmap_register_patch(rt5660->regmap, rt5660_patch, + ARRAY_SIZE(rt5660_patch)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + if (rt5660->pdata.dmic1_data_pin) { + regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1, + RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL); + + if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_GPIO2) + regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1, + RT5660_SEL_DMIC_DATA_MASK, + RT5660_SEL_DMIC_DATA_GPIO2); + else if (rt5660->pdata.dmic1_data_pin == RT5660_DMIC1_DATA_IN1P) + regmap_update_bits(rt5660->regmap, RT5660_DMIC_CTRL1, + RT5660_SEL_DMIC_DATA_MASK, + RT5660_SEL_DMIC_DATA_IN1P); + } + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5660, + rt5660_dai, ARRAY_SIZE(rt5660_dai)); +} + +static int rt5660_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static struct i2c_driver rt5660_i2c_driver = { + .driver = { + .name = "rt5660", + .acpi_match_table = ACPI_PTR(rt5660_acpi_match), + .of_match_table = of_match_ptr(rt5660_of_match), + }, + .probe = rt5660_i2c_probe, + .remove = rt5660_i2c_remove, + .id_table = rt5660_i2c_id, +}; +module_i2c_driver(rt5660_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5660 driver"); +MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h new file mode 100644 index 000000000000..6cdb9269ec9e --- /dev/null +++ b/sound/soc/codecs/rt5660.h @@ -0,0 +1,847 @@ +/* + * rt5660.h -- RT5660 ALSA SoC audio driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Oder Chiou <oder_chiou@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _RT5660_H +#define _RT5660_H + +#include <linux/clk.h> +#include <sound/rt5660.h> + +/* Info */ +#define RT5660_RESET 0x00 +#define RT5660_VENDOR_ID 0xfd +#define RT5660_VENDOR_ID1 0xfe +#define RT5660_VENDOR_ID2 0xff +/* I/O - Output */ +#define RT5660_SPK_VOL 0x01 +#define RT5660_LOUT_VOL 0x02 +/* I/O - Input */ +#define RT5660_IN1_IN2 0x0d +#define RT5660_IN3_IN4 0x0e +/* I/O - ADC/DAC/DMIC */ +#define RT5660_DAC1_DIG_VOL 0x19 +#define RT5660_STO1_ADC_DIG_VOL 0x1c +#define RT5660_ADC_BST_VOL1 0x1e +/* Mixer - D-D */ +#define RT5660_STO1_ADC_MIXER 0x27 +#define RT5660_AD_DA_MIXER 0x29 +#define RT5660_STO_DAC_MIXER 0x2a +#define RT5660_DIG_INF1_DATA 0x2f +/* Mixer - ADC */ +#define RT5660_REC_L1_MIXER 0x3b +#define RT5660_REC_L2_MIXER 0x3c +#define RT5660_REC_R1_MIXER 0x3d +#define RT5660_REC_R2_MIXER 0x3e +/* Mixer - DAC */ +#define RT5660_LOUT_MIXER 0x45 +#define RT5660_SPK_MIXER 0x46 +#define RT5660_SPO_MIXER 0x48 +#define RT5660_SPO_CLSD_RATIO 0x4a +#define RT5660_OUT_L_GAIN1 0x4d +#define RT5660_OUT_L_GAIN2 0x4e +#define RT5660_OUT_L1_MIXER 0x4f +#define RT5660_OUT_R_GAIN1 0x50 +#define RT5660_OUT_R_GAIN2 0x51 +#define RT5660_OUT_R1_MIXER 0x52 +/* Power */ +#define RT5660_PWR_DIG1 0x61 +#define RT5660_PWR_DIG2 0x62 +#define RT5660_PWR_ANLG1 0x63 +#define RT5660_PWR_ANLG2 0x64 +#define RT5660_PWR_MIXER 0x65 +#define RT5660_PWR_VOL 0x66 +/* Private Register Control */ +#define RT5660_PRIV_INDEX 0x6a +#define RT5660_PRIV_DATA 0x6c +/* Format - ADC/DAC */ +#define RT5660_I2S1_SDP 0x70 +#define RT5660_ADDA_CLK1 0x73 +#define RT5660_ADDA_CLK2 0x74 +#define RT5660_DMIC_CTRL1 0x75 +/* Function - Analog */ +#define RT5660_GLB_CLK 0x80 +#define RT5660_PLL_CTRL1 0x81 +#define RT5660_PLL_CTRL2 0x82 +#define RT5660_CLSD_AMP_OC_CTRL 0x8c +#define RT5660_CLSD_AMP_CTRL 0x8d +#define RT5660_LOUT_AMP_CTRL 0x8e +#define RT5660_SPK_AMP_SPKVDD 0x92 +#define RT5660_MICBIAS 0x93 +#define RT5660_CLSD_OUT_CTRL1 0xa1 +#define RT5660_CLSD_OUT_CTRL2 0xa2 +#define RT5660_DIPOLE_MIC_CTRL1 0xa3 +#define RT5660_DIPOLE_MIC_CTRL2 0xa4 +#define RT5660_DIPOLE_MIC_CTRL3 0xa5 +#define RT5660_DIPOLE_MIC_CTRL4 0xa6 +#define RT5660_DIPOLE_MIC_CTRL5 0xa7 +#define RT5660_DIPOLE_MIC_CTRL6 0xa8 +#define RT5660_DIPOLE_MIC_CTRL7 0xa9 +#define RT5660_DIPOLE_MIC_CTRL8 0xaa +#define RT5660_DIPOLE_MIC_CTRL9 0xab +#define RT5660_DIPOLE_MIC_CTRL10 0xac +#define RT5660_DIPOLE_MIC_CTRL11 0xad +#define RT5660_DIPOLE_MIC_CTRL12 0xae +/* Function - Digital */ +#define RT5660_EQ_CTRL1 0xb0 +#define RT5660_EQ_CTRL2 0xb1 +#define RT5660_DRC_AGC_CTRL1 0xb3 +#define RT5660_DRC_AGC_CTRL2 0xb4 +#define RT5660_DRC_AGC_CTRL3 0xb5 +#define RT5660_DRC_AGC_CTRL4 0xb6 +#define RT5660_DRC_AGC_CTRL5 0xb7 +#define RT5660_JD_CTRL 0xbb +#define RT5660_IRQ_CTRL1 0xbd +#define RT5660_IRQ_CTRL2 0xbe +#define RT5660_INT_IRQ_ST 0xbf +#define RT5660_GPIO_CTRL1 0xc0 +#define RT5660_GPIO_CTRL2 0xc2 +#define RT5660_WIND_FILTER_CTRL1 0xd3 +#define RT5660_SV_ZCD1 0xd9 +#define RT5660_SV_ZCD2 0xda +#define RT5660_DRC1_LM_CTRL1 0xe0 +#define RT5660_DRC1_LM_CTRL2 0xe1 +#define RT5660_DRC2_LM_CTRL1 0xe2 +#define RT5660_DRC2_LM_CTRL2 0xe3 +#define RT5660_MULTI_DRC_CTRL 0xe4 +#define RT5660_DRC2_CTRL1 0xe5 +#define RT5660_DRC2_CTRL2 0xe6 +#define RT5660_DRC2_CTRL3 0xe7 +#define RT5660_DRC2_CTRL4 0xe8 +#define RT5660_DRC2_CTRL5 0xe9 +#define RT5660_ALC_PGA_CTRL1 0xea +#define RT5660_ALC_PGA_CTRL2 0xeb +#define RT5660_ALC_PGA_CTRL3 0xec +#define RT5660_ALC_PGA_CTRL4 0xed +#define RT5660_ALC_PGA_CTRL5 0xee +#define RT5660_ALC_PGA_CTRL6 0xef +#define RT5660_ALC_PGA_CTRL7 0xf0 + +/* General Control */ +#define RT5660_GEN_CTRL1 0xfa +#define RT5660_GEN_CTRL2 0xfb +#define RT5660_GEN_CTRL3 0xfc + +/* Index of Codec Private Register definition */ +#define RT5660_CHOP_DAC_ADC 0x3d + +/* Global Definition */ +#define RT5660_L_MUTE (0x1 << 15) +#define RT5660_L_MUTE_SFT 15 +#define RT5660_VOL_L_MUTE (0x1 << 14) +#define RT5660_VOL_L_SFT 14 +#define RT5660_R_MUTE (0x1 << 7) +#define RT5660_R_MUTE_SFT 7 +#define RT5660_VOL_R_MUTE (0x1 << 6) +#define RT5660_VOL_R_SFT 6 +#define RT5660_L_VOL_MASK (0x3f << 8) +#define RT5660_L_VOL_SFT 8 +#define RT5660_R_VOL_MASK (0x3f) +#define RT5660_R_VOL_SFT 0 + +/* IN1 and IN2 Control (0x0d) */ +#define RT5660_IN_DF1 (0x1 << 15) +#define RT5660_IN_SFT1 15 +#define RT5660_BST_MASK1 (0x7f << 8) +#define RT5660_BST_SFT1 8 +#define RT5660_IN_DF2 (0x1 << 7) +#define RT5660_IN_SFT2 7 +#define RT5660_BST_MASK2 (0x7f << 0) +#define RT5660_BST_SFT2 0 + +/* IN3 and IN4 Control (0x0e) */ +#define RT5660_IN_DF3 (0x1 << 15) +#define RT5660_IN_SFT3 15 +#define RT5660_BST_MASK3 (0x7f << 8) +#define RT5660_BST_SFT3 8 +#define RT5660_IN_DF4 (0x1 << 7) +#define RT5660_IN_SFT4 7 +#define RT5660_BST_MASK4 (0x7f << 0) +#define RT5660_BST_SFT4 0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5660_DAC_L1_VOL_MASK (0x7f << 9) +#define RT5660_DAC_L1_VOL_SFT 9 +#define RT5660_DAC_R1_VOL_MASK (0x7f << 1) +#define RT5660_DAC_R1_VOL_SFT 1 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5660_ADC_L_VOL_MASK (0x3f << 9) +#define RT5660_ADC_L_VOL_SFT 9 +#define RT5660_ADC_R_VOL_MASK (0x3f << 1) +#define RT5660_ADC_R_VOL_SFT 1 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5660_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5660_STO1_ADC_L_BST_SFT 14 +#define RT5660_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5660_STO1_ADC_R_BST_SFT 12 + +/* Stereo ADC Mixer Control (0x27) */ +#define RT5660_M_ADC_L1 (0x1 << 14) +#define RT5660_M_ADC_L1_SFT 14 +#define RT5660_M_ADC_L2 (0x1 << 13) +#define RT5660_M_ADC_L2_SFT 13 +#define RT5660_M_ADC_R1 (0x1 << 6) +#define RT5660_M_ADC_R1_SFT 6 +#define RT5660_M_ADC_R2 (0x1 << 5) +#define RT5660_M_ADC_R2_SFT 5 + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5660_M_ADCMIX_L (0x1 << 15) +#define RT5660_M_ADCMIX_L_SFT 15 +#define RT5660_M_DAC1_L (0x1 << 14) +#define RT5660_M_DAC1_L_SFT 14 +#define RT5660_M_ADCMIX_R (0x1 << 7) +#define RT5660_M_ADCMIX_R_SFT 7 +#define RT5660_M_DAC1_R (0x1 << 6) +#define RT5660_M_DAC1_R_SFT 6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5660_M_DAC_L1 (0x1 << 14) +#define RT5660_M_DAC_L1_SFT 14 +#define RT5660_DAC_L1_STO_L_VOL_MASK (0x1 << 13) +#define RT5660_DAC_L1_STO_L_VOL_SFT 13 +#define RT5660_M_DAC_R1_STO_L (0x1 << 9) +#define RT5660_M_DAC_R1_STO_L_SFT 9 +#define RT5660_DAC_R1_STO_L_VOL_MASK (0x1 << 8) +#define RT5660_DAC_R1_STO_L_VOL_SFT 8 +#define RT5660_M_DAC_R1 (0x1 << 6) +#define RT5660_M_DAC_R1_SFT 6 +#define RT5660_DAC_R1_STO_R_VOL_MASK (0x1 << 5) +#define RT5660_DAC_R1_STO_R_VOL_SFT 5 +#define RT5660_M_DAC_L1_STO_R (0x1 << 1) +#define RT5660_M_DAC_L1_STO_R_SFT 1 +#define RT5660_DAC_L1_STO_R_VOL_MASK (0x1) +#define RT5660_DAC_L1_STO_R_VOL_SFT 0 + +/* Digital Interface Data Control (0x2f) */ +#define RT5660_IF1_DAC_IN_SEL (0x3 << 14) +#define RT5660_IF1_DAC_IN_SFT 14 +#define RT5660_IF1_ADC_IN_SEL (0x3 << 12) +#define RT5660_IF1_ADC_IN_SFT 12 + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5660_G_BST3_RM_L_MASK (0x7 << 4) +#define RT5660_G_BST3_RM_L_SFT 4 +#define RT5660_G_BST2_RM_L_MASK (0x7 << 1) +#define RT5660_G_BST2_RM_L_SFT 1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5660_G_BST1_RM_L_MASK (0x7 << 13) +#define RT5660_G_BST1_RM_L_SFT 13 +#define RT5660_G_OM_L_RM_L_MASK (0x7 << 10) +#define RT5660_G_OM_L_RM_L_SFT 10 +#define RT5660_M_BST3_RM_L (0x1 << 3) +#define RT5660_M_BST3_RM_L_SFT 3 +#define RT5660_M_BST2_RM_L (0x1 << 2) +#define RT5660_M_BST2_RM_L_SFT 2 +#define RT5660_M_BST1_RM_L (0x1 << 1) +#define RT5660_M_BST1_RM_L_SFT 1 +#define RT5660_M_OM_L_RM_L (0x1) +#define RT5660_M_OM_L_RM_L_SFT 0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5660_G_BST3_RM_R_MASK (0x7 << 4) +#define RT5660_G_BST3_RM_R_SFT 4 +#define RT5660_G_BST2_RM_R_MASK (0x7 << 1) +#define RT5660_G_BST2_RM_R_SFT 1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5660_G_BST1_RM_R_MASK (0x7 << 13) +#define RT5660_G_BST1_RM_R_SFT 13 +#define RT5660_G_OM_R_RM_R_MASK (0x7 << 10) +#define RT5660_G_OM_R_RM_R_SFT 10 +#define RT5660_M_BST3_RM_R (0x1 << 3) +#define RT5660_M_BST3_RM_R_SFT 3 +#define RT5660_M_BST2_RM_R (0x1 << 2) +#define RT5660_M_BST2_RM_R_SFT 2 +#define RT5660_M_BST1_RM_R (0x1 << 1) +#define RT5660_M_BST1_RM_R_SFT 1 +#define RT5660_M_OM_R_RM_R (0x1) +#define RT5660_M_OM_R_RM_R_SFT 0 + +/* LOUTMIX Control (0x45) */ +#define RT5660_M_DAC1_LM (0x1 << 14) +#define RT5660_M_DAC1_LM_SFT 14 +#define RT5660_M_LOVOL_M (0x1 << 13) +#define RT5660_M_LOVOL_LM_SFT 13 + +/* SPK Mixer Control (0x46) */ +#define RT5660_G_BST3_SM_MASK (0x3 << 14) +#define RT5660_G_BST3_SM_SFT 14 +#define RT5660_G_BST1_SM_MASK (0x3 << 12) +#define RT5660_G_BST1_SM_SFT 12 +#define RT5660_G_DACl_SM_MASK (0x3 << 10) +#define RT5660_G_DACl_SM_SFT 10 +#define RT5660_G_DACR_SM_MASK (0x3 << 8) +#define RT5660_G_DACR_SM_SFT 8 +#define RT5660_G_OM_L_SM_MASK (0x3 << 6) +#define RT5660_G_OM_L_SM_SFT 6 +#define RT5660_M_DACR_SM (0x1 << 5) +#define RT5660_M_DACR_SM_SFT 5 +#define RT5660_M_BST1_SM (0x1 << 4) +#define RT5660_M_BST1_SM_SFT 4 +#define RT5660_M_BST3_SM (0x1 << 3) +#define RT5660_M_BST3_SM_SFT 3 +#define RT5660_M_DACL_SM (0x1 << 2) +#define RT5660_M_DACL_SM_SFT 2 +#define RT5660_M_OM_L_SM (0x1 << 1) +#define RT5660_M_OM_L_SM_SFT 1 + +/* SPOMIX Control (0x48) */ +#define RT5660_M_DAC_R_SPM (0x1 << 14) +#define RT5660_M_DAC_R_SPM_SFT 14 +#define RT5660_M_DAC_L_SPM (0x1 << 13) +#define RT5660_M_DAC_L_SPM_SFT 13 +#define RT5660_M_SV_SPM (0x1 << 12) +#define RT5660_M_SV_SPM_SFT 12 +#define RT5660_M_BST1_SPM (0x1 << 11) +#define RT5660_M_BST1_SPM_SFT 11 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5660_G_BST3_OM_L_MASK (0x7 << 13) +#define RT5660_G_BST3_OM_L_SFT 13 +#define RT5660_G_BST2_OM_L_MASK (0x7 << 10) +#define RT5660_G_BST2_OM_L_SFT 10 +#define RT5660_G_BST1_OM_L_MASK (0x7 << 7) +#define RT5660_G_BST1_OM_L_SFT 7 +#define RT5660_G_RM_L_OM_L_MASK (0x7 << 1) +#define RT5660_G_RM_L_OM_L_SFT 1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5660_G_DAC_R1_OM_L_MASK (0x7 << 10) +#define RT5660_G_DAC_R1_OM_L_SFT 10 +#define RT5660_G_DAC_L1_OM_L_MASK (0x7 << 7) +#define RT5660_G_DAC_L1_OM_L_SFT 7 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5660_M_BST3_OM_L (0x1 << 5) +#define RT5660_M_BST3_OM_L_SFT 5 +#define RT5660_M_BST2_OM_L (0x1 << 4) +#define RT5660_M_BST2_OM_L_SFT 4 +#define RT5660_M_BST1_OM_L (0x1 << 3) +#define RT5660_M_BST1_OM_L_SFT 3 +#define RT5660_M_RM_L_OM_L (0x1 << 2) +#define RT5660_M_RM_L_OM_L_SFT 2 +#define RT5660_M_DAC_R_OM_L (0x1 << 1) +#define RT5660_M_DAC_R_OM_L_SFT 1 +#define RT5660_M_DAC_L_OM_L (0x1) +#define RT5660_M_DAC_L_OM_L_SFT 0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5660_G_BST2_OM_R_MASK (0x7 << 10) +#define RT5660_G_BST2_OM_R_SFT 10 +#define RT5660_G_BST1_OM_R_MASK (0x7 << 7) +#define RT5660_G_BST1_OM_R_SFT 7 +#define RT5660_G_RM_R_OM_R_MASK (0x7 << 1) +#define RT5660_G_RM_R_OM_R_SFT 1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5660_G_DAC_L_OM_R_MASK (0x7 << 10) +#define RT5660_G_DAC_L_OM_R_SFT 10 +#define RT5660_G_DAC_R_OM_R_MASK (0x7 << 7) +#define RT5660_G_DAC_R_OM_R_SFT 7 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5660_M_BST2_OM_R (0x1 << 4) +#define RT5660_M_BST2_OM_R_SFT 4 +#define RT5660_M_BST1_OM_R (0x1 << 3) +#define RT5660_M_BST1_OM_R_SFT 3 +#define RT5660_M_RM_R_OM_R (0x1 << 2) +#define RT5660_M_RM_R_OM_R_SFT 2 +#define RT5660_M_DAC_L_OM_R (0x1 << 1) +#define RT5660_M_DAC_L_OM_R_SFT 1 +#define RT5660_M_DAC_R_OM_R (0x1) +#define RT5660_M_DAC_R_OM_R_SFT 0 + +/* Power Management for Digital 1 (0x61) */ +#define RT5660_PWR_I2S1 (0x1 << 15) +#define RT5660_PWR_I2S1_BIT 15 +#define RT5660_PWR_DAC_L1 (0x1 << 12) +#define RT5660_PWR_DAC_L1_BIT 12 +#define RT5660_PWR_DAC_R1 (0x1 << 11) +#define RT5660_PWR_DAC_R1_BIT 11 +#define RT5660_PWR_ADC_L (0x1 << 2) +#define RT5660_PWR_ADC_L_BIT 2 +#define RT5660_PWR_ADC_R (0x1 << 1) +#define RT5660_PWR_ADC_R_BIT 1 +#define RT5660_PWR_CLS_D (0x1) +#define RT5660_PWR_CLS_D_BIT 0 + +/* Power Management for Digital 2 (0x62) */ +#define RT5660_PWR_ADC_S1F (0x1 << 15) +#define RT5660_PWR_ADC_S1F_BIT 15 +#define RT5660_PWR_DAC_S1F (0x1 << 11) +#define RT5660_PWR_DAC_S1F_BIT 11 + +/* Power Management for Analog 1 (0x63) */ +#define RT5660_PWR_VREF1 (0x1 << 15) +#define RT5660_PWR_VREF1_BIT 15 +#define RT5660_PWR_FV1 (0x1 << 14) +#define RT5660_PWR_FV1_BIT 14 +#define RT5660_PWR_MB (0x1 << 13) +#define RT5660_PWR_MB_BIT 13 +#define RT5660_PWR_BG (0x1 << 11) +#define RT5660_PWR_BG_BIT 11 +#define RT5660_PWR_HP_L (0x1 << 7) +#define RT5660_PWR_HP_L_BIT 7 +#define RT5660_PWR_HP_R (0x1 << 6) +#define RT5660_PWR_HP_R_BIT 6 +#define RT5660_PWR_HA (0x1 << 5) +#define RT5660_PWR_HA_BIT 5 +#define RT5660_PWR_VREF2 (0x1 << 4) +#define RT5660_PWR_VREF2_BIT 4 +#define RT5660_PWR_FV2 (0x1 << 3) +#define RT5660_PWR_FV2_BIT 3 +#define RT5660_PWR_LDO2 (0x1 << 2) +#define RT5660_PWR_LDO2_BIT 2 + +/* Power Management for Analog 2 (0x64) */ +#define RT5660_PWR_BST1 (0x1 << 15) +#define RT5660_PWR_BST1_BIT 15 +#define RT5660_PWR_BST2 (0x1 << 14) +#define RT5660_PWR_BST2_BIT 14 +#define RT5660_PWR_BST3 (0x1 << 13) +#define RT5660_PWR_BST3_BIT 13 +#define RT5660_PWR_MB1 (0x1 << 11) +#define RT5660_PWR_MB1_BIT 11 +#define RT5660_PWR_MB2 (0x1 << 10) +#define RT5660_PWR_MB2_BIT 10 +#define RT5660_PWR_PLL (0x1 << 9) +#define RT5660_PWR_PLL_BIT 9 + +/* Power Management for Mixer (0x65) */ +#define RT5660_PWR_OM_L (0x1 << 15) +#define RT5660_PWR_OM_L_BIT 15 +#define RT5660_PWR_OM_R (0x1 << 14) +#define RT5660_PWR_OM_R_BIT 14 +#define RT5660_PWR_SM (0x1 << 13) +#define RT5660_PWR_SM_BIT 13 +#define RT5660_PWR_RM_L (0x1 << 11) +#define RT5660_PWR_RM_L_BIT 11 +#define RT5660_PWR_RM_R (0x1 << 10) +#define RT5660_PWR_RM_R_BIT 10 + +/* Power Management for Volume (0x66) */ +#define RT5660_PWR_SV (0x1 << 15) +#define RT5660_PWR_SV_BIT 15 +#define RT5660_PWR_LV_L (0x1 << 11) +#define RT5660_PWR_LV_L_BIT 11 +#define RT5660_PWR_LV_R (0x1 << 10) +#define RT5660_PWR_LV_R_BIT 10 + +/* I2S1 Audio Serial Data Port Control (0x70) */ +#define RT5660_I2S_MS_MASK (0x1 << 15) +#define RT5660_I2S_MS_SFT 15 +#define RT5660_I2S_MS_M (0x0 << 15) +#define RT5660_I2S_MS_S (0x1 << 15) +#define RT5660_I2S_O_CP_MASK (0x3 << 10) +#define RT5660_I2S_O_CP_SFT 10 +#define RT5660_I2S_O_CP_OFF (0x0 << 10) +#define RT5660_I2S_O_CP_U_LAW (0x1 << 10) +#define RT5660_I2S_O_CP_A_LAW (0x2 << 10) +#define RT5660_I2S_I_CP_MASK (0x3 << 8) +#define RT5660_I2S_I_CP_SFT 8 +#define RT5660_I2S_I_CP_OFF (0x0 << 8) +#define RT5660_I2S_I_CP_U_LAW (0x1 << 8) +#define RT5660_I2S_I_CP_A_LAW (0x2 << 8) +#define RT5660_I2S_BP_MASK (0x1 << 7) +#define RT5660_I2S_BP_SFT 7 +#define RT5660_I2S_BP_NOR (0x0 << 7) +#define RT5660_I2S_BP_INV (0x1 << 7) +#define RT5660_I2S_DL_MASK (0x3 << 2) +#define RT5660_I2S_DL_SFT 2 +#define RT5660_I2S_DL_16 (0x0 << 2) +#define RT5660_I2S_DL_20 (0x1 << 2) +#define RT5660_I2S_DL_24 (0x2 << 2) +#define RT5660_I2S_DL_8 (0x3 << 2) +#define RT5660_I2S_DF_MASK (0x3) +#define RT5660_I2S_DF_SFT 0 +#define RT5660_I2S_DF_I2S (0x0) +#define RT5660_I2S_DF_LEFT (0x1) +#define RT5660_I2S_DF_PCM_A (0x2) +#define RT5660_I2S_DF_PCM_B (0x3) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5660_I2S_BCLK_MS1_MASK (0x1 << 15) +#define RT5660_I2S_BCLK_MS1_SFT 15 +#define RT5660_I2S_BCLK_MS1_32 (0x0 << 15) +#define RT5660_I2S_BCLK_MS1_64 (0x1 << 15) +#define RT5660_I2S_PD1_MASK (0x7 << 12) +#define RT5660_I2S_PD1_SFT 12 +#define RT5660_I2S_PD1_1 (0x0 << 12) +#define RT5660_I2S_PD1_2 (0x1 << 12) +#define RT5660_I2S_PD1_3 (0x2 << 12) +#define RT5660_I2S_PD1_4 (0x3 << 12) +#define RT5660_I2S_PD1_6 (0x4 << 12) +#define RT5660_I2S_PD1_8 (0x5 << 12) +#define RT5660_I2S_PD1_12 (0x6 << 12) +#define RT5660_I2S_PD1_16 (0x7 << 12) +#define RT5660_DAC_OSR_MASK (0x3 << 2) +#define RT5660_DAC_OSR_SFT 2 +#define RT5660_DAC_OSR_128 (0x0 << 2) +#define RT5660_DAC_OSR_64 (0x1 << 2) +#define RT5660_DAC_OSR_32 (0x2 << 2) +#define RT5660_DAC_OSR_16 (0x3 << 2) +#define RT5660_ADC_OSR_MASK (0x3) +#define RT5660_ADC_OSR_SFT 0 +#define RT5660_ADC_OSR_128 (0x0) +#define RT5660_ADC_OSR_64 (0x1) +#define RT5660_ADC_OSR_32 (0x2) +#define RT5660_ADC_OSR_16 (0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5660_RESET_ADF (0x1 << 13) +#define RT5660_RESET_ADF_SFT 13 +#define RT5660_RESET_DAF (0x1 << 12) +#define RT5660_RESET_DAF_SFT 12 +#define RT5660_DAHPF_EN (0x1 << 11) +#define RT5660_DAHPF_EN_SFT 11 +#define RT5660_ADHPF_EN (0x1 << 10) +#define RT5660_ADHPF_EN_SFT 10 + +/* Digital Microphone Control (0x75) */ +#define RT5660_DMIC_1_EN_MASK (0x1 << 15) +#define RT5660_DMIC_1_EN_SFT 15 +#define RT5660_DMIC_1_DIS (0x0 << 15) +#define RT5660_DMIC_1_EN (0x1 << 15) +#define RT5660_DMIC_1L_LH_MASK (0x1 << 13) +#define RT5660_DMIC_1L_LH_SFT 13 +#define RT5660_DMIC_1L_LH_RISING (0x0 << 13) +#define RT5660_DMIC_1L_LH_FALLING (0x1 << 13) +#define RT5660_DMIC_1R_LH_MASK (0x1 << 12) +#define RT5660_DMIC_1R_LH_SFT 12 +#define RT5660_DMIC_1R_LH_RISING (0x0 << 12) +#define RT5660_DMIC_1R_LH_FALLING (0x1 << 12) +#define RT5660_SEL_DMIC_DATA_MASK (0x1 << 11) +#define RT5660_SEL_DMIC_DATA_SFT 11 +#define RT5660_SEL_DMIC_DATA_GPIO2 (0x0 << 11) +#define RT5660_SEL_DMIC_DATA_IN1P (0x1 << 11) +#define RT5660_DMIC_CLK_MASK (0x7 << 5) +#define RT5660_DMIC_CLK_SFT 5 + +/* Global Clock Control (0x80) */ +#define RT5660_SCLK_SRC_MASK (0x3 << 14) +#define RT5660_SCLK_SRC_SFT 14 +#define RT5660_SCLK_SRC_MCLK (0x0 << 14) +#define RT5660_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5660_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5660_PLL1_SRC_MASK (0x3 << 12) +#define RT5660_PLL1_SRC_SFT 12 +#define RT5660_PLL1_SRC_MCLK (0x0 << 12) +#define RT5660_PLL1_SRC_BCLK1 (0x1 << 12) +#define RT5660_PLL1_SRC_RCCLK (0x2 << 12) +#define RT5660_PLL1_PD_MASK (0x1 << 3) +#define RT5660_PLL1_PD_SFT 3 +#define RT5660_PLL1_PD_1 (0x0 << 3) +#define RT5660_PLL1_PD_2 (0x1 << 3) + +#define RT5660_PLL_INP_MAX 40000000 +#define RT5660_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5660_PLL_N_MAX 0x1ff +#define RT5660_PLL_N_MASK (RT5660_PLL_N_MAX << 7) +#define RT5660_PLL_N_SFT 7 +#define RT5660_PLL_K_MAX 0x1f +#define RT5660_PLL_K_MASK (RT5660_PLL_K_MAX) +#define RT5660_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5660_PLL_M_MAX 0xf +#define RT5660_PLL_M_MASK (RT5660_PLL_M_MAX << 12) +#define RT5660_PLL_M_SFT 12 +#define RT5660_PLL_M_BP (0x1 << 11) +#define RT5660_PLL_M_BP_SFT 11 + +/* Class D Over Current Control (0x8c) */ +#define RT5660_CLSD_OC_MASK (0x1 << 9) +#define RT5660_CLSD_OC_SFT 9 +#define RT5660_CLSD_OC_PU (0x0 << 9) +#define RT5660_CLSD_OC_PD (0x1 << 9) +#define RT5660_AUTO_PD_MASK (0x1 << 8) +#define RT5660_AUTO_PD_SFT 8 +#define RT5660_AUTO_PD_DIS (0x0 << 8) +#define RT5660_AUTO_PD_EN (0x1 << 8) +#define RT5660_CLSD_OC_TH_MASK (0x3f) +#define RT5660_CLSD_OC_TH_SFT 0 + +/* Class D Output Control (0x8d) */ +#define RT5660_CLSD_RATIO_MASK (0xf << 12) +#define RT5660_CLSD_RATIO_SFT 12 + +/* Lout Amp Control 1 (0x8e) */ +#define RT5660_LOUT_CO_MASK (0x1 << 4) +#define RT5660_LOUT_CO_SFT 4 +#define RT5660_LOUT_CO_DIS (0x0 << 4) +#define RT5660_LOUT_CO_EN (0x1 << 4) +#define RT5660_LOUT_CB_MASK (0x1) +#define RT5660_LOUT_CB_SFT 0 +#define RT5660_LOUT_CB_PD (0x0) +#define RT5660_LOUT_CB_PU (0x1) + +/* SPKVDD detection control (0x92) */ +#define RT5660_SPKVDD_DET_MASK (0x1 << 15) +#define RT5660_SPKVDD_DET_SFT 15 +#define RT5660_SPKVDD_DET_DIS (0x0 << 15) +#define RT5660_SPKVDD_DET_EN (0x1 << 15) +#define RT5660_SPK_AG_MASK (0x1 << 14) +#define RT5660_SPK_AG_SFT 14 +#define RT5660_SPK_AG_DIS (0x0 << 14) +#define RT5660_SPK_AG_EN (0x1 << 14) + +/* Micbias Control (0x93) */ +#define RT5660_MIC1_BS_MASK (0x1 << 15) +#define RT5660_MIC1_BS_SFT 15 +#define RT5660_MIC1_BS_9AV (0x0 << 15) +#define RT5660_MIC1_BS_75AV (0x1 << 15) +#define RT5660_MIC2_BS_MASK (0x1 << 14) +#define RT5660_MIC2_BS_SFT 14 +#define RT5660_MIC2_BS_9AV (0x0 << 14) +#define RT5660_MIC2_BS_75AV (0x1 << 14) +#define RT5660_MIC1_OVCD_MASK (0x1 << 11) +#define RT5660_MIC1_OVCD_SFT 11 +#define RT5660_MIC1_OVCD_DIS (0x0 << 11) +#define RT5660_MIC1_OVCD_EN (0x1 << 11) +#define RT5660_MIC1_OVTH_MASK (0x3 << 9) +#define RT5660_MIC1_OVTH_SFT 9 +#define RT5660_MIC1_OVTH_600UA (0x0 << 9) +#define RT5660_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5660_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5660_MIC2_OVCD_MASK (0x1 << 8) +#define RT5660_MIC2_OVCD_SFT 8 +#define RT5660_MIC2_OVCD_DIS (0x0 << 8) +#define RT5660_MIC2_OVCD_EN (0x1 << 8) +#define RT5660_MIC2_OVTH_MASK (0x3 << 6) +#define RT5660_MIC2_OVTH_SFT 6 +#define RT5660_MIC2_OVTH_600UA (0x0 << 6) +#define RT5660_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5660_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5660_PWR_CLK25M_MASK (0x1 << 4) +#define RT5660_PWR_CLK25M_SFT 4 +#define RT5660_PWR_CLK25M_PD (0x0 << 4) +#define RT5660_PWR_CLK25M_PU (0x1 << 4) + +/* EQ Control 1 (0xb0) */ +#define RT5660_EQ_SRC_MASK (0x1 << 15) +#define RT5660_EQ_SRC_SFT 15 +#define RT5660_EQ_SRC_DAC (0x0 << 15) +#define RT5660_EQ_SRC_ADC (0x1 << 15) +#define RT5660_EQ_UPD (0x1 << 14) +#define RT5660_EQ_UPD_BIT 14 + +/* Jack Detect Control (0xbb) */ +#define RT5660_JD_MASK (0x3 << 14) +#define RT5660_JD_SFT 14 +#define RT5660_JD_DIS (0x0 << 14) +#define RT5660_JD_GPIO1 (0x1 << 14) +#define RT5660_JD_GPIO2 (0x2 << 14) +#define RT5660_JD_LOUT_MASK (0x1 << 11) +#define RT5660_JD_LOUT_SFT 11 +#define RT5660_JD_LOUT_DIS (0x0 << 11) +#define RT5660_JD_LOUT_EN (0x1 << 11) +#define RT5660_JD_LOUT_TRG_MASK (0x1 << 10) +#define RT5660_JD_LOUT_TRG_SFT 10 +#define RT5660_JD_LOUT_TRG_LO (0x0 << 10) +#define RT5660_JD_LOUT_TRG_HI (0x1 << 10) +#define RT5660_JD_SPO_MASK (0x1 << 9) +#define RT5660_JD_SPO_SFT 9 +#define RT5660_JD_SPO_DIS (0x0 << 9) +#define RT5660_JD_SPO_EN (0x1 << 9) +#define RT5660_JD_SPO_TRG_MASK (0x1 << 8) +#define RT5660_JD_SPO_TRG_SFT 8 +#define RT5660_JD_SPO_TRG_LO (0x0 << 8) +#define RT5660_JD_SPO_TRG_HI (0x1 << 8) + +/* IRQ Control 1 (0xbd) */ +#define RT5660_IRQ_JD_MASK (0x1 << 15) +#define RT5660_IRQ_JD_SFT 15 +#define RT5660_IRQ_JD_BP (0x0 << 15) +#define RT5660_IRQ_JD_NOR (0x1 << 15) +#define RT5660_IRQ_OT_MASK (0x1 << 14) +#define RT5660_IRQ_OT_SFT 14 +#define RT5660_IRQ_OT_BP (0x0 << 14) +#define RT5660_IRQ_OT_NOR (0x1 << 14) +#define RT5660_JD_STKY_MASK (0x1 << 13) +#define RT5660_JD_STKY_SFT 13 +#define RT5660_JD_STKY_DIS (0x0 << 13) +#define RT5660_JD_STKY_EN (0x1 << 13) +#define RT5660_OT_STKY_MASK (0x1 << 12) +#define RT5660_OT_STKY_SFT 12 +#define RT5660_OT_STKY_DIS (0x0 << 12) +#define RT5660_OT_STKY_EN (0x1 << 12) +#define RT5660_JD_P_MASK (0x1 << 11) +#define RT5660_JD_P_SFT 11 +#define RT5660_JD_P_NOR (0x0 << 11) +#define RT5660_JD_P_INV (0x1 << 11) +#define RT5660_OT_P_MASK (0x1 << 10) +#define RT5660_OT_P_SFT 10 +#define RT5660_OT_P_NOR (0x0 << 10) +#define RT5660_OT_P_INV (0x1 << 10) + +/* IRQ Control 2 (0xbe) */ +#define RT5660_IRQ_MB1_OC_MASK (0x1 << 15) +#define RT5660_IRQ_MB1_OC_SFT 15 +#define RT5660_IRQ_MB1_OC_BP (0x0 << 15) +#define RT5660_IRQ_MB1_OC_NOR (0x1 << 15) +#define RT5660_IRQ_MB2_OC_MASK (0x1 << 14) +#define RT5660_IRQ_MB2_OC_SFT 14 +#define RT5660_IRQ_MB2_OC_BP (0x0 << 14) +#define RT5660_IRQ_MB2_OC_NOR (0x1 << 14) +#define RT5660_MB1_OC_STKY_MASK (0x1 << 11) +#define RT5660_MB1_OC_STKY_SFT 11 +#define RT5660_MB1_OC_STKY_DIS (0x0 << 11) +#define RT5660_MB1_OC_STKY_EN (0x1 << 11) +#define RT5660_MB2_OC_STKY_MASK (0x1 << 10) +#define RT5660_MB2_OC_STKY_SFT 10 +#define RT5660_MB2_OC_STKY_DIS (0x0 << 10) +#define RT5660_MB2_OC_STKY_EN (0x1 << 10) +#define RT5660_MB1_OC_P_MASK (0x1 << 7) +#define RT5660_MB1_OC_P_SFT 7 +#define RT5660_MB1_OC_P_NOR (0x0 << 7) +#define RT5660_MB1_OC_P_INV (0x1 << 7) +#define RT5660_MB2_OC_P_MASK (0x1 << 6) +#define RT5660_MB2_OC_P_SFT 6 +#define RT5660_MB2_OC_P_NOR (0x0 << 6) +#define RT5660_MB2_OC_P_INV (0x1 << 6) +#define RT5660_MB1_OC_CLR (0x1 << 3) +#define RT5660_MB1_OC_CLR_SFT 3 +#define RT5660_MB2_OC_CLR (0x1 << 2) +#define RT5660_MB2_OC_CLR_SFT 2 + +/* GPIO Control 1 (0xc0) */ +#define RT5660_GP2_PIN_MASK (0x1 << 14) +#define RT5660_GP2_PIN_SFT 14 +#define RT5660_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5660_GP2_PIN_DMIC1_SDA (0x1 << 14) +#define RT5660_GP1_PIN_MASK (0x3 << 12) +#define RT5660_GP1_PIN_SFT 12 +#define RT5660_GP1_PIN_GPIO1 (0x0 << 12) +#define RT5660_GP1_PIN_DMIC1_SCL (0x1 << 12) +#define RT5660_GP1_PIN_IRQ (0x2 << 12) +#define RT5660_GPIO_M_MASK (0x1 << 9) +#define RT5660_GPIO_M_SFT 9 +#define RT5660_GPIO_M_FLT (0x0 << 9) +#define RT5660_GPIO_M_PH (0x1 << 9) + +/* GPIO Control 3 (0xc2) */ +#define RT5660_GP2_PF_MASK (0x1 << 5) +#define RT5660_GP2_PF_SFT 5 +#define RT5660_GP2_PF_IN (0x0 << 5) +#define RT5660_GP2_PF_OUT (0x1 << 5) +#define RT5660_GP2_OUT_MASK (0x1 << 4) +#define RT5660_GP2_OUT_SFT 4 +#define RT5660_GP2_OUT_LO (0x0 << 4) +#define RT5660_GP2_OUT_HI (0x1 << 4) +#define RT5660_GP2_P_MASK (0x1 << 3) +#define RT5660_GP2_P_SFT 3 +#define RT5660_GP2_P_NOR (0x0 << 3) +#define RT5660_GP2_P_INV (0x1 << 3) +#define RT5660_GP1_PF_MASK (0x1 << 2) +#define RT5660_GP1_PF_SFT 2 +#define RT5660_GP1_PF_IN (0x0 << 2) +#define RT5660_GP1_PF_OUT (0x1 << 2) +#define RT5660_GP1_OUT_MASK (0x1 << 1) +#define RT5660_GP1_OUT_SFT 1 +#define RT5660_GP1_OUT_LO (0x0 << 1) +#define RT5660_GP1_OUT_HI (0x1 << 1) +#define RT5660_GP1_P_MASK (0x1) +#define RT5660_GP1_P_SFT 0 +#define RT5660_GP1_P_NOR (0x0) +#define RT5660_GP1_P_INV (0x1) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5660_SV_MASK (0x1 << 15) +#define RT5660_SV_SFT 15 +#define RT5660_SV_DIS (0x0 << 15) +#define RT5660_SV_EN (0x1 << 15) +#define RT5660_SPO_SV_MASK (0x1 << 14) +#define RT5660_SPO_SV_SFT 14 +#define RT5660_SPO_SV_DIS (0x0 << 14) +#define RT5660_SPO_SV_EN (0x1 << 14) +#define RT5660_OUT_SV_MASK (0x1 << 12) +#define RT5660_OUT_SV_SFT 12 +#define RT5660_OUT_SV_DIS (0x0 << 12) +#define RT5660_OUT_SV_EN (0x1 << 12) +#define RT5660_ZCD_DIG_MASK (0x1 << 11) +#define RT5660_ZCD_DIG_SFT 11 +#define RT5660_ZCD_DIG_DIS (0x0 << 11) +#define RT5660_ZCD_DIG_EN (0x1 << 11) +#define RT5660_ZCD_MASK (0x1 << 10) +#define RT5660_ZCD_SFT 10 +#define RT5660_ZCD_PD (0x0 << 10) +#define RT5660_ZCD_PU (0x1 << 10) +#define RT5660_SV_DLY_MASK (0xf) +#define RT5660_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5660_ZCD_SPO_MASK (0x1 << 15) +#define RT5660_ZCD_SPO_SFT 15 +#define RT5660_ZCD_SPO_DIS (0x0 << 15) +#define RT5660_ZCD_SPO_EN (0x1 << 15) +#define RT5660_ZCD_OMR_MASK (0x1 << 8) +#define RT5660_ZCD_OMR_SFT 8 +#define RT5660_ZCD_OMR_DIS (0x0 << 8) +#define RT5660_ZCD_OMR_EN (0x1 << 8) +#define RT5660_ZCD_OML_MASK (0x1 << 7) +#define RT5660_ZCD_OML_SFT 7 +#define RT5660_ZCD_OML_DIS (0x0 << 7) +#define RT5660_ZCD_OML_EN (0x1 << 7) +#define RT5660_ZCD_SPM_MASK (0x1 << 6) +#define RT5660_ZCD_SPM_SFT 6 +#define RT5660_ZCD_SPM_DIS (0x0 << 6) +#define RT5660_ZCD_SPM_EN (0x1 << 6) +#define RT5660_ZCD_RMR_MASK (0x1 << 5) +#define RT5660_ZCD_RMR_SFT 5 +#define RT5660_ZCD_RMR_DIS (0x0 << 5) +#define RT5660_ZCD_RMR_EN (0x1 << 5) +#define RT5660_ZCD_RML_MASK (0x1 << 4) +#define RT5660_ZCD_RML_SFT 4 +#define RT5660_ZCD_RML_DIS (0x0 << 4) +#define RT5660_ZCD_RML_EN (0x1 << 4) + +/* General Control 1 (0xfa) */ +#define RT5660_PWR_VREF_HP (0x1 << 11) +#define RT5660_PWR_VREF_HP_SFT 11 +#define RT5660_DIG_GATE_CTRL (0x1) +#define RT5660_DIG_GATE_CTRL_SFT 0 + +/* System Clock Source */ +#define RT5660_SCLK_S_MCLK 0 +#define RT5660_SCLK_S_PLL1 1 +#define RT5660_SCLK_S_RCCLK 2 + +/* PLL1 Source */ +#define RT5660_PLL1_S_MCLK 0 +#define RT5660_PLL1_S_BCLK 1 + +enum { + RT5660_AIF1, + RT5660_AIFS, +}; + +struct rt5660_priv { + struct snd_soc_codec *codec; + struct rt5660_platform_data pdata; + struct regmap *regmap; + struct clk *mclk; + + int sysclk; + int sysclk_src; + int lrck[RT5660_AIFS]; + int bclk[RT5660_AIFS]; + int master[RT5660_AIFS]; + + int pll_src; + int pll_in; + int pll_out; +}; + +#endif diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c new file mode 100644 index 000000000000..01a18d88f1eb --- /dev/null +++ b/sound/soc/codecs/rt5663.c @@ -0,0 +1,3218 @@ +/* + * rt5663.c -- RT5668/RT5663 ALSA SoC audio codec driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Jack Yu <jack.yu@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <linux/workqueue.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rt5663.h" +#include "rl6231.h" + +#define RT5668_DEVICE_ID 0x6451 +#define RT5663_DEVICE_ID 0x6406 + +enum { + CODEC_TYPE_RT5668, + CODEC_TYPE_RT5663, +}; + +struct rt5663_priv { + struct snd_soc_codec *codec; + struct regmap *regmap; + struct delayed_work jack_detect_work; + struct snd_soc_jack *hs_jack; + struct timer_list btn_check_timer; + + int codec_type; + int sysclk; + int sysclk_src; + int lrck; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; +}; + +static const struct reg_default rt5668_reg[] = { + { 0x0000, 0x0000 }, + { 0x0001, 0xc8c8 }, + { 0x0002, 0x8080 }, + { 0x0003, 0x8000 }, + { 0x0004, 0xc80a }, + { 0x0005, 0x0000 }, + { 0x0006, 0x0000 }, + { 0x0007, 0x0000 }, + { 0x000a, 0x0000 }, + { 0x000b, 0x0000 }, + { 0x000c, 0x0000 }, + { 0x000d, 0x0000 }, + { 0x000f, 0x0808 }, + { 0x0010, 0x4000 }, + { 0x0011, 0x0000 }, + { 0x0012, 0x1404 }, + { 0x0013, 0x1000 }, + { 0x0014, 0xa00a }, + { 0x0015, 0x0404 }, + { 0x0016, 0x0404 }, + { 0x0017, 0x0011 }, + { 0x0018, 0xafaf }, + { 0x0019, 0xafaf }, + { 0x001a, 0xafaf }, + { 0x001b, 0x0011 }, + { 0x001c, 0x2f2f }, + { 0x001d, 0x2f2f }, + { 0x001e, 0x2f2f }, + { 0x001f, 0x0000 }, + { 0x0020, 0x0000 }, + { 0x0021, 0x0000 }, + { 0x0022, 0x5757 }, + { 0x0023, 0x0039 }, + { 0x0024, 0x000b }, + { 0x0026, 0xc0c0 }, + { 0x0027, 0xc0c0 }, + { 0x0028, 0xc0c0 }, + { 0x0029, 0x8080 }, + { 0x002a, 0xaaaa }, + { 0x002b, 0xaaaa }, + { 0x002c, 0xaba8 }, + { 0x002d, 0x0000 }, + { 0x002e, 0x0000 }, + { 0x002f, 0x0000 }, + { 0x0030, 0x0000 }, + { 0x0031, 0x5000 }, + { 0x0032, 0x0000 }, + { 0x0033, 0x0000 }, + { 0x0034, 0x0000 }, + { 0x0035, 0x0000 }, + { 0x003a, 0x0000 }, + { 0x003b, 0x0000 }, + { 0x003c, 0x00ff }, + { 0x003d, 0x0000 }, + { 0x003e, 0x00ff }, + { 0x003f, 0x0000 }, + { 0x0040, 0x0000 }, + { 0x0041, 0x00ff }, + { 0x0042, 0x0000 }, + { 0x0043, 0x00ff }, + { 0x0044, 0x0c0c }, + { 0x0049, 0xc00b }, + { 0x004a, 0x0000 }, + { 0x004b, 0x031f }, + { 0x004d, 0x0000 }, + { 0x004e, 0x001f }, + { 0x004f, 0x0000 }, + { 0x0050, 0x001f }, + { 0x0052, 0xf000 }, + { 0x0061, 0x0000 }, + { 0x0062, 0x0000 }, + { 0x0063, 0x003e }, + { 0x0064, 0x0000 }, + { 0x0065, 0x0000 }, + { 0x0066, 0x003f }, + { 0x0067, 0x0000 }, + { 0x006b, 0x0000 }, + { 0x006d, 0xff00 }, + { 0x006e, 0x2808 }, + { 0x006f, 0x000a }, + { 0x0070, 0x8000 }, + { 0x0071, 0x8000 }, + { 0x0072, 0x8000 }, + { 0x0073, 0x7000 }, + { 0x0074, 0x7770 }, + { 0x0075, 0x0002 }, + { 0x0076, 0x0001 }, + { 0x0078, 0x00f0 }, + { 0x0079, 0x0000 }, + { 0x007a, 0x0000 }, + { 0x007b, 0x0000 }, + { 0x007c, 0x0000 }, + { 0x007d, 0x0123 }, + { 0x007e, 0x4500 }, + { 0x007f, 0x8003 }, + { 0x0080, 0x0000 }, + { 0x0081, 0x0000 }, + { 0x0082, 0x0000 }, + { 0x0083, 0x0000 }, + { 0x0084, 0x0000 }, + { 0x0085, 0x0000 }, + { 0x0086, 0x0008 }, + { 0x0087, 0x0000 }, + { 0x0088, 0x0000 }, + { 0x0089, 0x0000 }, + { 0x008a, 0x0000 }, + { 0x008b, 0x0000 }, + { 0x008c, 0x0003 }, + { 0x008e, 0x0060 }, + { 0x008f, 0x1000 }, + { 0x0091, 0x0c26 }, + { 0x0092, 0x0073 }, + { 0x0093, 0x0000 }, + { 0x0094, 0x0080 }, + { 0x0098, 0x0000 }, + { 0x0099, 0x0000 }, + { 0x009a, 0x0007 }, + { 0x009f, 0x0000 }, + { 0x00a0, 0x0000 }, + { 0x00a1, 0x0002 }, + { 0x00a2, 0x0001 }, + { 0x00a3, 0x0002 }, + { 0x00a4, 0x0001 }, + { 0x00ae, 0x2040 }, + { 0x00af, 0x0000 }, + { 0x00b6, 0x0000 }, + { 0x00b7, 0x0000 }, + { 0x00b8, 0x0000 }, + { 0x00b9, 0x0000 }, + { 0x00ba, 0x0002 }, + { 0x00bb, 0x0000 }, + { 0x00be, 0x0000 }, + { 0x00c0, 0x0000 }, + { 0x00c1, 0x0aaa }, + { 0x00c2, 0xaa80 }, + { 0x00c3, 0x0003 }, + { 0x00c4, 0x0000 }, + { 0x00d0, 0x0000 }, + { 0x00d1, 0x2244 }, + { 0x00d2, 0x0000 }, + { 0x00d3, 0x3300 }, + { 0x00d4, 0x2200 }, + { 0x00d9, 0x0809 }, + { 0x00da, 0x0000 }, + { 0x00db, 0x0008 }, + { 0x00dc, 0x00c0 }, + { 0x00dd, 0x6724 }, + { 0x00de, 0x3131 }, + { 0x00df, 0x0008 }, + { 0x00e0, 0x4000 }, + { 0x00e1, 0x3131 }, + { 0x00e2, 0x600c }, + { 0x00ea, 0xb320 }, + { 0x00eb, 0x0000 }, + { 0x00ec, 0xb300 }, + { 0x00ed, 0x0000 }, + { 0x00ee, 0xb320 }, + { 0x00ef, 0x0000 }, + { 0x00f0, 0x0201 }, + { 0x00f1, 0x0ddd }, + { 0x00f2, 0x0ddd }, + { 0x00f6, 0x0000 }, + { 0x00f7, 0x0000 }, + { 0x00f8, 0x0000 }, + { 0x00fa, 0x0000 }, + { 0x00fb, 0x0000 }, + { 0x00fc, 0x0000 }, + { 0x00fd, 0x0000 }, + { 0x00fe, 0x10ec }, + { 0x00ff, 0x6451 }, + { 0x0100, 0xaaaa }, + { 0x0101, 0x000a }, + { 0x010a, 0xaaaa }, + { 0x010b, 0xa0a0 }, + { 0x010c, 0xaeae }, + { 0x010d, 0xaaaa }, + { 0x010e, 0xaaaa }, + { 0x010f, 0xaaaa }, + { 0x0110, 0xe002 }, + { 0x0111, 0xa602 }, + { 0x0112, 0xaaaa }, + { 0x0113, 0x2000 }, + { 0x0117, 0x0f00 }, + { 0x0125, 0x0420 }, + { 0x0132, 0x0000 }, + { 0x0133, 0x0000 }, + { 0x0136, 0x5555 }, + { 0x0137, 0x5540 }, + { 0x0138, 0x3700 }, + { 0x0139, 0x79a1 }, + { 0x013a, 0x2020 }, + { 0x013b, 0x2020 }, + { 0x013c, 0x2005 }, + { 0x013f, 0x0000 }, + { 0x0145, 0x0002 }, + { 0x0146, 0x0000 }, + { 0x0147, 0x0000 }, + { 0x0148, 0x0000 }, + { 0x0160, 0x4ec0 }, + { 0x0161, 0x0080 }, + { 0x0162, 0x0200 }, + { 0x0163, 0x0800 }, + { 0x0164, 0x0000 }, + { 0x0165, 0x0000 }, + { 0x0166, 0x0000 }, + { 0x0167, 0x000f }, + { 0x0168, 0x000f }, + { 0x0170, 0x4e80 }, + { 0x0171, 0x0080 }, + { 0x0172, 0x0200 }, + { 0x0173, 0x0800 }, + { 0x0174, 0x00ff }, + { 0x0175, 0x0000 }, + { 0x0190, 0x4131 }, + { 0x0191, 0x4131 }, + { 0x0192, 0x4131 }, + { 0x0193, 0x4131 }, + { 0x0194, 0x0000 }, + { 0x0195, 0x0000 }, + { 0x0196, 0x0000 }, + { 0x0197, 0x0000 }, + { 0x0198, 0x0000 }, + { 0x0199, 0x0000 }, + { 0x01a0, 0x1e64 }, + { 0x01a1, 0x06a3 }, + { 0x01a2, 0x0000 }, + { 0x01a3, 0x0000 }, + { 0x01a4, 0x0000 }, + { 0x01a5, 0x0000 }, + { 0x01a6, 0x0000 }, + { 0x01a7, 0x0000 }, + { 0x01a8, 0x0000 }, + { 0x01a9, 0x0000 }, + { 0x01aa, 0x0000 }, + { 0x01ab, 0x0000 }, + { 0x01b5, 0x0000 }, + { 0x01b6, 0x01c3 }, + { 0x01b7, 0x02a0 }, + { 0x01b8, 0x03e9 }, + { 0x01b9, 0x1389 }, + { 0x01ba, 0xc351 }, + { 0x01bb, 0x0009 }, + { 0x01bc, 0x0018 }, + { 0x01bd, 0x002a }, + { 0x01be, 0x004c }, + { 0x01bf, 0x0097 }, + { 0x01c0, 0x433d }, + { 0x01c1, 0x0000 }, + { 0x01c2, 0x0000 }, + { 0x01c3, 0x0000 }, + { 0x01c4, 0x0000 }, + { 0x01c5, 0x0000 }, + { 0x01c6, 0x0000 }, + { 0x01c7, 0x0000 }, + { 0x01c8, 0x40af }, + { 0x01c9, 0x0702 }, + { 0x01ca, 0x0000 }, + { 0x01cb, 0x0000 }, + { 0x01cc, 0x5757 }, + { 0x01cd, 0x5757 }, + { 0x01ce, 0x5757 }, + { 0x01cf, 0x5757 }, + { 0x01d0, 0x5757 }, + { 0x01d1, 0x5757 }, + { 0x01d2, 0x5757 }, + { 0x01d3, 0x5757 }, + { 0x01d4, 0x5757 }, + { 0x01d5, 0x5757 }, + { 0x01d6, 0x003c }, + { 0x01da, 0x0000 }, + { 0x01db, 0x0000 }, + { 0x01dc, 0x0000 }, + { 0x01de, 0x7c00 }, + { 0x01df, 0x0320 }, + { 0x01e0, 0x06a1 }, + { 0x01e1, 0x0000 }, + { 0x01e2, 0x0000 }, + { 0x01e3, 0x0000 }, + { 0x01e4, 0x0000 }, + { 0x01e5, 0x0000 }, + { 0x01e6, 0x0001 }, + { 0x01e7, 0x0000 }, + { 0x01e8, 0x0000 }, + { 0x01ea, 0x0000 }, + { 0x01eb, 0x0000 }, + { 0x01ec, 0x0000 }, + { 0x01ed, 0x0000 }, + { 0x01ee, 0x0000 }, + { 0x01ef, 0x0000 }, + { 0x01f0, 0x0000 }, + { 0x01f1, 0x0000 }, + { 0x01f2, 0x0000 }, + { 0x01f3, 0x0000 }, + { 0x01f4, 0x0000 }, + { 0x0200, 0x0000 }, + { 0x0201, 0x0000 }, + { 0x0202, 0x0000 }, + { 0x0203, 0x0000 }, + { 0x0204, 0x0000 }, + { 0x0205, 0x0000 }, + { 0x0206, 0x0000 }, + { 0x0207, 0x0000 }, + { 0x0208, 0x0000 }, + { 0x0210, 0x60b1 }, + { 0x0211, 0xa000 }, + { 0x0212, 0x024c }, + { 0x0213, 0xf7ff }, + { 0x0214, 0x024c }, + { 0x0215, 0x0102 }, + { 0x0216, 0x00a3 }, + { 0x0217, 0x0048 }, + { 0x0218, 0x92c0 }, + { 0x0219, 0x0000 }, + { 0x021a, 0x00c8 }, + { 0x021b, 0x0020 }, + { 0x02fa, 0x0000 }, + { 0x02fb, 0x0000 }, + { 0x02fc, 0x0000 }, + { 0x02ff, 0x0110 }, + { 0x0300, 0x001f }, + { 0x0301, 0x032c }, + { 0x0302, 0x5f21 }, + { 0x0303, 0x4000 }, + { 0x0304, 0x4000 }, + { 0x0305, 0x06d5 }, + { 0x0306, 0x8000 }, + { 0x0307, 0x0700 }, + { 0x0310, 0x4560 }, + { 0x0311, 0xa4a8 }, + { 0x0312, 0x7418 }, + { 0x0313, 0x0000 }, + { 0x0314, 0x0006 }, + { 0x0315, 0xffff }, + { 0x0316, 0xc400 }, + { 0x0317, 0x0000 }, + { 0x0330, 0x00a6 }, + { 0x0331, 0x04c3 }, + { 0x0332, 0x27c8 }, + { 0x0333, 0xbf50 }, + { 0x0334, 0x0045 }, + { 0x0335, 0x0007 }, + { 0x0336, 0x7418 }, + { 0x0337, 0x0501 }, + { 0x0338, 0x0000 }, + { 0x0339, 0x0010 }, + { 0x033a, 0x1010 }, + { 0x03c0, 0x7e00 }, + { 0x03c1, 0x8000 }, + { 0x03c2, 0x8000 }, + { 0x03c3, 0x8000 }, + { 0x03c4, 0x8000 }, + { 0x03c5, 0x8000 }, + { 0x03c6, 0x8000 }, + { 0x03c7, 0x8000 }, + { 0x03c8, 0x8000 }, + { 0x03c9, 0x8000 }, + { 0x03ca, 0x8000 }, + { 0x03cb, 0x8000 }, + { 0x03cc, 0x8000 }, + { 0x03d0, 0x0000 }, + { 0x03d1, 0x0000 }, + { 0x03d2, 0x0000 }, + { 0x03d3, 0x0000 }, + { 0x03d4, 0x2000 }, + { 0x03d5, 0x2000 }, + { 0x03d6, 0x0000 }, + { 0x03d7, 0x0000 }, + { 0x03d8, 0x2000 }, + { 0x03d9, 0x2000 }, + { 0x03da, 0x2000 }, + { 0x03db, 0x2000 }, + { 0x03dc, 0x0000 }, + { 0x03dd, 0x0000 }, + { 0x03de, 0x0000 }, + { 0x03df, 0x2000 }, + { 0x03e0, 0x0000 }, + { 0x03e1, 0x0000 }, + { 0x03e2, 0x0000 }, + { 0x03e3, 0x0000 }, + { 0x03e4, 0x0000 }, + { 0x03e5, 0x0000 }, + { 0x03e6, 0x0000 }, + { 0x03e7, 0x0000 }, + { 0x03e8, 0x0000 }, + { 0x03e9, 0x0000 }, + { 0x03ea, 0x0000 }, + { 0x03eb, 0x0000 }, + { 0x03ec, 0x0000 }, + { 0x03ed, 0x0000 }, + { 0x03ee, 0x0000 }, + { 0x03ef, 0x0000 }, + { 0x03f0, 0x0800 }, + { 0x03f1, 0x0800 }, + { 0x03f2, 0x0800 }, + { 0x03f3, 0x0800 }, + { 0x03fe, 0x0000 }, + { 0x03ff, 0x0000 }, + { 0x07f0, 0x0000 }, + { 0x07fa, 0x0000 }, +}; + +static const struct reg_default rt5663_reg[] = { + { 0x0000, 0x0000 }, + { 0x0002, 0x0008 }, + { 0x0005, 0x1000 }, + { 0x0006, 0x1000 }, + { 0x000a, 0x0000 }, + { 0x0010, 0x000f }, + { 0x0015, 0x42c1 }, + { 0x0016, 0x0000 }, + { 0x0018, 0x000b }, + { 0x0019, 0xafaf }, + { 0x001c, 0x2f2f }, + { 0x001f, 0x0000 }, + { 0x0022, 0x5757 }, + { 0x0023, 0x0039 }, + { 0x0026, 0xc0c0 }, + { 0x0029, 0x8080 }, + { 0x002a, 0xa0a0 }, + { 0x002c, 0x000c }, + { 0x002d, 0x0000 }, + { 0x0040, 0x0808 }, + { 0x0061, 0x0000 }, + { 0x0062, 0x0000 }, + { 0x0063, 0x003e }, + { 0x0064, 0x0000 }, + { 0x0065, 0x0000 }, + { 0x0066, 0x0000 }, + { 0x006b, 0x0000 }, + { 0x006e, 0x0000 }, + { 0x006f, 0x0000 }, + { 0x0070, 0x8020 }, + { 0x0073, 0x1000 }, + { 0x0074, 0xe400 }, + { 0x0075, 0x0002 }, + { 0x0076, 0x0001 }, + { 0x0077, 0x00f0 }, + { 0x0078, 0x0000 }, + { 0x0079, 0x0000 }, + { 0x007a, 0x0123 }, + { 0x007b, 0x8003 }, + { 0x0080, 0x0000 }, + { 0x0081, 0x0000 }, + { 0x0082, 0x0000 }, + { 0x0083, 0x0000 }, + { 0x0084, 0x0000 }, + { 0x0086, 0x0008 }, + { 0x0087, 0x0000 }, + { 0x008a, 0x0000 }, + { 0x008b, 0x0000 }, + { 0x008c, 0x0003 }, + { 0x008e, 0x0004 }, + { 0x008f, 0x1000 }, + { 0x0090, 0x0646 }, + { 0x0091, 0x0e3e }, + { 0x0092, 0x1071 }, + { 0x0093, 0x0000 }, + { 0x0094, 0x0080 }, + { 0x0097, 0x0000 }, + { 0x0098, 0x0000 }, + { 0x009a, 0x0000 }, + { 0x009f, 0x0000 }, + { 0x00ae, 0x2000 }, + { 0x00af, 0x0000 }, + { 0x00b6, 0x0000 }, + { 0x00b7, 0x0000 }, + { 0x00b8, 0x0000 }, + { 0x00ba, 0x0000 }, + { 0x00bb, 0x0000 }, + { 0x00be, 0x0000 }, + { 0x00bf, 0x0000 }, + { 0x00c0, 0x0000 }, + { 0x00c1, 0x0000 }, + { 0x00c5, 0x0000 }, + { 0x00cb, 0xa02f }, + { 0x00cc, 0x0000 }, + { 0x00cd, 0x0e02 }, + { 0x00d9, 0x08f9 }, + { 0x00db, 0x0008 }, + { 0x00dc, 0x00c0 }, + { 0x00dd, 0x6724 }, + { 0x00de, 0x3131 }, + { 0x00df, 0x0008 }, + { 0x00e0, 0x4000 }, + { 0x00e1, 0x3131 }, + { 0x00e2, 0x0043 }, + { 0x00e4, 0x400b }, + { 0x00e5, 0x8031 }, + { 0x00e6, 0x3080 }, + { 0x00e7, 0x4100 }, + { 0x00e8, 0x1400 }, + { 0x00e9, 0xe00a }, + { 0x00ea, 0x0404 }, + { 0x00eb, 0x0404 }, + { 0x00ec, 0xb320 }, + { 0x00ed, 0x0000 }, + { 0x00f4, 0x0000 }, + { 0x00f6, 0x0000 }, + { 0x00f8, 0x0000 }, + { 0x00fa, 0x8000 }, + { 0x00fd, 0x0001 }, + { 0x00fe, 0x10ec }, + { 0x00ff, 0x6406 }, + { 0x0100, 0xa0a0 }, + { 0x0108, 0x4444 }, + { 0x0109, 0x4444 }, + { 0x010a, 0xaaaa }, + { 0x010b, 0x00a0 }, + { 0x010c, 0x8aaa }, + { 0x010d, 0xaaaa }, + { 0x010e, 0x2aaa }, + { 0x010f, 0x002a }, + { 0x0110, 0xa0a4 }, + { 0x0111, 0x4602 }, + { 0x0112, 0x0101 }, + { 0x0113, 0x2000 }, + { 0x0114, 0x0000 }, + { 0x0116, 0x0000 }, + { 0x0117, 0x0f00 }, + { 0x0118, 0x0006 }, + { 0x0125, 0x2224 }, + { 0x0126, 0x5550 }, + { 0x0127, 0x0400 }, + { 0x0128, 0x7711 }, + { 0x0132, 0x0004 }, + { 0x0137, 0x5441 }, + { 0x0139, 0x79a1 }, + { 0x013a, 0x30c0 }, + { 0x013b, 0x2000 }, + { 0x013c, 0x2005 }, + { 0x013d, 0x30c0 }, + { 0x013e, 0x0000 }, + { 0x0140, 0x3700 }, + { 0x0141, 0x1f00 }, + { 0x0144, 0x0000 }, + { 0x0145, 0x0002 }, + { 0x0146, 0x0000 }, + { 0x0160, 0x0e80 }, + { 0x0161, 0x0020 }, + { 0x0162, 0x0080 }, + { 0x0163, 0x0800 }, + { 0x0164, 0x0000 }, + { 0x0165, 0x0000 }, + { 0x0166, 0x0000 }, + { 0x0167, 0x1417 }, + { 0x0168, 0x0017 }, + { 0x0169, 0x0017 }, + { 0x0180, 0x2000 }, + { 0x0181, 0x0000 }, + { 0x0182, 0x0000 }, + { 0x0183, 0x2000 }, + { 0x0184, 0x0000 }, + { 0x0185, 0x0000 }, + { 0x01b0, 0x4b30 }, + { 0x01b1, 0x0000 }, + { 0x01b2, 0xd870 }, + { 0x01b3, 0x0000 }, + { 0x01b4, 0x0030 }, + { 0x01b5, 0x5757 }, + { 0x01b6, 0x5757 }, + { 0x01b7, 0x5757 }, + { 0x01b8, 0x5757 }, + { 0x01c0, 0x433d }, + { 0x01c1, 0x0540 }, + { 0x01c2, 0x0000 }, + { 0x01c3, 0x0000 }, + { 0x01c4, 0x0000 }, + { 0x01c5, 0x0009 }, + { 0x01c6, 0x0018 }, + { 0x01c7, 0x002a }, + { 0x01c8, 0x004c }, + { 0x01c9, 0x0097 }, + { 0x01ca, 0x01c3 }, + { 0x01cb, 0x03e9 }, + { 0x01cc, 0x1389 }, + { 0x01cd, 0xc351 }, + { 0x01ce, 0x0000 }, + { 0x01cf, 0x0000 }, + { 0x01d0, 0x0000 }, + { 0x01d1, 0x0000 }, + { 0x01d2, 0x0000 }, + { 0x01d3, 0x003c }, + { 0x01d4, 0x5757 }, + { 0x01d5, 0x5757 }, + { 0x01d6, 0x5757 }, + { 0x01d7, 0x5757 }, + { 0x01d8, 0x5757 }, + { 0x01d9, 0x5757 }, + { 0x01da, 0x0000 }, + { 0x01db, 0x0000 }, + { 0x01dd, 0x0009 }, + { 0x01de, 0x7f00 }, + { 0x01df, 0x00c8 }, + { 0x01e0, 0x0691 }, + { 0x01e1, 0x0000 }, + { 0x01e2, 0x0000 }, + { 0x01e3, 0x0000 }, + { 0x01e4, 0x0000 }, + { 0x01e5, 0x0040 }, + { 0x01e6, 0x0000 }, + { 0x01e7, 0x0000 }, + { 0x01e8, 0x0000 }, + { 0x01ea, 0x0000 }, + { 0x01eb, 0x0000 }, + { 0x01ec, 0x0000 }, + { 0x01ed, 0x0000 }, + { 0x01ee, 0x0000 }, + { 0x01ef, 0x0000 }, + { 0x01f0, 0x0000 }, + { 0x01f1, 0x0000 }, + { 0x01f2, 0x0000 }, + { 0x0200, 0x0000 }, + { 0x0201, 0x2244 }, + { 0x0202, 0xaaaa }, + { 0x0250, 0x8010 }, + { 0x0251, 0x0000 }, + { 0x0252, 0x028a }, + { 0x02fa, 0x0000 }, + { 0x02fb, 0x0000 }, + { 0x02fc, 0x0000 }, + { 0x0300, 0x0000 }, + { 0x03d0, 0x0000 }, + { 0x03d1, 0x0000 }, + { 0x03d2, 0x0000 }, + { 0x03d3, 0x0000 }, + { 0x03d4, 0x2000 }, + { 0x03d5, 0x2000 }, + { 0x03d6, 0x0000 }, + { 0x03d7, 0x0000 }, + { 0x03d8, 0x2000 }, + { 0x03d9, 0x2000 }, + { 0x03da, 0x2000 }, + { 0x03db, 0x2000 }, + { 0x03dc, 0x0000 }, + { 0x03dd, 0x0000 }, + { 0x03de, 0x0000 }, + { 0x03df, 0x2000 }, + { 0x03e0, 0x0000 }, + { 0x03e1, 0x0000 }, + { 0x03e2, 0x0000 }, + { 0x03e3, 0x0000 }, + { 0x03e4, 0x0000 }, + { 0x03e5, 0x0000 }, + { 0x03e6, 0x0000 }, + { 0x03e7, 0x0000 }, + { 0x03e8, 0x0000 }, + { 0x03e9, 0x0000 }, + { 0x03ea, 0x0000 }, + { 0x03eb, 0x0000 }, + { 0x03ec, 0x0000 }, + { 0x03ed, 0x0000 }, + { 0x03ee, 0x0000 }, + { 0x03ef, 0x0000 }, + { 0x03f0, 0x0800 }, + { 0x03f1, 0x0800 }, + { 0x03f2, 0x0800 }, + { 0x03f3, 0x0800 }, +}; + +static bool rt5663_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5663_RESET: + case RT5663_SIL_DET_CTL: + case RT5663_HP_IMP_GAIN_2: + case RT5663_AD_DA_MIXER: + case RT5663_FRAC_DIV_2: + case RT5663_MICBIAS_1: + case RT5663_ASRC_11_2: + case RT5663_ADC_EQ_1: + case RT5663_INT_ST_1: + case RT5663_INT_ST_2: + case RT5663_GPIO_STA: + case RT5663_SIN_GEN_1: + case RT5663_IL_CMD_1: + case RT5663_IL_CMD_5: + case RT5663_IL_CMD_PWRSAV1: + case RT5663_EM_JACK_TYPE_1: + case RT5663_EM_JACK_TYPE_2: + case RT5663_EM_JACK_TYPE_3: + case RT5663_JD_CTRL2: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5663_PLL_INT_REG: + case RT5663_SOFT_RAMP: + case RT5663_STO_DRE_1: + case RT5663_STO_DRE_5: + case RT5663_STO_DRE_6: + case RT5663_STO_DRE_7: + case RT5663_MIC_DECRO_1: + case RT5663_MIC_DECRO_4: + case RT5663_HP_IMP_SEN_1: + case RT5663_HP_IMP_SEN_3: + case RT5663_HP_IMP_SEN_4: + case RT5663_HP_IMP_SEN_5: + case RT5663_HP_CALIB_1_1: + case RT5663_HP_CALIB_9: + case RT5663_HP_CALIB_ST1: + case RT5663_HP_CALIB_ST2: + case RT5663_HP_CALIB_ST3: + case RT5663_HP_CALIB_ST4: + case RT5663_HP_CALIB_ST5: + case RT5663_HP_CALIB_ST6: + case RT5663_HP_CALIB_ST7: + case RT5663_HP_CALIB_ST8: + case RT5663_HP_CALIB_ST9: + case RT5663_ANA_JD: + return true; + default: + return false; + } +} + +static bool rt5663_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5663_RESET: + case RT5663_HP_OUT_EN: + case RT5663_HP_LCH_DRE: + case RT5663_HP_RCH_DRE: + case RT5663_CALIB_BST: + case RT5663_RECMIX: + case RT5663_SIL_DET_CTL: + case RT5663_PWR_SAV_SILDET: + case RT5663_SIDETONE_CTL: + case RT5663_STO1_DAC_DIG_VOL: + case RT5663_STO1_ADC_DIG_VOL: + case RT5663_STO1_BOOST: + case RT5663_HP_IMP_GAIN_1: + case RT5663_HP_IMP_GAIN_2: + case RT5663_STO1_ADC_MIXER: + case RT5663_AD_DA_MIXER: + case RT5663_STO_DAC_MIXER: + case RT5663_DIG_SIDE_MIXER: + case RT5663_BYPASS_STO_DAC: + case RT5663_CALIB_REC_MIX: + case RT5663_PWR_DIG_1: + case RT5663_PWR_DIG_2: + case RT5663_PWR_ANLG_1: + case RT5663_PWR_ANLG_2: + case RT5663_PWR_ANLG_3: + case RT5663_PWR_MIXER: + case RT5663_SIG_CLK_DET: + case RT5663_PRE_DIV_GATING_1: + case RT5663_PRE_DIV_GATING_2: + case RT5663_I2S1_SDP: + case RT5663_ADDA_CLK_1: + case RT5663_ADDA_RST: + case RT5663_FRAC_DIV_1: + case RT5663_FRAC_DIV_2: + case RT5663_TDM_1: + case RT5663_TDM_2: + case RT5663_TDM_3: + case RT5663_TDM_4: + case RT5663_TDM_5: + case RT5663_GLB_CLK: + case RT5663_PLL_1: + case RT5663_PLL_2: + case RT5663_ASRC_1: + case RT5663_ASRC_2: + case RT5663_ASRC_4: + case RT5663_DUMMY_REG: + case RT5663_ASRC_8: + case RT5663_ASRC_9: + case RT5663_ASRC_11: + case RT5663_DEPOP_1: + case RT5663_DEPOP_2: + case RT5663_DEPOP_3: + case RT5663_HP_CHARGE_PUMP_1: + case RT5663_HP_CHARGE_PUMP_2: + case RT5663_MICBIAS_1: + case RT5663_RC_CLK: + case RT5663_ASRC_11_2: + case RT5663_DUMMY_REG_2: + case RT5663_REC_PATH_GAIN: + case RT5663_AUTO_1MRC_CLK: + case RT5663_ADC_EQ_1: + case RT5663_ADC_EQ_2: + case RT5663_IRQ_1: + case RT5663_IRQ_2: + case RT5663_IRQ_3: + case RT5663_IRQ_4: + case RT5663_IRQ_5: + case RT5663_INT_ST_1: + case RT5663_INT_ST_2: + case RT5663_GPIO_1: + case RT5663_GPIO_2: + case RT5663_GPIO_STA: + case RT5663_SIN_GEN_1: + case RT5663_SIN_GEN_2: + case RT5663_SIN_GEN_3: + case RT5663_SOF_VOL_ZC1: + case RT5663_IL_CMD_1: + case RT5663_IL_CMD_2: + case RT5663_IL_CMD_3: + case RT5663_IL_CMD_4: + case RT5663_IL_CMD_5: + case RT5663_IL_CMD_6: + case RT5663_IL_CMD_7: + case RT5663_IL_CMD_8: + case RT5663_IL_CMD_PWRSAV1: + case RT5663_IL_CMD_PWRSAV2: + case RT5663_EM_JACK_TYPE_1: + case RT5663_EM_JACK_TYPE_2: + case RT5663_EM_JACK_TYPE_3: + case RT5663_EM_JACK_TYPE_4: + case RT5663_EM_JACK_TYPE_5: + case RT5663_EM_JACK_TYPE_6: + case RT5663_STO1_HPF_ADJ1: + case RT5663_STO1_HPF_ADJ2: + case RT5663_FAST_OFF_MICBIAS: + case RT5663_JD_CTRL1: + case RT5663_JD_CTRL2: + case RT5663_DIG_MISC: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5663_DIG_VOL_ZCD: + case RT5663_ANA_BIAS_CUR_1: + case RT5663_ANA_BIAS_CUR_2: + case RT5663_ANA_BIAS_CUR_3: + case RT5663_ANA_BIAS_CUR_4: + case RT5663_ANA_BIAS_CUR_5: + case RT5663_ANA_BIAS_CUR_6: + case RT5663_BIAS_CUR_5: + case RT5663_BIAS_CUR_6: + case RT5663_BIAS_CUR_7: + case RT5663_BIAS_CUR_8: + case RT5663_DACREF_LDO: + case RT5663_DUMMY_REG_3: + case RT5663_BIAS_CUR_9: + case RT5663_DUMMY_REG_4: + case RT5663_VREFADJ_OP: + case RT5663_VREF_RECMIX: + case RT5663_CHARGE_PUMP_1: + case RT5663_CHARGE_PUMP_1_2: + case RT5663_CHARGE_PUMP_1_3: + case RT5663_CHARGE_PUMP_2: + case RT5663_DIG_IN_PIN1: + case RT5663_PAD_DRV_CTL: + case RT5663_PLL_INT_REG: + case RT5663_CHOP_DAC_L: + case RT5663_CHOP_ADC: + case RT5663_CALIB_ADC: + case RT5663_CHOP_DAC_R: + case RT5663_DUMMY_CTL_DACLR: + case RT5663_DUMMY_REG_5: + case RT5663_SOFT_RAMP: + case RT5663_TEST_MODE_1: + case RT5663_TEST_MODE_2: + case RT5663_TEST_MODE_3: + case RT5663_STO_DRE_1: + case RT5663_STO_DRE_2: + case RT5663_STO_DRE_3: + case RT5663_STO_DRE_4: + case RT5663_STO_DRE_5: + case RT5663_STO_DRE_6: + case RT5663_STO_DRE_7: + case RT5663_STO_DRE_8: + case RT5663_STO_DRE_9: + case RT5663_STO_DRE_10: + case RT5663_MIC_DECRO_1: + case RT5663_MIC_DECRO_2: + case RT5663_MIC_DECRO_3: + case RT5663_MIC_DECRO_4: + case RT5663_MIC_DECRO_5: + case RT5663_MIC_DECRO_6: + case RT5663_HP_DECRO_1: + case RT5663_HP_DECRO_2: + case RT5663_HP_DECRO_3: + case RT5663_HP_DECRO_4: + case RT5663_HP_DECOUP: + case RT5663_HP_IMP_SEN_MAP8: + case RT5663_HP_IMP_SEN_MAP9: + case RT5663_HP_IMP_SEN_MAP10: + case RT5663_HP_IMP_SEN_MAP11: + case RT5663_HP_IMP_SEN_1: + case RT5663_HP_IMP_SEN_2: + case RT5663_HP_IMP_SEN_3: + case RT5663_HP_IMP_SEN_4: + case RT5663_HP_IMP_SEN_5: + case RT5663_HP_IMP_SEN_6: + case RT5663_HP_IMP_SEN_7: + case RT5663_HP_IMP_SEN_8: + case RT5663_HP_IMP_SEN_9: + case RT5663_HP_IMP_SEN_10: + case RT5663_HP_IMP_SEN_11: + case RT5663_HP_IMP_SEN_12: + case RT5663_HP_IMP_SEN_13: + case RT5663_HP_IMP_SEN_14: + case RT5663_HP_IMP_SEN_15: + case RT5663_HP_IMP_SEN_16: + case RT5663_HP_IMP_SEN_17: + case RT5663_HP_IMP_SEN_18: + case RT5663_HP_IMP_SEN_19: + case RT5663_HP_IMPSEN_DIG5: + case RT5663_HP_IMPSEN_MAP1: + case RT5663_HP_IMPSEN_MAP2: + case RT5663_HP_IMPSEN_MAP3: + case RT5663_HP_IMPSEN_MAP4: + case RT5663_HP_IMPSEN_MAP5: + case RT5663_HP_IMPSEN_MAP7: + case RT5663_HP_LOGIC_1: + case RT5663_HP_LOGIC_2: + case RT5663_HP_CALIB_1: + case RT5663_HP_CALIB_1_1: + case RT5663_HP_CALIB_2: + case RT5663_HP_CALIB_3: + case RT5663_HP_CALIB_4: + case RT5663_HP_CALIB_5: + case RT5663_HP_CALIB_5_1: + case RT5663_HP_CALIB_6: + case RT5663_HP_CALIB_7: + case RT5663_HP_CALIB_9: + case RT5663_HP_CALIB_10: + case RT5663_HP_CALIB_11: + case RT5663_HP_CALIB_ST1: + case RT5663_HP_CALIB_ST2: + case RT5663_HP_CALIB_ST3: + case RT5663_HP_CALIB_ST4: + case RT5663_HP_CALIB_ST5: + case RT5663_HP_CALIB_ST6: + case RT5663_HP_CALIB_ST7: + case RT5663_HP_CALIB_ST8: + case RT5663_HP_CALIB_ST9: + case RT5663_HP_AMP_DET: + case RT5663_DUMMY_REG_6: + case RT5663_HP_BIAS: + case RT5663_CBJ_1: + case RT5663_CBJ_2: + case RT5663_CBJ_3: + case RT5663_DUMMY_1: + case RT5663_DUMMY_2: + case RT5663_DUMMY_3: + case RT5663_ANA_JD: + case RT5663_ADC_LCH_LPF1_A1: + case RT5663_ADC_RCH_LPF1_A1: + case RT5663_ADC_LCH_LPF1_H0: + case RT5663_ADC_RCH_LPF1_H0: + case RT5663_ADC_LCH_BPF1_A1: + case RT5663_ADC_RCH_BPF1_A1: + case RT5663_ADC_LCH_BPF1_A2: + case RT5663_ADC_RCH_BPF1_A2: + case RT5663_ADC_LCH_BPF1_H0: + case RT5663_ADC_RCH_BPF1_H0: + case RT5663_ADC_LCH_BPF2_A1: + case RT5663_ADC_RCH_BPF2_A1: + case RT5663_ADC_LCH_BPF2_A2: + case RT5663_ADC_RCH_BPF2_A2: + case RT5663_ADC_LCH_BPF2_H0: + case RT5663_ADC_RCH_BPF2_H0: + case RT5663_ADC_LCH_BPF3_A1: + case RT5663_ADC_RCH_BPF3_A1: + case RT5663_ADC_LCH_BPF3_A2: + case RT5663_ADC_RCH_BPF3_A2: + case RT5663_ADC_LCH_BPF3_H0: + case RT5663_ADC_RCH_BPF3_H0: + case RT5663_ADC_LCH_BPF4_A1: + case RT5663_ADC_RCH_BPF4_A1: + case RT5663_ADC_LCH_BPF4_A2: + case RT5663_ADC_RCH_BPF4_A2: + case RT5663_ADC_LCH_BPF4_H0: + case RT5663_ADC_RCH_BPF4_H0: + case RT5663_ADC_LCH_HPF1_A1: + case RT5663_ADC_RCH_HPF1_A1: + case RT5663_ADC_LCH_HPF1_H0: + case RT5663_ADC_RCH_HPF1_H0: + case RT5663_ADC_EQ_PRE_VOL_L: + case RT5663_ADC_EQ_PRE_VOL_R: + case RT5663_ADC_EQ_POST_VOL_L: + case RT5663_ADC_EQ_POST_VOL_R: + return true; + default: + return false; + } +} + +static bool rt5668_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5663_RESET: + case RT5668_CBJ_TYPE_2: + case RT5668_PDM_OUT_CTL: + case RT5668_PDM_I2C_DATA_CTL1: + case RT5668_PDM_I2C_DATA_CTL4: + case RT5668_ALC_BK_GAIN: + case RT5663_PLL_2: + case RT5663_MICBIAS_1: + case RT5663_ADC_EQ_1: + case RT5663_INT_ST_1: + case RT5668_GPIO_STA: + case RT5663_IL_CMD_1: + case RT5663_IL_CMD_5: + case RT5668_A_JD_CTRL: + case RT5663_JD_CTRL2: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5663_STO_DRE_1: + case RT5663_STO_DRE_5: + case RT5663_STO_DRE_6: + case RT5663_STO_DRE_7: + case RT5668_MONO_DYNA_6: + case RT5668_STO1_SIL_DET: + case RT5668_MONOL_SIL_DET: + case RT5668_MONOR_SIL_DET: + case RT5668_STO2_DAC_SIL: + case RT5668_MONO_AMP_CAL_ST1: + case RT5668_MONO_AMP_CAL_ST2: + case RT5668_MONO_AMP_CAL_ST3: + case RT5668_MONO_AMP_CAL_ST4: + case RT5663_HP_IMP_SEN_2: + case RT5663_HP_IMP_SEN_3: + case RT5663_HP_IMP_SEN_4: + case RT5663_HP_IMP_SEN_10: + case RT5663_HP_CALIB_1: + case RT5663_HP_CALIB_10: + case RT5663_HP_CALIB_ST1: + case RT5663_HP_CALIB_ST4: + case RT5663_HP_CALIB_ST5: + case RT5663_HP_CALIB_ST6: + case RT5663_HP_CALIB_ST7: + case RT5663_HP_CALIB_ST8: + case RT5663_HP_CALIB_ST9: + case RT5668_HP_CALIB_ST10: + case RT5668_HP_CALIB_ST11: + return true; + default: + return false; + } +} + +static bool rt5668_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5668_LOUT_CTRL: + case RT5668_HP_AMP_2: + case RT5668_MONO_OUT: + case RT5668_MONO_GAIN: + case RT5668_AEC_BST: + case RT5668_IN1_IN2: + case RT5668_IN3_IN4: + case RT5668_INL1_INR1: + case RT5668_CBJ_TYPE_2: + case RT5668_CBJ_TYPE_3: + case RT5668_CBJ_TYPE_4: + case RT5668_CBJ_TYPE_5: + case RT5668_CBJ_TYPE_8: + case RT5668_DAC3_DIG_VOL: + case RT5668_DAC3_CTRL: + case RT5668_MONO_ADC_DIG_VOL: + case RT5668_STO2_ADC_DIG_VOL: + case RT5668_MONO_ADC_BST_GAIN: + case RT5668_STO2_ADC_BST_GAIN: + case RT5668_SIDETONE_CTRL: + case RT5668_MONO1_ADC_MIXER: + case RT5668_STO2_ADC_MIXER: + case RT5668_MONO_DAC_MIXER: + case RT5668_DAC2_SRC_CTRL: + case RT5668_IF_3_4_DATA_CTL: + case RT5668_IF_5_DATA_CTL: + case RT5668_PDM_OUT_CTL: + case RT5668_PDM_I2C_DATA_CTL1: + case RT5668_PDM_I2C_DATA_CTL2: + case RT5668_PDM_I2C_DATA_CTL3: + case RT5668_PDM_I2C_DATA_CTL4: + case RT5668_RECMIX1_NEW: + case RT5668_RECMIX1L_0: + case RT5668_RECMIX1L: + case RT5668_RECMIX1R_0: + case RT5668_RECMIX1R: + case RT5668_RECMIX2_NEW: + case RT5668_RECMIX2_L_2: + case RT5668_RECMIX2_R: + case RT5668_RECMIX2_R_2: + case RT5668_CALIB_REC_LR: + case RT5668_ALC_BK_GAIN: + case RT5668_MONOMIX_GAIN: + case RT5668_MONOMIX_IN_GAIN: + case RT5668_OUT_MIXL_GAIN: + case RT5668_OUT_LMIX_IN_GAIN: + case RT5668_OUT_RMIX_IN_GAIN: + case RT5668_OUT_RMIX_IN_GAIN1: + case RT5668_LOUT_MIXER_CTRL: + case RT5668_PWR_VOL: + case RT5668_ADCDAC_RST: + case RT5668_I2S34_SDP: + case RT5668_I2S5_SDP: + case RT5668_TDM_5: + case RT5668_TDM_6: + case RT5668_TDM_7: + case RT5668_TDM_8: + case RT5668_ASRC_3: + case RT5668_ASRC_6: + case RT5668_ASRC_7: + case RT5668_PLL_TRK_13: + case RT5668_I2S_M_CLK_CTL: + case RT5668_FDIV_I2S34_M_CLK: + case RT5668_FDIV_I2S34_M_CLK2: + case RT5668_FDIV_I2S5_M_CLK: + case RT5668_FDIV_I2S5_M_CLK2: + case RT5668_IRQ_4: + case RT5668_GPIO_3: + case RT5668_GPIO_4: + case RT5668_GPIO_STA: + case RT5668_HP_AMP_DET1: + case RT5668_HP_AMP_DET2: + case RT5668_HP_AMP_DET3: + case RT5668_MID_BD_HP_AMP: + case RT5668_LOW_BD_HP_AMP: + case RT5668_SOF_VOL_ZC2: + case RT5668_ADC_STO2_ADJ1: + case RT5668_ADC_STO2_ADJ2: + case RT5668_A_JD_CTRL: + case RT5668_JD1_TRES_CTRL: + case RT5668_JD2_TRES_CTRL: + case RT5668_JD_CTRL2: + case RT5668_DUM_REG_2: + case RT5668_DUM_REG_3: + case RT5663_VENDOR_ID: + case RT5663_VENDOR_ID_1: + case RT5663_VENDOR_ID_2: + case RT5668_DACADC_DIG_VOL2: + case RT5668_DIG_IN_PIN2: + case RT5668_PAD_DRV_CTL1: + case RT5668_SOF_RAM_DEPOP: + case RT5668_VOL_TEST: + case RT5668_TEST_MODE_3: + case RT5668_TEST_MODE_4: + case RT5663_STO_DRE_9: + case RT5668_MONO_DYNA_1: + case RT5668_MONO_DYNA_2: + case RT5668_MONO_DYNA_3: + case RT5668_MONO_DYNA_4: + case RT5668_MONO_DYNA_5: + case RT5668_MONO_DYNA_6: + case RT5668_STO1_SIL_DET: + case RT5668_MONOL_SIL_DET: + case RT5668_MONOR_SIL_DET: + case RT5668_STO2_DAC_SIL: + case RT5668_PWR_SAV_CTL1: + case RT5668_PWR_SAV_CTL2: + case RT5668_PWR_SAV_CTL3: + case RT5668_PWR_SAV_CTL4: + case RT5668_PWR_SAV_CTL5: + case RT5668_PWR_SAV_CTL6: + case RT5668_MONO_AMP_CAL1: + case RT5668_MONO_AMP_CAL2: + case RT5668_MONO_AMP_CAL3: + case RT5668_MONO_AMP_CAL4: + case RT5668_MONO_AMP_CAL5: + case RT5668_MONO_AMP_CAL6: + case RT5668_MONO_AMP_CAL7: + case RT5668_MONO_AMP_CAL_ST1: + case RT5668_MONO_AMP_CAL_ST2: + case RT5668_MONO_AMP_CAL_ST3: + case RT5668_MONO_AMP_CAL_ST4: + case RT5668_MONO_AMP_CAL_ST5: + case RT5668_HP_IMP_SEN_13: + case RT5668_HP_IMP_SEN_14: + case RT5668_HP_IMP_SEN_6: + case RT5668_HP_IMP_SEN_7: + case RT5668_HP_IMP_SEN_8: + case RT5668_HP_IMP_SEN_9: + case RT5668_HP_IMP_SEN_10: + case RT5668_HP_LOGIC_3: + case RT5668_HP_CALIB_ST10: + case RT5668_HP_CALIB_ST11: + case RT5668_PRO_REG_TBL_4: + case RT5668_PRO_REG_TBL_5: + case RT5668_PRO_REG_TBL_6: + case RT5668_PRO_REG_TBL_7: + case RT5668_PRO_REG_TBL_8: + case RT5668_PRO_REG_TBL_9: + case RT5668_SAR_ADC_INL_1: + case RT5668_SAR_ADC_INL_2: + case RT5668_SAR_ADC_INL_3: + case RT5668_SAR_ADC_INL_4: + case RT5668_SAR_ADC_INL_5: + case RT5668_SAR_ADC_INL_6: + case RT5668_SAR_ADC_INL_7: + case RT5668_SAR_ADC_INL_8: + case RT5668_SAR_ADC_INL_9: + case RT5668_SAR_ADC_INL_10: + case RT5668_SAR_ADC_INL_11: + case RT5668_SAR_ADC_INL_12: + case RT5668_DRC_CTRL_1: + case RT5668_DRC1_CTRL_2: + case RT5668_DRC1_CTRL_3: + case RT5668_DRC1_CTRL_4: + case RT5668_DRC1_CTRL_5: + case RT5668_DRC1_CTRL_6: + case RT5668_DRC1_HD_CTRL_1: + case RT5668_DRC1_HD_CTRL_2: + case RT5668_DRC1_PRI_REG_1: + case RT5668_DRC1_PRI_REG_2: + case RT5668_DRC1_PRI_REG_3: + case RT5668_DRC1_PRI_REG_4: + case RT5668_DRC1_PRI_REG_5: + case RT5668_DRC1_PRI_REG_6: + case RT5668_DRC1_PRI_REG_7: + case RT5668_DRC1_PRI_REG_8: + case RT5668_ALC_PGA_CTL_1: + case RT5668_ALC_PGA_CTL_2: + case RT5668_ALC_PGA_CTL_3: + case RT5668_ALC_PGA_CTL_4: + case RT5668_ALC_PGA_CTL_5: + case RT5668_ALC_PGA_CTL_6: + case RT5668_ALC_PGA_CTL_7: + case RT5668_ALC_PGA_CTL_8: + case RT5668_ALC_PGA_REG_1: + case RT5668_ALC_PGA_REG_2: + case RT5668_ALC_PGA_REG_3: + case RT5668_ADC_EQ_RECOV_1: + case RT5668_ADC_EQ_RECOV_2: + case RT5668_ADC_EQ_RECOV_3: + case RT5668_ADC_EQ_RECOV_4: + case RT5668_ADC_EQ_RECOV_5: + case RT5668_ADC_EQ_RECOV_6: + case RT5668_ADC_EQ_RECOV_7: + case RT5668_ADC_EQ_RECOV_8: + case RT5668_ADC_EQ_RECOV_9: + case RT5668_ADC_EQ_RECOV_10: + case RT5668_ADC_EQ_RECOV_11: + case RT5668_ADC_EQ_RECOV_12: + case RT5668_ADC_EQ_RECOV_13: + case RT5668_VID_HIDDEN: + case RT5668_VID_CUSTOMER: + case RT5668_SCAN_MODE: + case RT5668_I2C_BYPA: + return true; + case RT5663_TDM_1: + case RT5663_DEPOP_3: + case RT5663_ASRC_11_2: + case RT5663_INT_ST_2: + case RT5663_GPIO_STA: + case RT5663_SIN_GEN_1: + case RT5663_SIN_GEN_2: + case RT5663_SIN_GEN_3: + case RT5663_IL_CMD_PWRSAV1: + case RT5663_IL_CMD_PWRSAV2: + case RT5663_EM_JACK_TYPE_1: + case RT5663_EM_JACK_TYPE_2: + case RT5663_EM_JACK_TYPE_3: + case RT5663_EM_JACK_TYPE_4: + case RT5663_FAST_OFF_MICBIAS: + case RT5663_ANA_BIAS_CUR_1: + case RT5663_ANA_BIAS_CUR_2: + case RT5663_BIAS_CUR_9: + case RT5663_DUMMY_REG_4: + case RT5663_VREF_RECMIX: + case RT5663_CHARGE_PUMP_1_2: + case RT5663_CHARGE_PUMP_1_3: + case RT5663_CHARGE_PUMP_2: + case RT5663_CHOP_DAC_R: + case RT5663_DUMMY_CTL_DACLR: + case RT5663_DUMMY_REG_5: + case RT5663_SOFT_RAMP: + case RT5663_TEST_MODE_1: + case RT5663_STO_DRE_10: + case RT5663_MIC_DECRO_1: + case RT5663_MIC_DECRO_2: + case RT5663_MIC_DECRO_3: + case RT5663_MIC_DECRO_4: + case RT5663_MIC_DECRO_5: + case RT5663_MIC_DECRO_6: + case RT5663_HP_DECRO_1: + case RT5663_HP_DECRO_2: + case RT5663_HP_DECRO_3: + case RT5663_HP_DECRO_4: + case RT5663_HP_DECOUP: + case RT5663_HP_IMPSEN_MAP4: + case RT5663_HP_IMPSEN_MAP5: + case RT5663_HP_IMPSEN_MAP7: + case RT5663_HP_CALIB_1: + case RT5663_CBJ_1: + case RT5663_CBJ_2: + case RT5663_CBJ_3: + return false; + default: + return rt5663_readable_register(dev, reg); + } +} + +static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0); +static const DECLARE_TLV_DB_SCALE(rt5668_hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static const DECLARE_TLV_DB_RANGE(in_bst_tlv, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); + +/* Interface data select */ +static const char * const rt5663_if1_adc_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5663_if1_adc_enum, RT5663_TDM_2, + RT5663_DATA_SWAP_ADCDAT1_SHIFT, rt5663_if1_adc_data_select); + +static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec, + bool enable) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + if (enable) { + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_EN); + /* reset in-line command */ + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_RESET); + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_NOR); + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + snd_soc_update_bits(codec, RT5663_IRQ_3, + RT5668_EN_IRQ_INLINE_MASK, + RT5668_EN_IRQ_INLINE_NOR); + break; + case CODEC_TYPE_RT5663: + snd_soc_update_bits(codec, RT5663_IRQ_2, + RT5663_EN_IRQ_INLINE_MASK, + RT5663_EN_IRQ_INLINE_NOR); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } else { + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + snd_soc_update_bits(codec, RT5663_IRQ_3, + RT5668_EN_IRQ_INLINE_MASK, + RT5668_EN_IRQ_INLINE_BYP); + break; + case CODEC_TYPE_RT5663: + snd_soc_update_bits(codec, RT5663_IRQ_2, + RT5663_EN_IRQ_INLINE_MASK, + RT5663_EN_IRQ_INLINE_BYP); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_DIS); + /* reset in-line command */ + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_RESET); + snd_soc_update_bits(codec, RT5663_IL_CMD_6, + RT5668_RESET_4BTN_INL_MASK, + RT5668_RESET_4BTN_INL_NOR); + } +} + +/** + * rt5668_jack_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ + +static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; + + dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert); + if (jack_insert) { + snd_soc_write(codec, RT5668_CBJ_TYPE_2, 0x8040); + snd_soc_write(codec, RT5668_CBJ_TYPE_3, 0x1484); + + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2"); + snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_force_enable_pin(dapm, "CBJ Power"); + snd_soc_dapm_sync(dapm); + snd_soc_update_bits(codec, RT5663_RC_CLK, + RT5668_DIG_1M_CLK_MASK, RT5668_DIG_1M_CLK_EN); + snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8); + + while (i < 5) { + msleep(sleep_time[i]); + val = snd_soc_read(codec, RT5668_CBJ_TYPE_2) & 0x0003; + if (val == 0x1 || val == 0x2 || val == 0x3) + break; + dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n", + __func__, val, sleep_time[i]); + i++; + } + dev_dbg(codec->dev, "%s val = %d\n", __func__, val); + switch (val) { + case 1: + case 2: + rt5668->jack_type = SND_JACK_HEADSET; + rt5663_enable_push_button_irq(codec, true); + break; + default: + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_disable_pin(dapm, "CBJ Power"); + snd_soc_dapm_sync(dapm); + rt5668->jack_type = SND_JACK_HEADPHONE; + break; + } + } else { + snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0); + + if (rt5668->jack_type == SND_JACK_HEADSET) { + rt5663_enable_push_button_irq(codec, false); + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_disable_pin(dapm, "CBJ Power"); + snd_soc_dapm_sync(dapm); + } + rt5668->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5668->jack_type); + return rt5668->jack_type; +} + +/** + * rt5663_jack_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ +static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; + + dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert); + + if (jack_insert) { + snd_soc_update_bits(codec, RT5663_DIG_MISC, + RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN); + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5663_SI_HP_MASK | RT5668_OSW_HP_L_MASK | + RT5668_OSW_HP_R_MASK, RT5663_SI_HP_EN | + RT5668_OSW_HP_L_DIS | RT5668_OSW_HP_R_DIS); + snd_soc_update_bits(codec, RT5663_DUMMY_1, + RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK | + RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN | + RT5663_HPA_CPL_BIAS_1 | RT5663_HPA_CPR_BIAS_1); + snd_soc_update_bits(codec, RT5663_CBJ_1, + RT5663_INBUF_CBJ_BST1_MASK | RT5663_CBJ_SENSE_BST1_MASK, + RT5663_INBUF_CBJ_BST1_ON | RT5663_CBJ_SENSE_BST1_L); + snd_soc_update_bits(codec, RT5663_IL_CMD_2, + RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON); + /* BST1 power on for JD */ + snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, + RT5668_PWR_BST1_MASK, RT5668_PWR_BST1_ON); + snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1, + RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK | + RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN | + RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN); + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_MB_MASK | RT5668_LDO1_DVO_MASK | + RT5668_AMP_HP_MASK, RT5668_PWR_MB | + RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK, + RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN); + snd_soc_update_bits(codec, RT5663_IRQ_1, + RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); + while (i < 5) { + msleep(sleep_time[i]); + val = snd_soc_read(codec, RT5663_EM_JACK_TYPE_2) & + 0x0003; + i++; + if (val == 0x1 || val == 0x2 || val == 0x3) + break; + dev_dbg(codec->dev, "%s: MX-00e7 val=%x sleep %d\n", + __func__, val, sleep_time[i]); + } + dev_dbg(codec->dev, "%s val = %d\n", __func__, val); + switch (val) { + case 1: + case 2: + rt5663->jack_type = SND_JACK_HEADSET; + rt5663_enable_push_button_irq(codec, true); + break; + default: + rt5663->jack_type = SND_JACK_HEADPHONE; + break; + } + } else { + if (rt5663->jack_type == SND_JACK_HEADSET) + rt5663_enable_push_button_irq(codec, false); + rt5663->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type); + return rt5663->jack_type; +} + +static int rt5663_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5663_IL_CMD_5); + dev_dbg(codec->dev, "%s: val=0x%x\n", __func__, val); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5663_IL_CMD_5, val); + + return btn_type; +} + +static irqreturn_t rt5663_irq(int irq, void *data) +{ + struct rt5663_priv *rt5663 = data; + + dev_dbg(rt5663->codec->dev, "%s IRQ queue work\n", __func__); + + queue_delayed_work(system_wq, &rt5663->jack_detect_work, + msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +int rt5663_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + rt5663->hs_jack = hs_jack; + + rt5663_irq(0, rt5663); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5663_set_jack_detect); + +static bool rt5663_check_jd_status(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + int val = snd_soc_read(codec, RT5663_INT_ST_1); + + dev_dbg(codec->dev, "%s val=%x\n", __func__, val); + + /* JD1 */ + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + return !(val & 0x2000); + case CODEC_TYPE_RT5663: + return !(val & 0x1000); + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + + return false; +} + +static void rt5663_jack_detect_work(struct work_struct *work) +{ + struct rt5663_priv *rt5663 = + container_of(work, struct rt5663_priv, jack_detect_work.work); + struct snd_soc_codec *codec = rt5663->codec; + int btn_type, report = 0; + + if (!codec) + return; + + if (rt5663_check_jd_status(codec)) { + /* jack in */ + if (rt5663->jack_type == 0) { + /* jack was out, report jack type */ + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + report = rt5668_jack_detect(rt5663->codec, 1); + break; + case CODEC_TYPE_RT5663: + report = rt5663_jack_detect(rt5663->codec, 1); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } else { + /* jack is already in, report button event */ + report = SND_JACK_HEADSET; + btn_type = rt5663_button_detect(rt5663->codec); + /** + * rt5663 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + report |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + report |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + report |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + report |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + btn_type = 0; + dev_err(rt5663->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + /* button release or spurious interrput*/ + if (btn_type == 0) + report = rt5663->jack_type; + } + } else { + /* jack out */ + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + report = rt5668_jack_detect(rt5663->codec, 0); + break; + case CODEC_TYPE_RT5663: + report = rt5663_jack_detect(rt5663->codec, 0); + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } + dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report); + snd_soc_jack_report(rt5663->hs_jack, report, SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); +} + +static const struct snd_kcontrol_new rt5663_snd_controls[] = { + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL, + RT5668_DAC_L1_VOL_SHIFT + 1, RT5668_DAC_R1_VOL_SHIFT + 1, + 87, 0, dac_vol_tlv), + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL, + RT5668_ADC_L_MUTE_SHIFT, RT5668_ADC_R_MUTE_SHIFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL, + RT5668_ADC_L_VOL_SHIFT + 1, RT5668_ADC_R_VOL_SHIFT + 1, + 63, 0, adc_vol_tlv), +}; + +static const struct snd_kcontrol_new rt5668_specific_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE, + RT5663_HP_RCH_DRE, RT5668_GAIN_HP_SHIFT, 15, 1, + rt5668_hp_vol_tlv), + /* Mic Boost Volume */ + SOC_SINGLE_TLV("IN1 Capture Volume", RT5668_AEC_BST, + RT5668_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv), +}; + +static const struct snd_kcontrol_new rt5663_specific_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_STO_DRE_9, + RT5663_STO_DRE_10, RT5663_DRE_GAIN_HP_SHIFT, 23, 1, + rt5663_hp_vol_tlv), + /* Mic Boost Volume*/ + SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_CBJ_2, + RT5663_GAIN_BST1_SHIFT, 8, 0, in_bst_tlv), + /* Data Swap for Slot0/1 in ADCDAT1 */ + SOC_ENUM("IF1 ADC Data Swap", rt5663_if1_adc_enum), +}; + +static int rt5663_is_sys_clk_from_pll(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + val = snd_soc_read(codec, RT5663_GLB_CLK); + val &= RT5663_SCLK_SRC_MASK; + if (val == RT5663_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + switch (w->shift) { + case RT5668_ADC_STO1_ASRC_SHIFT: + reg = RT5668_ASRC_3; + shift = RT5668_AD_STO1_TRACK_SHIFT; + break; + case RT5668_DAC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_2; + shift = RT5668_DA_STO1_TRACK_SHIFT; + break; + default: + return 0; + } + } else { + switch (w->shift) { + case RT5663_ADC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_2; + shift = RT5663_AD_STO1_TRACK_SHIFT; + break; + case RT5663_DAC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_2; + shift = RT5663_DA_STO1_TRACK_SHIFT; + break; + default: + return 0; + } + } + + val = (snd_soc_read(codec, reg) >> shift) & 0x7; + + if (val) + return 1; + + return 0; +} + +static int rt5663_i2s_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 rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + int da_asrc_en, ad_asrc_en; + + da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & + RT5663_DA_STO1_TRACK_MASK) ? 1 : 0; + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + ad_asrc_en = (snd_soc_read(codec, RT5668_ASRC_3) & + RT5668_AD_STO1_TRACK_MASK) ? 1 : 0; + break; + case CODEC_TYPE_RT5663: + ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & + RT5663_AD_STO1_TRACK_MASK) ? 1 : 0; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + return 1; + } + + if (da_asrc_en || ad_asrc_en) + if (rt5663->sysclk > rt5663->lrck * 384) + return 1; + + dev_err(codec->dev, "sysclk < 384 x fs, disable i2s asrc\n"); + + return 0; +} + +/** + * rt5663_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 RT5668 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 rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + unsigned int asrc3_mask = 0; + unsigned int asrc3_value = 0; + + switch (clk_src) { + case RT5663_CLK_SEL_SYS: + case RT5663_CLK_SEL_I2S1_ASRC: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5663_DA_STEREO_FILTER) { + asrc2_mask |= RT5668_DA_STO1_TRACK_MASK; + asrc2_value |= clk_src << RT5668_DA_STO1_TRACK_SHIFT; + } + + if (filter_mask & RT5663_AD_STEREO_FILTER) { + switch (rt5668->codec_type) { + case CODEC_TYPE_RT5668: + asrc3_mask |= RT5668_AD_STO1_TRACK_MASK; + asrc3_value |= clk_src << RT5668_AD_STO1_TRACK_SHIFT; + break; + case CODEC_TYPE_RT5663: + asrc2_mask |= RT5663_AD_STO1_TRACK_MASK; + asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + } + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5663_ASRC_2, asrc2_mask, + asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5668_ASRC_3, asrc3_mask, + asrc3_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src); + +/* Analog Mixer */ +static const struct snd_kcontrol_new rt5668_recmix1l[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1L, + RT5668_RECMIX1L_BST2_SHIFT, 1, 1), + SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5668_RECMIX1L, + RT5668_RECMIX1L_BST1_CBJ_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5668_recmix1r[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1R, + RT5668_RECMIX1R_BST2_SHIFT, 1, 1), +}; + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_L1_SHIFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_L2_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_R1_SHIFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, + RT5668_M_STO1_ADC_R2_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_adda_l_mix[] = { + SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER, + RT5668_M_ADCMIX_L_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER, + RT5668_M_DAC1_L_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_adda_r_mix[] = { + SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER, + RT5668_M_ADCMIX_R_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER, + RT5668_M_DAC1_R_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_L1_STO_L_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_R1_STO_L_SHIFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_L1_STO_R_SHIFT, 1, 1), + SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, + RT5668_M_DAC_R1_STO_R_SHIFT, 1, 1), +}; + +/* Out Switch */ +static const struct snd_kcontrol_new rt5668_hpo_switch = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_AMP_2, + RT5668_EN_DAC_HPO_SHIFT, 1, 0); + +/* Stereo ADC source */ +static const char * const rt5668_sto1_adc_src[] = { + "ADC L", "ADC R" +}; + +static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_L_SRC_SHIFT, rt5668_sto1_adc_src); + +static const struct snd_kcontrol_new rt5668_sto1_adcl_mux = + SOC_DAPM_ENUM("STO1 ADC L Mux", rt5668_sto1_adcl_enum); + +static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_R_SRC_SHIFT, rt5668_sto1_adc_src); + +static const struct snd_kcontrol_new rt5668_sto1_adcr_mux = + SOC_DAPM_ENUM("STO1 ADC R Mux", rt5668_sto1_adcr_enum); + +/* RT5663: Analog DACL1 input source */ +static const char * const rt5663_alg_dacl_src[] = { + "DAC L", "STO DAC MIXL" +}; + +static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacl_enum, RT5663_BYPASS_STO_DAC, + RT5663_DACL1_SRC_SHIFT, rt5663_alg_dacl_src); + +static const struct snd_kcontrol_new rt5663_alg_dacl_mux = + SOC_DAPM_ENUM("DAC L Mux", rt5663_alg_dacl_enum); + +/* RT5663: Analog DACR1 input source */ +static const char * const rt5663_alg_dacr_src[] = { + "DAC R", "STO DAC MIXR" +}; + +static SOC_ENUM_SINGLE_DECL(rt5663_alg_dacr_enum, RT5663_BYPASS_STO_DAC, + RT5663_DACR1_SRC_SHIFT, rt5663_alg_dacr_src); + +static const struct snd_kcontrol_new rt5663_alg_dacr_mux = + SOC_DAPM_ENUM("DAC R Mux", rt5663_alg_dacr_enum); + +static int rt5663_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5668_SEL_PM_HP_SHIFT, RT5668_SEL_PM_HP_HIGH); + snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, + RT5668_HP_SIG_SRC1_MASK, + RT5668_HP_SIG_SRC1_SILENCE); + } else { + snd_soc_write(codec, RT5663_DEPOP_2, 0x3003); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, + 0x000b); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, + 0x0030); + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_DIS); + snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371); + snd_soc_write(codec, RT5663_HP_BIAS, 0xabba); + snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224); + snd_soc_write(codec, RT5663_ANA_BIAS_CUR_1, 0x7766); + snd_soc_write(codec, RT5663_HP_BIAS, 0xafaa); + snd_soc_write(codec, RT5663_CHARGE_PUMP_2, 0x7777); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, + 0x3000); + } + break; + + case SND_SOC_DAPM_PRE_PMD: + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, + RT5668_HP_SIG_SRC1_MASK, + RT5668_HP_SIG_SRC1_REG); + } else { + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0); + snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, + RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_EN); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0); + snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, + 0x000b); + } + break; + + default: + return 0; + } + + return 0; +} + +static int rt5668_bst2_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, + RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, + RT5668_PWR_BST2 | RT5668_PWR_BST2_OP); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, + RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0xff00); + snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0xfffc); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, RT5663_PRE_DIV_GATING_1, 0x0000); + snd_soc_write(codec, RT5663_PRE_DIV_GATING_2, 0x0000); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5668_PWR_PLL_SHIFT, 0, + NULL, 0), + + /* micbias */ + SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2, + RT5668_PWR_MB1_SHIFT, 0), + SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2, + RT5668_PWR_MB2_SHIFT, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + + /* REC Mixer Power */ + SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2, + RT5668_PWR_RECMIX1_SHIFT, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1, + RT5668_PWR_ADC_L1_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC, + RT5668_CKGEN_ADCC_SHIFT, 0, NULL, 0), + + /* ADC Mixer */ + SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM, + 0, 0, rt5663_sto1_adc_l_mix, + ARRAY_SIZE(rt5663_sto1_adc_l_mix)), + + /* ADC Filter Power */ + SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2, + RT5668_PWR_ADC_S1F_SHIFT, 0, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5668_PWR_I2S1_SHIFT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIFTX", "AIF Capture", 0, SND_SOC_NOPM, 0, 0), + + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("ADDA MIXL", SND_SOC_NOPM, 0, 0, rt5663_adda_l_mix, + ARRAY_SIZE(rt5663_adda_l_mix)), + SND_SOC_DAPM_MIXER("ADDA MIXR", SND_SOC_NOPM, 0, 0, rt5663_adda_r_mix, + ARRAY_SIZE(rt5663_adda_r_mix)), + SND_SOC_DAPM_PGA("DAC L1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC R1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2, + RT5668_PWR_DAC_S1F_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)), + SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5663_sto1_dac_r_mix, ARRAY_SIZE(rt5663_sto1_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1, + RT5668_PWR_DAC_L1_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1, + RT5668_PWR_DAC_R1_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0), + + /* Headphone*/ + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5663_hp_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), +}; + +static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3, + RT5668_PWR_LDO2_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5668_PWR_VOL, + RT5668_PWR_MIC_DET_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1, + RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, + RT5668_I2S1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1, + RT5668_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1, + RT5668_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3, + RT5668_PWR_CBJ_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0, + rt5668_bst2_power, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_recmix1l, + ARRAY_SIZE(rt5668_recmix1l)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5668_recmix1r, + ARRAY_SIZE(rt5668_recmix1r)), + SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2, + RT5668_PWR_RECMIX2_SHIFT, 0, NULL, 0), + + /* ADC */ + SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1, + RT5668_PWR_ADC_R1_SHIFT, 0, NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER, + RT5668_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0), + + SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5668_sto1_adcl_mux), + SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5668_sto1_adcr_mux), + + /* ADC Mix */ + SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5668_sto1_adc_r_mix, ARRAY_SIZE(rt5668_sto1_adc_r_mix)), + + /* Analog DAC Clock */ + SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L, + RT5668_CKGEN_DAC1_SHIFT, 0, NULL, 0), + + /* Headphone out */ + SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, + &rt5668_hpo_switch), +}; + +static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = { + /* System Clock Pre Divider Gating */ + SND_SOC_DAPM_SUPPLY("Pre Div Power", SND_SOC_NOPM, 0, 0, + rt5663_pre_div_power, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* LDO */ + SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1, + RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, + RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1, + RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1, + RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* STO ADC */ + SND_SOC_DAPM_PGA("STO1 ADC L1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("STO1 ADC L2", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Analog DAC source */ + SND_SOC_DAPM_MUX("DAC L Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacl_mux), + SND_SOC_DAPM_MUX("DAC R Mux", SND_SOC_NOPM, 0, 0, &rt5663_alg_dacr_mux), +}; + +static const struct snd_soc_dapm_route rt5663_dapm_routes[] = { + /* PLL */ + { "I2S", NULL, "PLL", rt5663_is_sys_clk_from_pll }, + + /* ASRC */ + { "STO1 ADC Filter", NULL, "ADC ASRC", rt5663_is_using_asrc }, + { "STO1 DAC Filter", NULL, "DAC ASRC", rt5663_is_using_asrc }, + { "I2S", NULL, "I2S ASRC", rt5663_i2s_use_asrc }, + + { "ADC L", NULL, "ADC L Power" }, + { "ADC L", NULL, "ADC Clock" }, + + { "STO1 ADC L2", NULL, "STO1 DAC MIXL" }, + + { "STO1 ADC MIXL", "ADC1 Switch", "STO1 ADC L1" }, + { "STO1 ADC MIXL", "ADC2 Switch", "STO1 ADC L2" }, + { "STO1 ADC MIXL", NULL, "STO1 ADC Filter" }, + + { "IF1 ADC1", NULL, "STO1 ADC MIXL" }, + { "IF ADC", NULL, "IF1 ADC1" }, + { "AIFTX", NULL, "IF ADC" }, + { "AIFTX", NULL, "I2S" }, + + { "AIFRX", NULL, "I2S" }, + { "IF DAC", NULL, "AIFRX" }, + { "IF1 DAC1 L", NULL, "IF DAC" }, + { "IF1 DAC1 R", NULL, "IF DAC" }, + + { "ADDA MIXL", "ADC L Switch", "STO1 ADC MIXL" }, + { "ADDA MIXL", "DAC L Switch", "IF1 DAC1 L" }, + { "ADDA MIXL", NULL, "STO1 DAC Filter" }, + { "ADDA MIXL", NULL, "STO1 DAC L Power" }, + { "ADDA MIXR", "DAC R Switch", "IF1 DAC1 R" }, + { "ADDA MIXR", NULL, "STO1 DAC Filter" }, + { "ADDA MIXR", NULL, "STO1 DAC R Power" }, + + { "DAC L1", NULL, "ADDA MIXL" }, + { "DAC R1", NULL, "ADDA MIXR" }, + + { "STO1 DAC MIXL", "DAC L Switch", "DAC L1" }, + { "STO1 DAC MIXL", "DAC R Switch", "DAC R1" }, + { "STO1 DAC MIXL", NULL, "STO1 DAC L Power" }, + { "STO1 DAC MIXL", NULL, "STO1 DAC Filter" }, + { "STO1 DAC MIXR", "DAC R Switch", "DAC R1" }, + { "STO1 DAC MIXR", "DAC L Switch", "DAC L1" }, + { "STO1 DAC MIXR", NULL, "STO1 DAC R Power" }, + { "STO1 DAC MIXR", NULL, "STO1 DAC Filter" }, + + { "HP Amp", NULL, "DAC L" }, + { "HP Amp", NULL, "DAC R" }, +}; + +static const struct snd_soc_dapm_route rt5668_specific_dapm_routes[] = { + { "MICBIAS1", NULL, "LDO2" }, + { "MICBIAS2", NULL, "LDO2" }, + + { "BST1 CBJ", NULL, "IN1P" }, + { "BST1 CBJ", NULL, "IN1N" }, + { "BST1 CBJ", NULL, "CBJ Power" }, + + { "BST2", NULL, "IN2P" }, + { "BST2", NULL, "IN2N" }, + { "BST2", NULL, "BST2 Power" }, + + { "RECMIX1L", "BST2 Switch", "BST2" }, + { "RECMIX1L", "BST1 CBJ Switch", "BST1 CBJ" }, + { "RECMIX1L", NULL, "RECMIX1L Power" }, + { "RECMIX1R", "BST2 Switch", "BST2" }, + { "RECMIX1R", NULL, "RECMIX1R Power" }, + + { "ADC L", NULL, "RECMIX1L" }, + { "ADC R", NULL, "RECMIX1R" }, + { "ADC R", NULL, "ADC R Power" }, + { "ADC R", NULL, "ADC Clock" }, + + { "STO1 ADC L Mux", "ADC L", "ADC L" }, + { "STO1 ADC L Mux", "ADC R", "ADC R" }, + { "STO1 ADC L1", NULL, "STO1 ADC L Mux" }, + + { "STO1 ADC R Mux", "ADC L", "ADC L" }, + { "STO1 ADC R Mux", "ADC R", "ADC R" }, + { "STO1 ADC R1", NULL, "STO1 ADC R Mux" }, + { "STO1 ADC R2", NULL, "STO1 DAC MIXR" }, + + { "STO1 ADC MIXR", "ADC1 Switch", "STO1 ADC R1" }, + { "STO1 ADC MIXR", "ADC2 Switch", "STO1 ADC R2" }, + { "STO1 ADC MIXR", NULL, "STO1 ADC Filter" }, + + { "IF1 ADC1", NULL, "STO1 ADC MIXR" }, + + { "ADDA MIXR", "ADC R Switch", "STO1 ADC MIXR" }, + + { "DAC L", NULL, "STO1 DAC MIXL" }, + { "DAC L", NULL, "LDO DAC" }, + { "DAC L", NULL, "DAC Clock" }, + { "DAC R", NULL, "STO1 DAC MIXR" }, + { "DAC R", NULL, "LDO DAC" }, + { "DAC R", NULL, "DAC Clock" }, + + { "HPO Playback", "Switch", "HP Amp" }, + { "HPOL", NULL, "HPO Playback" }, + { "HPOR", NULL, "HPO Playback" }, +}; + +static const struct snd_soc_dapm_route rt5663_specific_dapm_routes[] = { + { "I2S", NULL, "Pre Div Power" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST1", NULL, "RECMIX1L Power" }, + + { "ADC L", NULL, "BST1" }, + + { "STO1 ADC L1", NULL, "ADC L" }, + + { "DAC L Mux", "DAC L", "DAC L1" }, + { "DAC L Mux", "STO DAC MIXL", "STO1 DAC MIXL" }, + { "DAC R Mux", "DAC R", "DAC R1"}, + { "DAC R Mux", "STO DAC MIXR", "STO1 DAC MIXR" }, + + { "DAC L", NULL, "DAC L Mux" }, + { "DAC R", NULL, "DAC R Mux" }, + + { "HPOL", NULL, "HP Amp" }, + { "HPOR", NULL, "HP Amp" }, +}; + +static int rt5663_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0; + int pre_div; + + rt5663->lrck = params_rate(params); + + dev_dbg(dai->dev, "bclk is %dHz and sysclk is %dHz\n", + rt5663->lrck, rt5663->sysclk); + + pre_div = rl6231_get_clk_info(rt5663->sysclk, rt5663->lrck); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5663->lrck, dai->id); + return -EINVAL; + } + + dev_dbg(dai->dev, "pre_div is %d for iis %d\n", pre_div, dai->id); + + switch (params_width(params)) { + case 8: + val_len = RT5668_I2S_DL_8; + break; + case 16: + val_len = RT5668_I2S_DL_16; + break; + case 20: + val_len = RT5668_I2S_DL_20; + break; + case 24: + val_len = RT5668_I2S_DL_24; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5663_I2S1_SDP, + RT5668_I2S_DL_MASK, val_len); + + snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, + RT5668_I2S_PD1_MASK, pre_div << RT5668_I2S_PD1_SHIFT); + + return 0; +} + +static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5668_I2S_MS_S; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5668_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5668_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5668_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5668_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5668_I2S_MS_MASK | + RT5668_I2S_BP_MASK | RT5668_I2S_DF_MASK, reg_val); + + return 0; +} + +static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5663->sysclk && clk_id == rt5663->sysclk_src) + return 0; + + switch (clk_id) { + case RT5663_SCLK_S_MCLK: + reg_val |= RT5663_SCLK_SRC_MCLK; + break; + case RT5663_SCLK_S_PLL1: + reg_val |= RT5663_SCLK_SRC_PLL1; + break; + case RT5663_SCLK_S_RCCLK: + reg_val |= RT5663_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5668_SCLK_SRC_MASK, + reg_val); + rt5663->sysclk = freq; + rt5663->sysclk_src = clk_id; + + dev_dbg(codec->dev, "Sysclk is %dHz and clock id is %d\n", + freq, clk_id); + + return 0; +} + +static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + int mask, shift, val; + + if (source == rt5663->pll_src && freq_in == rt5663->pll_in && + freq_out == rt5663->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5663->pll_in = 0; + rt5663->pll_out = 0; + snd_soc_update_bits(codec, RT5663_GLB_CLK, + RT5663_SCLK_SRC_MASK, RT5663_SCLK_SRC_MCLK); + return 0; + } + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + mask = RT5668_PLL1_SRC_MASK; + shift = RT5668_PLL1_SRC_SHIFT; + break; + case CODEC_TYPE_RT5663: + mask = RT5663_PLL1_SRC_MASK; + shift = RT5663_PLL1_SRC_SHIFT; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + return -EINVAL; + } + + switch (source) { + case RT5663_PLL1_S_MCLK: + val = 0x0; + break; + case RT5663_PLL1_S_BCLK1: + val = 0x1; + break; + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5663_GLB_CLK, mask, (val << shift)); + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", pll_code.m_bp, + (pll_code.m_bp ? 0 : pll_code.m_code), pll_code.n_code, + pll_code.k_code); + + snd_soc_write(codec, RT5663_PLL_1, + pll_code.n_code << RT5668_PLL_N_SHIFT | pll_code.k_code); + snd_soc_write(codec, RT5663_PLL_2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SHIFT | + pll_code.m_bp << RT5668_PLL_M_BP_SHIFT); + + rt5663->pll_in = freq_in; + rt5663->pll_out = freq_out; + rt5663->pll_src = source; + + return 0; +} + +static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0, reg; + + if (rx_mask || tx_mask) + val |= RT5668_TDM_MODE_TDM; + + switch (slots) { + case 4: + val |= RT5668_TDM_IN_CH_4; + val |= RT5668_TDM_OUT_CH_4; + break; + case 6: + val |= RT5668_TDM_IN_CH_6; + val |= RT5668_TDM_OUT_CH_6; + break; + case 8: + val |= RT5668_TDM_IN_CH_8; + val |= RT5668_TDM_OUT_CH_8; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= RT5668_TDM_IN_LEN_20; + val |= RT5668_TDM_OUT_LEN_20; + break; + case 24: + val |= RT5668_TDM_IN_LEN_24; + val |= RT5668_TDM_OUT_LEN_24; + break; + case 32: + val |= RT5668_TDM_IN_LEN_32; + val |= RT5668_TDM_OUT_LEN_32; + break; + case 16: + break; + default: + return -EINVAL; + } + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + reg = RT5663_TDM_2; + break; + case CODEC_TYPE_RT5663: + reg = RT5663_TDM_1; + break; + default: + dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, reg, RT5668_TDM_MODE_MASK | + RT5668_TDM_IN_CH_MASK | RT5668_TDM_OUT_CH_MASK | + RT5668_TDM_IN_LEN_MASK | RT5668_TDM_OUT_LEN_MASK, val); + + return 0; +} + +static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + unsigned int reg; + + dev_dbg(codec->dev, "%s ratio = %d\n", __func__, ratio); + + if (rt5663->codec_type == CODEC_TYPE_RT5668) + reg = RT5668_TDM_8; + else + reg = RT5663_TDM_5; + + switch (ratio) { + case 32: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_16); + break; + case 40: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_20); + break; + case 48: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_24); + break; + case 64: + snd_soc_update_bits(codec, reg, + RT5663_TDM_LENGTN_MASK, + RT5663_TDM_LENGTN_32); + break; + default: + dev_err(codec->dev, "Invalid ratio!\n"); + return -EINVAL; + } + + return 0; +} + +static int rt5663_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_ON: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK, + RT5668_PWR_FV1 | RT5668_PWR_FV2); + break; + + case SND_SOC_BIAS_PREPARE: + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_DIG_MISC, + RT5668_DIG_GATE_CTRL_MASK, + RT5668_DIG_GATE_CTRL_EN); + snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, + RT5668_EN_ANA_CLK_DET_MASK | + RT5668_PWR_CLK_DET_MASK, + RT5668_EN_ANA_CLK_DET_AUTO | + RT5668_PWR_CLK_DET_EN); + } + break; + + case SND_SOC_BIAS_STANDBY: + if (rt5663->codec_type == CODEC_TYPE_RT5668) + snd_soc_update_bits(codec, RT5663_DIG_MISC, + RT5668_DIG_GATE_CTRL_MASK, + RT5668_DIG_GATE_CTRL_DIS); + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | + RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK | + RT5668_PWR_MB_MASK, RT5668_PWR_VREF1 | + RT5668_PWR_VREF2 | RT5668_PWR_MB); + usleep_range(10000, 10005); + if (rt5663->codec_type == CODEC_TYPE_RT5668) { + snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, + RT5668_EN_ANA_CLK_DET_MASK | + RT5668_PWR_CLK_DET_MASK, + RT5668_EN_ANA_CLK_DET_DIS | + RT5668_PWR_CLK_DET_DIS); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, + RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | + RT5668_PWR_FV1 | RT5668_PWR_FV2, 0x0); + break; + + default: + break; + } + + return 0; +} + +static int rt5663_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + rt5663->codec = codec; + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + snd_soc_dapm_new_controls(dapm, + rt5668_specific_dapm_widgets, + ARRAY_SIZE(rt5668_specific_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, + rt5668_specific_dapm_routes, + ARRAY_SIZE(rt5668_specific_dapm_routes)); + snd_soc_add_codec_controls(codec, rt5668_specific_controls, + ARRAY_SIZE(rt5668_specific_controls)); + break; + case CODEC_TYPE_RT5663: + snd_soc_dapm_new_controls(dapm, + rt5663_specific_dapm_widgets, + ARRAY_SIZE(rt5663_specific_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, + rt5663_specific_dapm_routes, + ARRAY_SIZE(rt5663_specific_dapm_routes)); + snd_soc_add_codec_controls(codec, rt5663_specific_controls, + ARRAY_SIZE(rt5663_specific_controls)); + break; + } + + return 0; +} + +static int rt5663_remove(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + regmap_write(rt5663->regmap, RT5663_RESET, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int rt5663_suspend(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5663->regmap, true); + regcache_mark_dirty(rt5663->regmap); + + return 0; +} + +static int rt5663_resume(struct snd_soc_codec *codec) +{ + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5663->regmap, false); + regcache_sync(rt5663->regmap); + + return 0; +} +#else +#define rt5663_suspend NULL +#define rt5663_resume NULL +#endif + +#define RT5663_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5663_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static struct snd_soc_dai_ops rt5663_aif_dai_ops = { + .hw_params = rt5663_hw_params, + .set_fmt = rt5663_set_dai_fmt, + .set_sysclk = rt5663_set_dai_sysclk, + .set_pll = rt5663_set_dai_pll, + .set_tdm_slot = rt5663_set_tdm_slot, + .set_bclk_ratio = rt5663_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt5663_dai[] = { + { + .name = "rt5663-aif", + .id = RT5663_AIF, + .playback = { + .stream_name = "AIF Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5663_STEREO_RATES, + .formats = RT5663_FORMATS, + }, + .capture = { + .stream_name = "AIF Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5663_STEREO_RATES, + .formats = RT5663_FORMATS, + }, + .ops = &rt5663_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5663 = { + .probe = rt5663_probe, + .remove = rt5663_remove, + .suspend = rt5663_suspend, + .resume = rt5663_resume, + .set_bias_level = rt5663_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = rt5663_snd_controls, + .num_controls = ARRAY_SIZE(rt5663_snd_controls), + .dapm_widgets = rt5663_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5663_dapm_widgets), + .dapm_routes = rt5663_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5663_dapm_routes), + } +}; + +static const struct regmap_config rt5668_regmap = { + .reg_bits = 16, + .val_bits = 16, + .use_single_rw = true, + .max_register = 0x07fa, + .volatile_reg = rt5668_volatile_register, + .readable_reg = rt5668_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5668_reg, + .num_reg_defaults = ARRAY_SIZE(rt5668_reg), +}; + +static const struct regmap_config rt5663_regmap = { + .reg_bits = 16, + .val_bits = 16, + .use_single_rw = true, + .max_register = 0x03f3, + .volatile_reg = rt5663_volatile_register, + .readable_reg = rt5663_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5663_reg, + .num_reg_defaults = ARRAY_SIZE(rt5663_reg), +}; + +static const struct regmap_config temp_regmap = { + .name = "nocache", + .reg_bits = 16, + .val_bits = 16, + .use_single_rw = true, + .max_register = 0x03f3, + .cache_type = REGCACHE_NONE, +}; + +static const struct i2c_device_id rt5663_i2c_id[] = { + { "rt5668", 0 }, + { "rt5663", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id rt5663_of_match[] = { + { .compatible = "realtek,rt5668", }, + { .compatible = "realtek,rt5663", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5663_of_match); +#endif + +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5663_acpi_match[] = { + { "10EC5668", 0}, + { "10EC5663", 0}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match); +#endif + +static void rt5668_calibrate(struct rt5663_priv *rt5668) +{ + regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0xa402); + regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x0100); + regmap_write(rt5668->regmap, RT5663_RECMIX, 0x4040); + regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x0001); + regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0380); + regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1000); + regmap_write(rt5668->regmap, RT5663_CHOP_DAC_L, 0x3030); + regmap_write(rt5668->regmap, RT5663_CALIB_ADC, 0x3c05); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa23e); + msleep(40); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf23e); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x0321); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0xfc00); + msleep(500); +} + +static void rt5663_calibrate(struct rt5663_priv *rt5668) +{ + int value, count; + + regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0280); + regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x8001); + regmap_write(rt5668->regmap, RT5663_VREF_RECMIX, 0x0032); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa2be); + msleep(20); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf2be); + regmap_write(rt5668->regmap, RT5663_PWR_DIG_2, 0x8400); + regmap_write(rt5668->regmap, RT5663_CHOP_ADC, 0x3000); + regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x8df8); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_2, 0x0003); + regmap_write(rt5668->regmap, RT5663_PWR_ANLG_3, 0x018c); + regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1111); + regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); + regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); + regmap_write(rt5668->regmap, RT5663_DEPOP_2, 0x3003); + regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); + regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); + regmap_write(rt5668->regmap, RT5663_DACREF_LDO, 0x3b0b); + regmap_write(rt5668->regmap, RT5663_STO_DAC_MIXER, 0x2080); + regmap_write(rt5668->regmap, RT5663_BYPASS_STO_DAC, 0x000c); + regmap_write(rt5668->regmap, RT5663_HP_BIAS, 0xabba); + regmap_write(rt5668->regmap, RT5663_CHARGE_PUMP_1, 0x2224); + regmap_write(rt5668->regmap, RT5663_HP_OUT_EN, 0x8088); + regmap_write(rt5668->regmap, RT5663_STO_DRE_9, 0x0017); + regmap_write(rt5668->regmap, RT5663_STO_DRE_10, 0x0017); + regmap_write(rt5668->regmap, RT5663_STO1_ADC_MIXER, 0x4040); + regmap_write(rt5668->regmap, RT5663_RECMIX, 0x0005); + regmap_write(rt5668->regmap, RT5663_ADDA_RST, 0xc000); + regmap_write(rt5668->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x00c9); + regmap_write(rt5668->regmap, RT5663_DUMMY_1, 0x004c); + regmap_write(rt5668->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); + regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0x4702); + msleep(200); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0x0069); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_3, 0x06c2); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0x7b00); + regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0xfb00); + count = 0; + while (true) { + regmap_read(rt5668->regmap, RT5663_HP_CALIB_1_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 200) + return; + count++; + } +} + +static int rt5663_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5663_priv *rt5663; + int ret; + unsigned int val; + struct regmap *regmap; + + rt5663 = devm_kzalloc(&i2c->dev, sizeof(struct rt5663_priv), + GFP_KERNEL); + + if (rt5663 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5663); + + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", + ret); + return ret; + } + regmap_read(regmap, RT5663_VENDOR_ID_2, &val); + switch (val) { + case RT5668_DEVICE_ID: + rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap); + rt5663->codec_type = CODEC_TYPE_RT5668; + break; + case RT5663_DEVICE_ID: + rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_regmap); + rt5663->codec_type = CODEC_TYPE_RT5663; + break; + default: + dev_err(&i2c->dev, + "Device with ID register %#x is not rt5663 or rt5668\n", + val); + return -ENODEV; + } + + if (IS_ERR(rt5663->regmap)) { + ret = PTR_ERR(rt5663->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + /* reset and calibrate */ + regmap_write(rt5663->regmap, RT5663_RESET, 0); + regcache_cache_bypass(rt5663->regmap, true); + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + rt5668_calibrate(rt5663); + break; + case CODEC_TYPE_RT5663: + rt5663_calibrate(rt5663); + break; + default: + dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__); + } + regcache_cache_bypass(rt5663->regmap, false); + regmap_write(rt5663->regmap, RT5663_RESET, 0); + dev_dbg(&i2c->dev, "calibrate done\n"); + + /* GPIO1 as IRQ */ + regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5668_GP1_PIN_MASK, + RT5668_GP1_PIN_IRQ); + /* 4btn inline command debounce */ + regmap_update_bits(rt5663->regmap, RT5663_IL_CMD_5, + RT5668_4BTN_CLK_DEB_MASK, RT5668_4BTN_CLK_DEB_65MS); + + switch (rt5663->codec_type) { + case CODEC_TYPE_RT5668: + regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402); + /* JD1 */ + regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, + RT5668_IRQ_POW_SAV_MASK | RT5668_IRQ_POW_SAV_JD1_MASK, + RT5668_IRQ_POW_SAV_EN | RT5668_IRQ_POW_SAV_JD1_EN); + regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_2, + RT5668_PWR_JD1_MASK, RT5668_PWR_JD1); + regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, + RT5668_EN_CB_JD_MASK, RT5668_EN_CB_JD_EN); + + regmap_update_bits(rt5663->regmap, RT5663_HP_LOGIC_2, + RT5668_HP_SIG_SRC1_MASK, RT5668_HP_SIG_SRC1_REG); + regmap_update_bits(rt5663->regmap, RT5663_RECMIX, + RT5668_VREF_BIAS_MASK | RT5668_CBJ_DET_MASK | + RT5668_DET_TYPE_MASK, RT5668_VREF_BIAS_REG | + RT5668_CBJ_DET_EN | RT5668_DET_TYPE_QFN); + /* Set GPIO4 and GPIO8 as input for combo jack */ + regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, + RT5668_GP4_PIN_CONF_MASK, RT5668_GP4_PIN_CONF_INPUT); + regmap_update_bits(rt5663->regmap, RT5668_GPIO_3, + RT5668_GP8_PIN_CONF_MASK, RT5668_GP8_PIN_CONF_INPUT); + regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1, + RT5668_LDO1_DVO_MASK | RT5668_AMP_HP_MASK, + RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + break; + case CODEC_TYPE_RT5663: + regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be); + msleep(20); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, + RT5663_GP1_PIN_CONF_MASK, RT5663_GP1_PIN_CONF_OUTPUT); + /* DACREF LDO control */ + regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e, + 0x3a0a); + regmap_update_bits(rt5663->regmap, RT5663_RECMIX, + RT5663_RECMIX1_BST1_MASK, RT5663_RECMIX1_BST1_ON); + regmap_update_bits(rt5663->regmap, RT5663_TDM_2, + RT5663_DATA_SWAP_ADCDAT1_MASK, + RT5663_DATA_SWAP_ADCDAT1_LL); + break; + default: + dev_err(&i2c->dev, "%s:Unknown codec type\n", __func__); + } + + INIT_DELAYED_WORK(&rt5663->jack_detect_work, rt5663_jack_detect_work); + + if (i2c->irq) { + ret = request_irq(i2c->irq, rt5663_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5663", rt5663); + if (ret) + dev_err(&i2c->dev, "%s Failed to reguest IRQ: %d\n", + __func__, ret); + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5663, + rt5663_dai, ARRAY_SIZE(rt5663_dai)); + + if (ret) { + if (i2c->irq) + free_irq(i2c->irq, rt5663); + } + + return ret; +} + +static int rt5663_i2c_remove(struct i2c_client *i2c) +{ + struct rt5663_priv *rt5663 = i2c_get_clientdata(i2c); + + if (i2c->irq) + free_irq(i2c->irq, rt5663); + + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static void rt5663_i2c_shutdown(struct i2c_client *client) +{ + struct rt5663_priv *rt5663 = i2c_get_clientdata(client); + + regmap_write(rt5663->regmap, RT5663_RESET, 0); +} + +static struct i2c_driver rt5663_i2c_driver = { + .driver = { + .name = "rt5663", + .acpi_match_table = ACPI_PTR(rt5663_acpi_match), + .of_match_table = of_match_ptr(rt5663_of_match), + }, + .probe = rt5663_i2c_probe, + .remove = rt5663_i2c_remove, + .shutdown = rt5663_i2c_shutdown, + .id_table = rt5663_i2c_id, +}; +module_i2c_driver(rt5663_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5663 driver"); +MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h new file mode 100644 index 000000000000..2cc8f28080f6 --- /dev/null +++ b/sound/soc/codecs/rt5663.h @@ -0,0 +1,1121 @@ +/* + * rt5663.h -- RT5663 ALSA SoC audio driver + * + * Copyright 2016 Realtek Microelectronics + * Author: Jack Yu <jack.yu@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5663_H__ +#define __RT5663_H__ + +/* Info */ +#define RT5663_RESET 0x0000 +#define RT5663_VENDOR_ID 0x00fd +#define RT5663_VENDOR_ID_1 0x00fe +#define RT5663_VENDOR_ID_2 0x00ff + +#define RT5668_LOUT_CTRL 0x0001 +#define RT5668_HP_AMP_2 0x0003 +#define RT5668_MONO_OUT 0x0004 +#define RT5668_MONO_GAIN 0x0007 + +#define RT5668_AEC_BST 0x000b +#define RT5668_IN1_IN2 0x000c +#define RT5668_IN3_IN4 0x000d +#define RT5668_INL1_INR1 0x000f +#define RT5668_CBJ_TYPE_2 0x0011 +#define RT5668_CBJ_TYPE_3 0x0012 +#define RT5668_CBJ_TYPE_4 0x0013 +#define RT5668_CBJ_TYPE_5 0x0014 +#define RT5668_CBJ_TYPE_8 0x0017 + +/* I/O - ADC/DAC/DMIC */ +#define RT5668_DAC3_DIG_VOL 0x001a +#define RT5668_DAC3_CTRL 0x001b +#define RT5668_MONO_ADC_DIG_VOL 0x001d +#define RT5668_STO2_ADC_DIG_VOL 0x001e +#define RT5668_MONO_ADC_BST_GAIN 0x0020 +#define RT5668_STO2_ADC_BST_GAIN 0x0021 +#define RT5668_SIDETONE_CTRL 0x0024 +/* Mixer - D-D */ +#define RT5668_MONO1_ADC_MIXER 0x0027 +#define RT5668_STO2_ADC_MIXER 0x0028 +#define RT5668_MONO_DAC_MIXER 0x002b +#define RT5668_DAC2_SRC_CTRL 0x002e +#define RT5668_IF_3_4_DATA_CTL 0x002f +#define RT5668_IF_5_DATA_CTL 0x0030 +#define RT5668_PDM_OUT_CTL 0x0031 +#define RT5668_PDM_I2C_DATA_CTL1 0x0032 +#define RT5668_PDM_I2C_DATA_CTL2 0x0033 +#define RT5668_PDM_I2C_DATA_CTL3 0x0034 +#define RT5668_PDM_I2C_DATA_CTL4 0x0035 + +/*Mixer - Analog*/ +#define RT5668_RECMIX1_NEW 0x003a +#define RT5668_RECMIX1L_0 0x003b +#define RT5668_RECMIX1L 0x003c +#define RT5668_RECMIX1R_0 0x003d +#define RT5668_RECMIX1R 0x003e +#define RT5668_RECMIX2_NEW 0x003f +#define RT5668_RECMIX2_L_2 0x0041 +#define RT5668_RECMIX2_R 0x0042 +#define RT5668_RECMIX2_R_2 0x0043 +#define RT5668_CALIB_REC_LR 0x0044 +#define RT5668_ALC_BK_GAIN 0x0049 +#define RT5668_MONOMIX_GAIN 0x004a +#define RT5668_MONOMIX_IN_GAIN 0x004b +#define RT5668_OUT_MIXL_GAIN 0x004d +#define RT5668_OUT_LMIX_IN_GAIN 0x004e +#define RT5668_OUT_RMIX_IN_GAIN 0x004f +#define RT5668_OUT_RMIX_IN_GAIN1 0x0050 +#define RT5668_LOUT_MIXER_CTRL 0x0052 +/* Power */ +#define RT5668_PWR_VOL 0x0067 + +#define RT5668_ADCDAC_RST 0x006d +/* Format - ADC/DAC */ +#define RT5668_I2S34_SDP 0x0071 +#define RT5668_I2S5_SDP 0x0072 +/* Format - TDM Control */ +#define RT5668_TDM_5 0x007c +#define RT5668_TDM_6 0x007d +#define RT5668_TDM_7 0x007e +#define RT5668_TDM_8 0x007f + +/* Function - Analog */ +#define RT5668_ASRC_3 0x0085 +#define RT5668_ASRC_6 0x0088 +#define RT5668_ASRC_7 0x0089 +#define RT5668_PLL_TRK_13 0x0099 +#define RT5668_I2S_M_CLK_CTL 0x00a0 +#define RT5668_FDIV_I2S34_M_CLK 0x00a1 +#define RT5668_FDIV_I2S34_M_CLK2 0x00a2 +#define RT5668_FDIV_I2S5_M_CLK 0x00a3 +#define RT5668_FDIV_I2S5_M_CLK2 0x00a4 + +/* Function - Digital */ +#define RT5668_IRQ_4 0x00b9 +#define RT5668_GPIO_3 0x00c2 +#define RT5668_GPIO_4 0x00c3 +#define RT5668_GPIO_STA 0x00c4 +#define RT5668_HP_AMP_DET1 0x00d0 +#define RT5668_HP_AMP_DET2 0x00d1 +#define RT5668_HP_AMP_DET3 0x00d2 +#define RT5668_MID_BD_HP_AMP 0x00d3 +#define RT5668_LOW_BD_HP_AMP 0x00d4 +#define RT5668_SOF_VOL_ZC2 0x00da +#define RT5668_ADC_STO2_ADJ1 0x00ee +#define RT5668_ADC_STO2_ADJ2 0x00ef +/* General Control */ +#define RT5668_A_JD_CTRL 0x00f0 +#define RT5668_JD1_TRES_CTRL 0x00f1 +#define RT5668_JD2_TRES_CTRL 0x00f2 +#define RT5668_JD_CTRL2 0x00f7 +#define RT5668_DUM_REG_2 0x00fb +#define RT5668_DUM_REG_3 0x00fc + + +#define RT5668_DACADC_DIG_VOL2 0x0101 +#define RT5668_DIG_IN_PIN2 0x0133 +#define RT5668_PAD_DRV_CTL1 0x0136 +#define RT5668_SOF_RAM_DEPOP 0x0138 +#define RT5668_VOL_TEST 0x013f +#define RT5668_TEST_MODE_3 0x0147 +#define RT5668_TEST_MODE_4 0x0148 +#define RT5668_MONO_DYNA_1 0x0170 +#define RT5668_MONO_DYNA_2 0x0171 +#define RT5668_MONO_DYNA_3 0x0172 +#define RT5668_MONO_DYNA_4 0x0173 +#define RT5668_MONO_DYNA_5 0x0174 +#define RT5668_MONO_DYNA_6 0x0175 +#define RT5668_STO1_SIL_DET 0x0190 +#define RT5668_MONOL_SIL_DET 0x0191 +#define RT5668_MONOR_SIL_DET 0x0192 +#define RT5668_STO2_DAC_SIL 0x0193 +#define RT5668_PWR_SAV_CTL1 0x0194 +#define RT5668_PWR_SAV_CTL2 0x0195 +#define RT5668_PWR_SAV_CTL3 0x0196 +#define RT5668_PWR_SAV_CTL4 0x0197 +#define RT5668_PWR_SAV_CTL5 0x0198 +#define RT5668_PWR_SAV_CTL6 0x0199 +#define RT5668_MONO_AMP_CAL1 0x01a0 +#define RT5668_MONO_AMP_CAL2 0x01a1 +#define RT5668_MONO_AMP_CAL3 0x01a2 +#define RT5668_MONO_AMP_CAL4 0x01a3 +#define RT5668_MONO_AMP_CAL5 0x01a4 +#define RT5668_MONO_AMP_CAL6 0x01a5 +#define RT5668_MONO_AMP_CAL7 0x01a6 +#define RT5668_MONO_AMP_CAL_ST1 0x01a7 +#define RT5668_MONO_AMP_CAL_ST2 0x01a8 +#define RT5668_MONO_AMP_CAL_ST3 0x01a9 +#define RT5668_MONO_AMP_CAL_ST4 0x01aa +#define RT5668_MONO_AMP_CAL_ST5 0x01ab +#define RT5668_HP_IMP_SEN_13 0x01b9 +#define RT5668_HP_IMP_SEN_14 0x01ba +#define RT5668_HP_IMP_SEN_6 0x01bb +#define RT5668_HP_IMP_SEN_7 0x01bc +#define RT5668_HP_IMP_SEN_8 0x01bd +#define RT5668_HP_IMP_SEN_9 0x01be +#define RT5668_HP_IMP_SEN_10 0x01bf +#define RT5668_HP_LOGIC_3 0x01dc +#define RT5668_HP_CALIB_ST10 0x01f3 +#define RT5668_HP_CALIB_ST11 0x01f4 +#define RT5668_PRO_REG_TBL_4 0x0203 +#define RT5668_PRO_REG_TBL_5 0x0204 +#define RT5668_PRO_REG_TBL_6 0x0205 +#define RT5668_PRO_REG_TBL_7 0x0206 +#define RT5668_PRO_REG_TBL_8 0x0207 +#define RT5668_PRO_REG_TBL_9 0x0208 +#define RT5668_SAR_ADC_INL_1 0x0210 +#define RT5668_SAR_ADC_INL_2 0x0211 +#define RT5668_SAR_ADC_INL_3 0x0212 +#define RT5668_SAR_ADC_INL_4 0x0213 +#define RT5668_SAR_ADC_INL_5 0x0214 +#define RT5668_SAR_ADC_INL_6 0x0215 +#define RT5668_SAR_ADC_INL_7 0x0216 +#define RT5668_SAR_ADC_INL_8 0x0217 +#define RT5668_SAR_ADC_INL_9 0x0218 +#define RT5668_SAR_ADC_INL_10 0x0219 +#define RT5668_SAR_ADC_INL_11 0x021a +#define RT5668_SAR_ADC_INL_12 0x021b +#define RT5668_DRC_CTRL_1 0x02ff +#define RT5668_DRC1_CTRL_2 0x0301 +#define RT5668_DRC1_CTRL_3 0x0302 +#define RT5668_DRC1_CTRL_4 0x0303 +#define RT5668_DRC1_CTRL_5 0x0304 +#define RT5668_DRC1_CTRL_6 0x0305 +#define RT5668_DRC1_HD_CTRL_1 0x0306 +#define RT5668_DRC1_HD_CTRL_2 0x0307 +#define RT5668_DRC1_PRI_REG_1 0x0310 +#define RT5668_DRC1_PRI_REG_2 0x0311 +#define RT5668_DRC1_PRI_REG_3 0x0312 +#define RT5668_DRC1_PRI_REG_4 0x0313 +#define RT5668_DRC1_PRI_REG_5 0x0314 +#define RT5668_DRC1_PRI_REG_6 0x0315 +#define RT5668_DRC1_PRI_REG_7 0x0316 +#define RT5668_DRC1_PRI_REG_8 0x0317 +#define RT5668_ALC_PGA_CTL_1 0x0330 +#define RT5668_ALC_PGA_CTL_2 0x0331 +#define RT5668_ALC_PGA_CTL_3 0x0332 +#define RT5668_ALC_PGA_CTL_4 0x0333 +#define RT5668_ALC_PGA_CTL_5 0x0334 +#define RT5668_ALC_PGA_CTL_6 0x0335 +#define RT5668_ALC_PGA_CTL_7 0x0336 +#define RT5668_ALC_PGA_CTL_8 0x0337 +#define RT5668_ALC_PGA_REG_1 0x0338 +#define RT5668_ALC_PGA_REG_2 0x0339 +#define RT5668_ALC_PGA_REG_3 0x033a +#define RT5668_ADC_EQ_RECOV_1 0x03c0 +#define RT5668_ADC_EQ_RECOV_2 0x03c1 +#define RT5668_ADC_EQ_RECOV_3 0x03c2 +#define RT5668_ADC_EQ_RECOV_4 0x03c3 +#define RT5668_ADC_EQ_RECOV_5 0x03c4 +#define RT5668_ADC_EQ_RECOV_6 0x03c5 +#define RT5668_ADC_EQ_RECOV_7 0x03c6 +#define RT5668_ADC_EQ_RECOV_8 0x03c7 +#define RT5668_ADC_EQ_RECOV_9 0x03c8 +#define RT5668_ADC_EQ_RECOV_10 0x03c9 +#define RT5668_ADC_EQ_RECOV_11 0x03ca +#define RT5668_ADC_EQ_RECOV_12 0x03cb +#define RT5668_ADC_EQ_RECOV_13 0x03cc +#define RT5668_VID_HIDDEN 0x03fe +#define RT5668_VID_CUSTOMER 0x03ff +#define RT5668_SCAN_MODE 0x07f0 +#define RT5668_I2C_BYPA 0x07fa + +/* Headphone Amp Control 2 (0x0003) */ +#define RT5668_EN_DAC_HPO_MASK (0x1 << 14) +#define RT5668_EN_DAC_HPO_SHIFT 14 +#define RT5668_EN_DAC_HPO_DIS (0x0 << 14) +#define RT5668_EN_DAC_HPO_EN (0x1 << 14) + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5668_GAIN_HP (0x1f << 8) +#define RT5668_GAIN_HP_SHIFT 8 + +/* AEC BST Control (0x000b) */ +#define RT5668_GAIN_CBJ_MASK (0xf << 8) +#define RT5668_GAIN_CBJ_SHIFT 8 + +/* IN1 Control / MIC GND REF (0x000c) */ +#define RT5668_IN1_DF_MASK (0x1 << 15) +#define RT5668_IN1_DF_SHIFT 15 + +/* Combo Jack and Type Detection Control 1 (0x0010) */ +#define RT5668_CBJ_DET_MASK (0x1 << 15) +#define RT5668_CBJ_DET_SHIFT 15 +#define RT5668_CBJ_DET_DIS (0x0 << 15) +#define RT5668_CBJ_DET_EN (0x1 << 15) +#define RT5668_DET_TYPE_MASK (0x1 << 12) +#define RT5668_DET_TYPE_SHIFT 12 +#define RT5668_DET_TYPE_WLCSP (0x0 << 12) +#define RT5668_DET_TYPE_QFN (0x1 << 12) +#define RT5668_VREF_BIAS_MASK (0x1 << 6) +#define RT5668_VREF_BIAS_SHIFT 6 +#define RT5668_VREF_BIAS_FSM (0x0 << 6) +#define RT5668_VREF_BIAS_REG (0x1 << 6) + +/* REC Left Mixer Control 2 (0x003c) */ +#define RT5668_RECMIX1L_BST1_CBJ (0x1 << 7) +#define RT5668_RECMIX1L_BST1_CBJ_SHIFT 7 +#define RT5668_RECMIX1L_BST2 (0x1 << 4) +#define RT5668_RECMIX1L_BST2_SHIFT 4 + +/* REC Right Mixer Control 2 (0x003e) */ +#define RT5668_RECMIX1R_BST2 (0x1 << 4) +#define RT5668_RECMIX1R_BST2_SHIFT 4 + +/* DAC1 Digital Volume (0x0019) */ +#define RT5668_DAC_L1_VOL_MASK (0xff << 8) +#define RT5668_DAC_L1_VOL_SHIFT 8 +#define RT5668_DAC_R1_VOL_MASK (0xff) +#define RT5668_DAC_R1_VOL_SHIFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5668_ADC_L_MUTE_MASK (0x1 << 15) +#define RT5668_ADC_L_MUTE_SHIFT 15 +#define RT5668_ADC_L_VOL_MASK (0x7f << 8) +#define RT5668_ADC_L_VOL_SHIFT 8 +#define RT5668_ADC_R_MUTE_MASK (0x1 << 7) +#define RT5668_ADC_R_MUTE_SHIFT 7 +#define RT5668_ADC_R_VOL_MASK (0x7f) +#define RT5668_ADC_R_VOL_SHIFT 0 + +/* Stereo ADC Mixer Control (0x0026) */ +#define RT5668_M_STO1_ADC_L1 (0x1 << 15) +#define RT5668_M_STO1_ADC_L1_SHIFT 15 +#define RT5668_M_STO1_ADC_L2 (0x1 << 14) +#define RT5668_M_STO1_ADC_L2_SHIFT 14 +#define RT5668_STO1_ADC_L1_SRC (0x1 << 13) +#define RT5668_STO1_ADC_L1_SRC_SHIFT 13 +#define RT5668_STO1_ADC_L2_SRC (0x1 << 12) +#define RT5668_STO1_ADC_L2_SRC_SHIFT 12 +#define RT5668_STO1_ADC_L_SRC (0x3 << 10) +#define RT5668_STO1_ADC_L_SRC_SHIFT 10 +#define RT5668_M_STO1_ADC_R1 (0x1 << 7) +#define RT5668_M_STO1_ADC_R1_SHIFT 7 +#define RT5668_M_STO1_ADC_R2 (0x1 << 6) +#define RT5668_M_STO1_ADC_R2_SHIFT 6 +#define RT5668_STO1_ADC_R1_SRC (0x1 << 5) +#define RT5668_STO1_ADC_R1_SRC_SHIFT 5 +#define RT5668_STO1_ADC_R2_SRC (0x1 << 4) +#define RT5668_STO1_ADC_R2_SRC_SHIFT 4 +#define RT5668_STO1_ADC_R_SRC (0x3 << 2) +#define RT5668_STO1_ADC_R_SRC_SHIFT 2 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5668_M_ADCMIX_L (0x1 << 15) +#define RT5668_M_ADCMIX_L_SHIFT 15 +#define RT5668_M_DAC1_L (0x1 << 14) +#define RT5668_M_DAC1_L_SHIFT 14 +#define RT5668_M_ADCMIX_R (0x1 << 7) +#define RT5668_M_ADCMIX_R_SHIFT 7 +#define RT5668_M_DAC1_R (0x1 << 6) +#define RT5668_M_DAC1_R_SHIFT 6 + +/* Stereo DAC Mixer Control (0x002a) */ +#define RT5668_M_DAC_L1_STO_L (0x1 << 15) +#define RT5668_M_DAC_L1_STO_L_SHIFT 15 +#define RT5668_M_DAC_R1_STO_L (0x1 << 13) +#define RT5668_M_DAC_R1_STO_L_SHIFT 13 +#define RT5668_M_DAC_L1_STO_R (0x1 << 7) +#define RT5668_M_DAC_L1_STO_R_SHIFT 7 +#define RT5668_M_DAC_R1_STO_R (0x1 << 5) +#define RT5668_M_DAC_R1_STO_R_SHIFT 5 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5668_PWR_I2S1 (0x1 << 15) +#define RT5668_PWR_I2S1_SHIFT 15 +#define RT5668_PWR_DAC_L1 (0x1 << 11) +#define RT5668_PWR_DAC_L1_SHIFT 11 +#define RT5668_PWR_DAC_R1 (0x1 << 10) +#define RT5668_PWR_DAC_R1_SHIFT 10 +#define RT5668_PWR_LDO_DACREF_MASK (0x1 << 8) +#define RT5668_PWR_LDO_DACREF_SHIFT 8 +#define RT5668_PWR_LDO_DACREF_ON (0x1 << 8) +#define RT5668_PWR_LDO_DACREF_DOWN (0x0 << 8) +#define RT5668_PWR_LDO_SHIFT 8 +#define RT5668_PWR_ADC_L1 (0x1 << 4) +#define RT5668_PWR_ADC_L1_SHIFT 4 +#define RT5668_PWR_ADC_R1 (0x1 << 3) +#define RT5668_PWR_ADC_R1_SHIFT 3 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5668_PWR_ADC_S1F (0x1 << 15) +#define RT5668_PWR_ADC_S1F_SHIFT 15 +#define RT5668_PWR_DAC_S1F (0x1 << 10) +#define RT5668_PWR_DAC_S1F_SHIFT 10 + +/* Power Management for Analog 1 (0x0063) */ +#define RT5668_PWR_VREF1 (0x1 << 15) +#define RT5668_PWR_VREF1_MASK (0x1 << 15) +#define RT5668_PWR_VREF1_SHIFT 15 +#define RT5668_PWR_FV1 (0x1 << 14) +#define RT5668_PWR_FV1_MASK (0x1 << 14) +#define RT5668_PWR_FV1_SHIFT 14 +#define RT5668_PWR_VREF2 (0x1 << 13) +#define RT5668_PWR_VREF2_MASK (0x1 << 13) +#define RT5668_PWR_VREF2_SHIFT 13 +#define RT5668_PWR_FV2 (0x1 << 12) +#define RT5668_PWR_FV2_MASK (0x1 << 12) +#define RT5668_PWR_FV2_SHIFT 12 +#define RT5668_PWR_MB (0x1 << 9) +#define RT5668_PWR_MB_MASK (0x1 << 9) +#define RT5668_PWR_MB_SHIFT 9 +#define RT5668_AMP_HP_MASK (0x3 << 2) +#define RT5668_AMP_HP_SHIFT 2 +#define RT5668_AMP_HP_1X (0x0 << 2) +#define RT5668_AMP_HP_3X (0x1 << 2) +#define RT5668_AMP_HP_5X (0x3 << 2) +#define RT5668_LDO1_DVO_MASK (0x3) +#define RT5668_LDO1_DVO_SHIFT 0 +#define RT5668_LDO1_DVO_0_9V (0x0) +#define RT5668_LDO1_DVO_1_0V (0x1) +#define RT5668_LDO1_DVO_1_2V (0x2) +#define RT5668_LDO1_DVO_1_4V (0x3) + +/* Power Management for Analog 2 (0x0064) */ +#define RT5668_PWR_BST1 (0x1 << 15) +#define RT5668_PWR_BST1_MASK (0x1 << 15) +#define RT5668_PWR_BST1_SHIFT 15 +#define RT5668_PWR_BST1_OFF (0x0 << 15) +#define RT5668_PWR_BST1_ON (0x1 << 15) +#define RT5668_PWR_BST2 (0x1 << 14) +#define RT5668_PWR_BST2_MASK (0x1 << 14) +#define RT5668_PWR_BST2_SHIFT 14 +#define RT5668_PWR_MB1 (0x1 << 11) +#define RT5668_PWR_MB1_SHIFT 11 +#define RT5668_PWR_MB2 (0x1 << 10) +#define RT5668_PWR_MB2_SHIFT 10 +#define RT5668_PWR_BST2_OP (0x1 << 6) +#define RT5668_PWR_BST2_OP_MASK (0x1 << 6) +#define RT5668_PWR_BST2_OP_SHIFT 6 +#define RT5668_PWR_JD1 (0x1 << 3) +#define RT5668_PWR_JD1_MASK (0x1 << 3) +#define RT5668_PWR_JD1_SHIFT 3 +#define RT5668_PWR_JD2 (0x1 << 2) +#define RT5668_PWR_JD2_MASK (0x1 << 2) +#define RT5668_PWR_JD2_SHIFT 2 +#define RT5668_PWR_RECMIX1 (0x1 << 1) +#define RT5668_PWR_RECMIX1_SHIFT 1 +#define RT5668_PWR_RECMIX2 (0x1) +#define RT5668_PWR_RECMIX2_SHIFT 0 + +/* Power Management for Analog 3 (0x0065) */ +#define RT5668_PWR_CBJ_MASK (0x1 << 9) +#define RT5668_PWR_CBJ_SHIFT 9 +#define RT5668_PWR_CBJ_OFF (0x0 << 9) +#define RT5668_PWR_CBJ_ON (0x1 << 9) +#define RT5668_PWR_PLL (0x1 << 6) +#define RT5668_PWR_PLL_SHIFT 6 +#define RT5668_PWR_LDO2 (0x1 << 2) +#define RT5668_PWR_LDO2_SHIFT 2 + +/* Power Management for Volume (0x0067) */ +#define RT5668_PWR_MIC_DET (0x1 << 5) +#define RT5668_PWR_MIC_DET_SHIFT 5 + +/* MCLK and System Clock Detection Control (0x006b) */ +#define RT5668_EN_ANA_CLK_DET_MASK (0x1 << 15) +#define RT5668_EN_ANA_CLK_DET_SHIFT 15 +#define RT5668_EN_ANA_CLK_DET_DIS (0x0 << 15) +#define RT5668_EN_ANA_CLK_DET_AUTO (0x1 << 15) +#define RT5668_PWR_CLK_DET_MASK (0x1) +#define RT5668_PWR_CLK_DET_SHIFT 0 +#define RT5668_PWR_CLK_DET_DIS (0x0) +#define RT5668_PWR_CLK_DET_EN (0x1) + +/* I2S1 Audio Serial Data Port Control (0x0070) */ +#define RT5668_I2S_MS_MASK (0x1 << 15) +#define RT5668_I2S_MS_SHIFT 15 +#define RT5668_I2S_MS_M (0x0 << 15) +#define RT5668_I2S_MS_S (0x1 << 15) +#define RT5668_I2S_BP_MASK (0x1 << 8) +#define RT5668_I2S_BP_SHIFT 8 +#define RT5668_I2S_BP_NOR (0x0 << 8) +#define RT5668_I2S_BP_INV (0x1 << 8) +#define RT5668_I2S_DL_MASK (0x3 << 4) +#define RT5668_I2S_DL_SHIFT 4 +#define RT5668_I2S_DL_16 (0x0 << 4) +#define RT5668_I2S_DL_20 (0x1 << 4) +#define RT5668_I2S_DL_24 (0x2 << 4) +#define RT5668_I2S_DL_8 (0x3 << 4) +#define RT5668_I2S_DF_MASK (0x7) +#define RT5668_I2S_DF_SHIFT 0 +#define RT5668_I2S_DF_I2S (0x0) +#define RT5668_I2S_DF_LEFT (0x1) +#define RT5668_I2S_DF_PCM_A (0x2) +#define RT5668_I2S_DF_PCM_B (0x3) +#define RT5668_I2S_DF_PCM_A_N (0x6) +#define RT5668_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5668_I2S_PD1_MASK (0x7 << 12) +#define RT5668_I2S_PD1_SHIFT 12 +#define RT5668_M_I2S_DIV_MASK (0x7 << 8) +#define RT5668_M_I2S_DIV_SHIFT 8 +#define RT5668_CLK_SRC_MASK (0x3 << 4) +#define RT5668_CLK_SRC_MCLK (0x0 << 4) +#define RT5668_CLK_SRC_PLL_OUT (0x1 << 4) +#define RT5668_CLK_SRC_DIV (0x2 << 4) +#define RT5668_CLK_SRC_RC (0x3 << 4) +#define RT5668_DAC_OSR_MASK (0x3 << 2) +#define RT5668_DAC_OSR_SHIFT 2 +#define RT5668_DAC_OSR_128 (0x0 << 2) +#define RT5668_DAC_OSR_64 (0x1 << 2) +#define RT5668_DAC_OSR_32 (0x2 << 2) +#define RT5668_ADC_OSR_MASK (0x3) +#define RT5668_ADC_OSR_SHIFT 0 +#define RT5668_ADC_OSR_128 (0x0) +#define RT5668_ADC_OSR_64 (0x1) +#define RT5668_ADC_OSR_32 (0x2) + +/* TDM1 control 1 (0x0078) */ +#define RT5668_TDM_MODE_MASK (0x1 << 15) +#define RT5668_TDM_MODE_SHIFT 15 +#define RT5668_TDM_MODE_I2S (0x0 << 15) +#define RT5668_TDM_MODE_TDM (0x1 << 15) +#define RT5668_TDM_IN_CH_MASK (0x3 << 10) +#define RT5668_TDM_IN_CH_SHIFT 10 +#define RT5668_TDM_IN_CH_2 (0x0 << 10) +#define RT5668_TDM_IN_CH_4 (0x1 << 10) +#define RT5668_TDM_IN_CH_6 (0x2 << 10) +#define RT5668_TDM_IN_CH_8 (0x3 << 10) +#define RT5668_TDM_OUT_CH_MASK (0x3 << 8) +#define RT5668_TDM_OUT_CH_SHIFT 8 +#define RT5668_TDM_OUT_CH_2 (0x0 << 8) +#define RT5668_TDM_OUT_CH_4 (0x1 << 8) +#define RT5668_TDM_OUT_CH_6 (0x2 << 8) +#define RT5668_TDM_OUT_CH_8 (0x3 << 8) +#define RT5668_TDM_IN_LEN_MASK (0x3 << 6) +#define RT5668_TDM_IN_LEN_SHIFT 6 +#define RT5668_TDM_IN_LEN_16 (0x0 << 6) +#define RT5668_TDM_IN_LEN_20 (0x1 << 6) +#define RT5668_TDM_IN_LEN_24 (0x2 << 6) +#define RT5668_TDM_IN_LEN_32 (0x3 << 6) +#define RT5668_TDM_OUT_LEN_MASK (0x3 << 4) +#define RT5668_TDM_OUT_LEN_SHIFT 4 +#define RT5668_TDM_OUT_LEN_16 (0x0 << 4) +#define RT5668_TDM_OUT_LEN_20 (0x1 << 4) +#define RT5668_TDM_OUT_LEN_24 (0x2 << 4) +#define RT5668_TDM_OUT_LEN_32 (0x3 << 4) + +/* Global Clock Control (0x0080) */ +#define RT5668_SCLK_SRC_MASK (0x3 << 14) +#define RT5668_SCLK_SRC_SHIFT 14 +#define RT5668_SCLK_SRC_MCLK (0x0 << 14) +#define RT5668_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5668_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5668_PLL1_SRC_MASK (0x7 << 8) +#define RT5668_PLL1_SRC_SHIFT 8 +#define RT5668_PLL1_SRC_MCLK (0x0 << 8) +#define RT5668_PLL1_SRC_BCLK1 (0x1 << 8) +#define RT5668_PLL1_PD_MASK (0x1 << 4) +#define RT5668_PLL1_PD_SHIFT 4 + +#define RT5668_PLL_INP_MAX 40000000 +#define RT5668_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x0081) */ +#define RT5668_PLL_N_MAX 0x001ff +#define RT5668_PLL_N_MASK (RT5668_PLL_N_MAX << 7) +#define RT5668_PLL_N_SHIFT 7 +#define RT5668_PLL_K_MAX 0x001f +#define RT5668_PLL_K_MASK (RT5668_PLL_K_MAX) +#define RT5668_PLL_K_SHIFT 0 + +/* PLL M/N/K Code Control 2 (0x0082) */ +#define RT5668_PLL_M_MAX 0x00f +#define RT5668_PLL_M_MASK (RT5668_PLL_M_MAX << 12) +#define RT5668_PLL_M_SHIFT 12 +#define RT5668_PLL_M_BP (0x1 << 11) +#define RT5668_PLL_M_BP_SHIFT 11 + +/* PLL tracking mode 1 (0x0083) */ +#define RT5668_I2S1_ASRC_MASK (0x1 << 13) +#define RT5668_I2S1_ASRC_SHIFT 13 +#define RT5668_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5668_DAC_STO1_ASRC_SHIFT 12 +#define RT5668_ADC_STO1_ASRC_MASK (0x1 << 4) +#define RT5668_ADC_STO1_ASRC_SHIFT 4 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5668_DA_STO1_TRACK_MASK (0x7 << 12) +#define RT5668_DA_STO1_TRACK_SHIFT 12 +#define RT5668_DA_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5668_DA_STO1_TRACK_I2S1 (0x1 << 12) + +/* PLL tracking mode 3 (0x0085)*/ +#define RT5668_AD_STO1_TRACK_MASK (0x7 << 12) +#define RT5668_AD_STO1_TRACK_SHIFT 12 +#define RT5668_AD_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5668_AD_STO1_TRACK_I2S1 (0x1 << 12) + +/* HPOUT Charge pump control 1 (0x0091) */ +#define RT5668_OSW_HP_L_MASK (0x1 << 11) +#define RT5668_OSW_HP_L_SHIFT 11 +#define RT5668_OSW_HP_L_EN (0x1 << 11) +#define RT5668_OSW_HP_L_DIS (0x0 << 11) +#define RT5668_OSW_HP_R_MASK (0x1 << 10) +#define RT5668_OSW_HP_R_SHIFT 10 +#define RT5668_OSW_HP_R_EN (0x1 << 10) +#define RT5668_OSW_HP_R_DIS (0x0 << 10) +#define RT5668_SEL_PM_HP_MASK (0x3 << 8) +#define RT5668_SEL_PM_HP_SHIFT 8 +#define RT5668_SEL_PM_HP_0_6 (0x0 << 8) +#define RT5668_SEL_PM_HP_0_9 (0x1 << 8) +#define RT5668_SEL_PM_HP_1_8 (0x2 << 8) +#define RT5668_SEL_PM_HP_HIGH (0x3 << 8) +#define RT5668_OVCD_HP_MASK (0x1 << 2) +#define RT5668_OVCD_HP_SHIFT 2 +#define RT5668_OVCD_HP_EN (0x1 << 2) +#define RT5668_OVCD_HP_DIS (0x0 << 2) + +/* RC Clock Control (0x0094) */ +#define RT5668_DIG_25M_CLK_MASK (0x1 << 9) +#define RT5668_DIG_25M_CLK_SHIFT 9 +#define RT5668_DIG_25M_CLK_DIS (0x0 << 9) +#define RT5668_DIG_25M_CLK_EN (0x1 << 9) +#define RT5668_DIG_1M_CLK_MASK (0x1 << 8) +#define RT5668_DIG_1M_CLK_SHIFT 8 +#define RT5668_DIG_1M_CLK_DIS (0x0 << 8) +#define RT5668_DIG_1M_CLK_EN (0x1 << 8) + +/* Auto Turn On 1M RC CLK (0x009f) */ +#define RT5668_IRQ_POW_SAV_MASK (0x1 << 15) +#define RT5668_IRQ_POW_SAV_SHIFT 15 +#define RT5668_IRQ_POW_SAV_DIS (0x0 << 15) +#define RT5668_IRQ_POW_SAV_EN (0x1 << 15) +#define RT5668_IRQ_POW_SAV_JD1_MASK (0x1 << 14) +#define RT5668_IRQ_POW_SAV_JD1_SHIFT 14 +#define RT5668_IRQ_POW_SAV_JD1_DIS (0x0 << 14) +#define RT5668_IRQ_POW_SAV_JD1_EN (0x1 << 14) + +/* IRQ Control 1 (0x00b6) */ +#define RT5668_EN_CB_JD_MASK (0x1 << 3) +#define RT5668_EN_CB_JD_SHIFT 3 +#define RT5668_EN_CB_JD_EN (0x1 << 3) +#define RT5668_EN_CB_JD_DIS (0x0 << 3) + +/* IRQ Control 3 (0x00b8) */ +#define RT5668_EN_IRQ_INLINE_MASK (0x1 << 6) +#define RT5668_EN_IRQ_INLINE_SHIFT 6 +#define RT5668_EN_IRQ_INLINE_BYP (0x0 << 6) +#define RT5668_EN_IRQ_INLINE_NOR (0x1 << 6) + +/* GPIO Control 1 (0x00c0) */ +#define RT5668_GP1_PIN_MASK (0x1 << 15) +#define RT5668_GP1_PIN_SHIFT 15 +#define RT5668_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5668_GP1_PIN_IRQ (0x1 << 15) + +/* GPIO Control 2 (0x00c1) */ +#define RT5668_GP4_PIN_CONF_MASK (0x1 << 5) +#define RT5668_GP4_PIN_CONF_SHIFT 5 +#define RT5668_GP4_PIN_CONF_INPUT (0x0 << 5) +#define RT5668_GP4_PIN_CONF_OUTPUT (0x1 << 5) + +/* GPIO Control 2 (0x00c2) */ +#define RT5668_GP8_PIN_CONF_MASK (0x1 << 13) +#define RT5668_GP8_PIN_CONF_SHIFT 13 +#define RT5668_GP8_PIN_CONF_INPUT (0x0 << 13) +#define RT5668_GP8_PIN_CONF_OUTPUT (0x1 << 13) + +/* 4 Buttons Inline Command Function 1 (0x00df) */ +#define RT5668_4BTN_CLK_DEB_MASK (0x3 << 2) +#define RT5668_4BTN_CLK_DEB_SHIFT 2 +#define RT5668_4BTN_CLK_DEB_8MS (0x0 << 2) +#define RT5668_4BTN_CLK_DEB_16MS (0x1 << 2) +#define RT5668_4BTN_CLK_DEB_32MS (0x2 << 2) +#define RT5668_4BTN_CLK_DEB_65MS (0x3 << 2) + +/* Inline Command Function 6 (0x00e0) */ +#define RT5668_EN_4BTN_INL_MASK (0x1 << 15) +#define RT5668_EN_4BTN_INL_SHIFT 15 +#define RT5668_EN_4BTN_INL_DIS (0x0 << 15) +#define RT5668_EN_4BTN_INL_EN (0x1 << 15) +#define RT5668_RESET_4BTN_INL_MASK (0x1 << 14) +#define RT5668_RESET_4BTN_INL_SHIFT 14 +#define RT5668_RESET_4BTN_INL_RESET (0x0 << 14) +#define RT5668_RESET_4BTN_INL_NOR (0x1 << 14) + +/* Digital Misc Control (0x00fa) */ +#define RT5668_DIG_GATE_CTRL_MASK 0x1 +#define RT5668_DIG_GATE_CTRL_SHIFT (0) +#define RT5668_DIG_GATE_CTRL_DIS 0x0 +#define RT5668_DIG_GATE_CTRL_EN 0x1 + +/* Chopper and Clock control for DAC L (0x013a)*/ +#define RT5668_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5668_CKXEN_DAC1_SHIFT 13 +#define RT5668_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5668_CKGEN_DAC1_SHIFT 12 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5668_CKXEN_ADCC_MASK (0x1 << 13) +#define RT5668_CKXEN_ADCC_SHIFT 13 +#define RT5668_CKGEN_ADCC_MASK (0x1 << 12) +#define RT5668_CKGEN_ADCC_SHIFT 12 + +/* HP Behavior Logic Control 2 (0x01db) */ +#define RT5668_HP_SIG_SRC1_MASK (0x3) +#define RT5668_HP_SIG_SRC1_SHIFT 0 +#define RT5668_HP_SIG_SRC1_HP_DC (0x0) +#define RT5668_HP_SIG_SRC1_HP_CALIB (0x1) +#define RT5668_HP_SIG_SRC1_REG (0x2) +#define RT5668_HP_SIG_SRC1_SILENCE (0x3) + +/* RT5663 specific register */ +#define RT5663_HP_OUT_EN 0x0002 +#define RT5663_HP_LCH_DRE 0x0005 +#define RT5663_HP_RCH_DRE 0x0006 +#define RT5663_CALIB_BST 0x000a +#define RT5663_RECMIX 0x0010 +#define RT5663_SIL_DET_CTL 0x0015 +#define RT5663_PWR_SAV_SILDET 0x0016 +#define RT5663_SIDETONE_CTL 0x0018 +#define RT5663_STO1_DAC_DIG_VOL 0x0019 +#define RT5663_STO1_ADC_DIG_VOL 0x001c +#define RT5663_STO1_BOOST 0x001f +#define RT5663_HP_IMP_GAIN_1 0x0022 +#define RT5663_HP_IMP_GAIN_2 0x0023 +#define RT5663_STO1_ADC_MIXER 0x0026 +#define RT5663_AD_DA_MIXER 0x0029 +#define RT5663_STO_DAC_MIXER 0x002a +#define RT5663_DIG_SIDE_MIXER 0x002c +#define RT5663_BYPASS_STO_DAC 0x002d +#define RT5663_CALIB_REC_MIX 0x0040 +#define RT5663_PWR_DIG_1 0x0061 +#define RT5663_PWR_DIG_2 0x0062 +#define RT5663_PWR_ANLG_1 0x0063 +#define RT5663_PWR_ANLG_2 0x0064 +#define RT5663_PWR_ANLG_3 0x0065 +#define RT5663_PWR_MIXER 0x0066 +#define RT5663_SIG_CLK_DET 0x006b +#define RT5663_PRE_DIV_GATING_1 0x006e +#define RT5663_PRE_DIV_GATING_2 0x006f +#define RT5663_I2S1_SDP 0x0070 +#define RT5663_ADDA_CLK_1 0x0073 +#define RT5663_ADDA_RST 0x0074 +#define RT5663_FRAC_DIV_1 0x0075 +#define RT5663_FRAC_DIV_2 0x0076 +#define RT5663_TDM_1 0x0077 +#define RT5663_TDM_2 0x0078 +#define RT5663_TDM_3 0x0079 +#define RT5663_TDM_4 0x007a +#define RT5663_TDM_5 0x007b +#define RT5663_GLB_CLK 0x0080 +#define RT5663_PLL_1 0x0081 +#define RT5663_PLL_2 0x0082 +#define RT5663_ASRC_1 0x0083 +#define RT5663_ASRC_2 0x0084 +#define RT5663_ASRC_4 0x0086 +#define RT5663_DUMMY_REG 0x0087 +#define RT5663_ASRC_8 0x008a +#define RT5663_ASRC_9 0x008b +#define RT5663_ASRC_11 0x008c +#define RT5663_DEPOP_1 0x008e +#define RT5663_DEPOP_2 0x008f +#define RT5663_DEPOP_3 0x0090 +#define RT5663_HP_CHARGE_PUMP_1 0x0091 +#define RT5663_HP_CHARGE_PUMP_2 0x0092 +#define RT5663_MICBIAS_1 0x0093 +#define RT5663_RC_CLK 0x0094 +#define RT5663_ASRC_11_2 0x0097 +#define RT5663_DUMMY_REG_2 0x0098 +#define RT5663_REC_PATH_GAIN 0x009a +#define RT5663_AUTO_1MRC_CLK 0x009f +#define RT5663_ADC_EQ_1 0x00ae +#define RT5663_ADC_EQ_2 0x00af +#define RT5663_IRQ_1 0x00b6 +#define RT5663_IRQ_2 0x00b7 +#define RT5663_IRQ_3 0x00b8 +#define RT5663_IRQ_4 0x00ba +#define RT5663_IRQ_5 0x00bb +#define RT5663_INT_ST_1 0x00be +#define RT5663_INT_ST_2 0x00bf +#define RT5663_GPIO_1 0x00c0 +#define RT5663_GPIO_2 0x00c1 +#define RT5663_GPIO_STA 0x00c5 +#define RT5663_SIN_GEN_1 0x00cb +#define RT5663_SIN_GEN_2 0x00cc +#define RT5663_SIN_GEN_3 0x00cd +#define RT5663_SOF_VOL_ZC1 0x00d9 +#define RT5663_IL_CMD_1 0x00db +#define RT5663_IL_CMD_2 0x00dc +#define RT5663_IL_CMD_3 0x00dd +#define RT5663_IL_CMD_4 0x00de +#define RT5663_IL_CMD_5 0x00df +#define RT5663_IL_CMD_6 0x00e0 +#define RT5663_IL_CMD_7 0x00e1 +#define RT5663_IL_CMD_8 0x00e2 +#define RT5663_IL_CMD_PWRSAV1 0x00e4 +#define RT5663_IL_CMD_PWRSAV2 0x00e5 +#define RT5663_EM_JACK_TYPE_1 0x00e6 +#define RT5663_EM_JACK_TYPE_2 0x00e7 +#define RT5663_EM_JACK_TYPE_3 0x00e8 +#define RT5663_EM_JACK_TYPE_4 0x00e9 +#define RT5663_EM_JACK_TYPE_5 0x00ea +#define RT5663_EM_JACK_TYPE_6 0x00eb +#define RT5663_STO1_HPF_ADJ1 0x00ec +#define RT5663_STO1_HPF_ADJ2 0x00ed +#define RT5663_FAST_OFF_MICBIAS 0x00f4 +#define RT5663_JD_CTRL1 0x00f6 +#define RT5663_JD_CTRL2 0x00f8 +#define RT5663_DIG_MISC 0x00fa +#define RT5663_DIG_VOL_ZCD 0x0100 +#define RT5663_ANA_BIAS_CUR_1 0x0108 +#define RT5663_ANA_BIAS_CUR_2 0x0109 +#define RT5663_ANA_BIAS_CUR_3 0x010a +#define RT5663_ANA_BIAS_CUR_4 0x010b +#define RT5663_ANA_BIAS_CUR_5 0x010c +#define RT5663_ANA_BIAS_CUR_6 0x010d +#define RT5663_BIAS_CUR_5 0x010e +#define RT5663_BIAS_CUR_6 0x010f +#define RT5663_BIAS_CUR_7 0x0110 +#define RT5663_BIAS_CUR_8 0x0111 +#define RT5663_DACREF_LDO 0x0112 +#define RT5663_DUMMY_REG_3 0x0113 +#define RT5663_BIAS_CUR_9 0x0114 +#define RT5663_DUMMY_REG_4 0x0116 +#define RT5663_VREFADJ_OP 0x0117 +#define RT5663_VREF_RECMIX 0x0118 +#define RT5663_CHARGE_PUMP_1 0x0125 +#define RT5663_CHARGE_PUMP_1_2 0x0126 +#define RT5663_CHARGE_PUMP_1_3 0x0127 +#define RT5663_CHARGE_PUMP_2 0x0128 +#define RT5663_DIG_IN_PIN1 0x0132 +#define RT5663_PAD_DRV_CTL 0x0137 +#define RT5663_PLL_INT_REG 0x0139 +#define RT5663_CHOP_DAC_L 0x013a +#define RT5663_CHOP_ADC 0x013b +#define RT5663_CALIB_ADC 0x013c +#define RT5663_CHOP_DAC_R 0x013d +#define RT5663_DUMMY_CTL_DACLR 0x013e +#define RT5663_DUMMY_REG_5 0x0140 +#define RT5663_SOFT_RAMP 0x0141 +#define RT5663_TEST_MODE_1 0x0144 +#define RT5663_TEST_MODE_2 0x0145 +#define RT5663_TEST_MODE_3 0x0146 +#define RT5663_STO_DRE_1 0x0160 +#define RT5663_STO_DRE_2 0x0161 +#define RT5663_STO_DRE_3 0x0162 +#define RT5663_STO_DRE_4 0x0163 +#define RT5663_STO_DRE_5 0x0164 +#define RT5663_STO_DRE_6 0x0165 +#define RT5663_STO_DRE_7 0x0166 +#define RT5663_STO_DRE_8 0x0167 +#define RT5663_STO_DRE_9 0x0168 +#define RT5663_STO_DRE_10 0x0169 +#define RT5663_MIC_DECRO_1 0x0180 +#define RT5663_MIC_DECRO_2 0x0181 +#define RT5663_MIC_DECRO_3 0x0182 +#define RT5663_MIC_DECRO_4 0x0183 +#define RT5663_MIC_DECRO_5 0x0184 +#define RT5663_MIC_DECRO_6 0x0185 +#define RT5663_HP_DECRO_1 0x01b0 +#define RT5663_HP_DECRO_2 0x01b1 +#define RT5663_HP_DECRO_3 0x01b2 +#define RT5663_HP_DECRO_4 0x01b3 +#define RT5663_HP_DECOUP 0x01b4 +#define RT5663_HP_IMP_SEN_MAP8 0x01b5 +#define RT5663_HP_IMP_SEN_MAP9 0x01b6 +#define RT5663_HP_IMP_SEN_MAP10 0x01b7 +#define RT5663_HP_IMP_SEN_MAP11 0x01b8 +#define RT5663_HP_IMP_SEN_1 0x01c0 +#define RT5663_HP_IMP_SEN_2 0x01c1 +#define RT5663_HP_IMP_SEN_3 0x01c2 +#define RT5663_HP_IMP_SEN_4 0x01c3 +#define RT5663_HP_IMP_SEN_5 0x01c4 +#define RT5663_HP_IMP_SEN_6 0x01c5 +#define RT5663_HP_IMP_SEN_7 0x01c6 +#define RT5663_HP_IMP_SEN_8 0x01c7 +#define RT5663_HP_IMP_SEN_9 0x01c8 +#define RT5663_HP_IMP_SEN_10 0x01c9 +#define RT5663_HP_IMP_SEN_11 0x01ca +#define RT5663_HP_IMP_SEN_12 0x01cb +#define RT5663_HP_IMP_SEN_13 0x01cc +#define RT5663_HP_IMP_SEN_14 0x01cd +#define RT5663_HP_IMP_SEN_15 0x01ce +#define RT5663_HP_IMP_SEN_16 0x01cf +#define RT5663_HP_IMP_SEN_17 0x01d0 +#define RT5663_HP_IMP_SEN_18 0x01d1 +#define RT5663_HP_IMP_SEN_19 0x01d2 +#define RT5663_HP_IMPSEN_DIG5 0x01d3 +#define RT5663_HP_IMPSEN_MAP1 0x01d4 +#define RT5663_HP_IMPSEN_MAP2 0x01d5 +#define RT5663_HP_IMPSEN_MAP3 0x01d6 +#define RT5663_HP_IMPSEN_MAP4 0x01d7 +#define RT5663_HP_IMPSEN_MAP5 0x01d8 +#define RT5663_HP_IMPSEN_MAP7 0x01d9 +#define RT5663_HP_LOGIC_1 0x01da +#define RT5663_HP_LOGIC_2 0x01db +#define RT5663_HP_CALIB_1 0x01dd +#define RT5663_HP_CALIB_1_1 0x01de +#define RT5663_HP_CALIB_2 0x01df +#define RT5663_HP_CALIB_3 0x01e0 +#define RT5663_HP_CALIB_4 0x01e1 +#define RT5663_HP_CALIB_5 0x01e2 +#define RT5663_HP_CALIB_5_1 0x01e3 +#define RT5663_HP_CALIB_6 0x01e4 +#define RT5663_HP_CALIB_7 0x01e5 +#define RT5663_HP_CALIB_9 0x01e6 +#define RT5663_HP_CALIB_10 0x01e7 +#define RT5663_HP_CALIB_11 0x01e8 +#define RT5663_HP_CALIB_ST1 0x01ea +#define RT5663_HP_CALIB_ST2 0x01eb +#define RT5663_HP_CALIB_ST3 0x01ec +#define RT5663_HP_CALIB_ST4 0x01ed +#define RT5663_HP_CALIB_ST5 0x01ee +#define RT5663_HP_CALIB_ST6 0x01ef +#define RT5663_HP_CALIB_ST7 0x01f0 +#define RT5663_HP_CALIB_ST8 0x01f1 +#define RT5663_HP_CALIB_ST9 0x01f2 +#define RT5663_HP_AMP_DET 0x0200 +#define RT5663_DUMMY_REG_6 0x0201 +#define RT5663_HP_BIAS 0x0202 +#define RT5663_CBJ_1 0x0250 +#define RT5663_CBJ_2 0x0251 +#define RT5663_CBJ_3 0x0252 +#define RT5663_DUMMY_1 0x02fa +#define RT5663_DUMMY_2 0x02fb +#define RT5663_DUMMY_3 0x02fc +#define RT5663_ANA_JD 0x0300 +#define RT5663_ADC_LCH_LPF1_A1 0x03d0 +#define RT5663_ADC_RCH_LPF1_A1 0x03d1 +#define RT5663_ADC_LCH_LPF1_H0 0x03d2 +#define RT5663_ADC_RCH_LPF1_H0 0x03d3 +#define RT5663_ADC_LCH_BPF1_A1 0x03d4 +#define RT5663_ADC_RCH_BPF1_A1 0x03d5 +#define RT5663_ADC_LCH_BPF1_A2 0x03d6 +#define RT5663_ADC_RCH_BPF1_A2 0x03d7 +#define RT5663_ADC_LCH_BPF1_H0 0x03d8 +#define RT5663_ADC_RCH_BPF1_H0 0x03d9 +#define RT5663_ADC_LCH_BPF2_A1 0x03da +#define RT5663_ADC_RCH_BPF2_A1 0x03db +#define RT5663_ADC_LCH_BPF2_A2 0x03dc +#define RT5663_ADC_RCH_BPF2_A2 0x03dd +#define RT5663_ADC_LCH_BPF2_H0 0x03de +#define RT5663_ADC_RCH_BPF2_H0 0x03df +#define RT5663_ADC_LCH_BPF3_A1 0x03e0 +#define RT5663_ADC_RCH_BPF3_A1 0x03e1 +#define RT5663_ADC_LCH_BPF3_A2 0x03e2 +#define RT5663_ADC_RCH_BPF3_A2 0x03e3 +#define RT5663_ADC_LCH_BPF3_H0 0x03e4 +#define RT5663_ADC_RCH_BPF3_H0 0x03e5 +#define RT5663_ADC_LCH_BPF4_A1 0x03e6 +#define RT5663_ADC_RCH_BPF4_A1 0x03e7 +#define RT5663_ADC_LCH_BPF4_A2 0x03e8 +#define RT5663_ADC_RCH_BPF4_A2 0x03e9 +#define RT5663_ADC_LCH_BPF4_H0 0x03ea +#define RT5663_ADC_RCH_BPF4_H0 0x03eb +#define RT5663_ADC_LCH_HPF1_A1 0x03ec +#define RT5663_ADC_RCH_HPF1_A1 0x03ed +#define RT5663_ADC_LCH_HPF1_H0 0x03ee +#define RT5663_ADC_RCH_HPF1_H0 0x03ef +#define RT5663_ADC_EQ_PRE_VOL_L 0x03f0 +#define RT5663_ADC_EQ_PRE_VOL_R 0x03f1 +#define RT5663_ADC_EQ_POST_VOL_L 0x03f2 +#define RT5663_ADC_EQ_POST_VOL_R 0x03f3 + +/* RT5663: RECMIX Control (0x0010) */ +#define RT5663_RECMIX1_BST1_MASK (0x1) +#define RT5663_RECMIX1_BST1_SHIFT 0 +#define RT5663_RECMIX1_BST1_ON (0x0) +#define RT5663_RECMIX1_BST1_OFF (0x1) + +/* RT5663: Bypass Stereo1 DAC Mixer Control (0x002d) */ +#define RT5663_DACL1_SRC_MASK (0x1 << 3) +#define RT5663_DACL1_SRC_SHIFT 3 +#define RT5663_DACR1_SRC_MASK (0x1 << 2) +#define RT5663_DACR1_SRC_SHIFT 2 + +/* RT5663: TDM control 2 (0x0078) */ +#define RT5663_DATA_SWAP_ADCDAT1_MASK (0x3 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_SHIFT 14 +#define RT5663_DATA_SWAP_ADCDAT1_LR (0x0 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_RL (0x1 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_LL (0x2 << 14) +#define RT5663_DATA_SWAP_ADCDAT1_RR (0x3 << 14) + +/* RT5663: TDM control 5 (0x007b) */ +#define RT5663_TDM_LENGTN_MASK (0x3) +#define RT5663_TDM_LENGTN_SHIFT 0 +#define RT5663_TDM_LENGTN_16 (0x0) +#define RT5663_TDM_LENGTN_20 (0x1) +#define RT5663_TDM_LENGTN_24 (0x2) +#define RT5663_TDM_LENGTN_32 (0x3) + +/* RT5663: Global Clock Control (0x0080) */ +#define RT5663_SCLK_SRC_MASK (0x3 << 14) +#define RT5663_SCLK_SRC_SHIFT 14 +#define RT5663_SCLK_SRC_MCLK (0x0 << 14) +#define RT5663_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5663_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5663_PLL1_SRC_MASK (0x7 << 11) +#define RT5663_PLL1_SRC_SHIFT 11 +#define RT5663_PLL1_SRC_MCLK (0x0 << 11) +#define RT5663_PLL1_SRC_BCLK1 (0x1 << 11) + +/* PLL tracking mode 1 (0x0083) */ +#define RT5663_I2S1_ASRC_MASK (0x1 << 11) +#define RT5663_I2S1_ASRC_SHIFT 11 +#define RT5663_DAC_STO1_ASRC_MASK (0x1 << 10) +#define RT5663_DAC_STO1_ASRC_SHIFT 10 +#define RT5663_ADC_STO1_ASRC_MASK (0x1 << 3) +#define RT5663_ADC_STO1_ASRC_SHIFT 3 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5663_DA_STO1_TRACK_MASK (0x7 << 12) +#define RT5663_DA_STO1_TRACK_SHIFT 12 +#define RT5663_DA_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5663_DA_STO1_TRACK_I2S1 (0x1 << 12) +#define RT5663_AD_STO1_TRACK_MASK (0x7) +#define RT5663_AD_STO1_TRACK_SHIFT 0 +#define RT5663_AD_STO1_TRACK_SYSCLK (0x0) +#define RT5663_AD_STO1_TRACK_I2S1 (0x1) + +/* RT5663: HPOUT Charge pump control 1 (0x0091) */ +#define RT5663_SI_HP_MASK (0x1 << 12) +#define RT5663_SI_HP_SHIFT 12 +#define RT5663_SI_HP_EN (0x1 << 12) +#define RT5663_SI_HP_DIS (0x0 << 12) + +/* RT5663: GPIO Control 2 (0x00b6) */ +#define RT5663_GP1_PIN_CONF_MASK (0x1 << 2) +#define RT5663_GP1_PIN_CONF_SHIFT 2 +#define RT5663_GP1_PIN_CONF_OUTPUT (0x1 << 2) +#define RT5663_GP1_PIN_CONF_INPUT (0x0 << 2) + +/* RT5663: GPIO Control 2 (0x00b7) */ +#define RT5663_EN_IRQ_INLINE_MASK (0x1 << 3) +#define RT5663_EN_IRQ_INLINE_SHIFT 3 +#define RT5663_EN_IRQ_INLINE_NOR (0x1 << 3) +#define RT5663_EN_IRQ_INLINE_BYP (0x0 << 3) + +/* RT5663: IRQ Control 1 (0x00c1) */ +#define RT5663_EN_IRQ_JD1_MASK (0x1 << 6) +#define RT5663_EN_IRQ_JD1_SHIFT 6 +#define RT5663_EN_IRQ_JD1_EN (0x1 << 6) +#define RT5663_EN_IRQ_JD1_DIS (0x0 << 6) + +/* RT5663: Inline Command Function 2 (0x00dc) */ +#define RT5663_PWR_MIC_DET_MASK (0x1) +#define RT5663_PWR_MIC_DET_SHIFT 0 +#define RT5663_PWR_MIC_DET_ON (0x1) +#define RT5663_PWR_MIC_DET_OFF (0x0) + +/* RT5663: Embeeded Jack and Type Detection Control 1 (0x00e6)*/ +#define RT5663_CBJ_DET_MASK (0x1 << 15) +#define RT5663_CBJ_DET_SHIFT 15 +#define RT5663_CBJ_DET_DIS (0x0 << 15) +#define RT5663_CBJ_DET_EN (0x1 << 15) +#define RT5663_EXT_JD_MASK (0x1 << 11) +#define RT5663_EXT_JD_SHIFT 11 +#define RT5663_EXT_JD_EN (0x1 << 11) +#define RT5663_EXT_JD_DIS (0x0 << 11) +#define RT5663_POL_EXT_JD_MASK (0x1 << 10) +#define RT5663_POL_EXT_JD_SHIFT 10 +#define RT5663_POL_EXT_JD_EN (0x1 << 10) +#define RT5663_POL_EXT_JD_DIS (0x0 << 10) + +/* RT5663: DACREF LDO Control (0x0112)*/ +#define RT5663_PWR_LDO_DACREFL_MASK (0x1 << 9) +#define RT5663_PWR_LDO_DACREFL_SHIFT 9 +#define RT5663_PWR_LDO_DACREFR_MASK (0x1 << 1) +#define RT5663_PWR_LDO_DACREFR_SHIFT 1 + +/* RT5663: Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/ +#define RT5663_DRE_GAIN_HP_MASK (0x1f) +#define RT5663_DRE_GAIN_HP_SHIFT 0 + +/* RT5663: Combo Jack Control (0x0250) */ +#define RT5663_INBUF_CBJ_BST1_MASK (0x1 << 11) +#define RT5663_INBUF_CBJ_BST1_SHIFT 11 +#define RT5663_INBUF_CBJ_BST1_ON (0x1 << 11) +#define RT5663_INBUF_CBJ_BST1_OFF (0x0 << 11) +#define RT5663_CBJ_SENSE_BST1_MASK (0x1 << 10) +#define RT5663_CBJ_SENSE_BST1_SHIFT 10 +#define RT5663_CBJ_SENSE_BST1_L (0x1 << 10) +#define RT5663_CBJ_SENSE_BST1_R (0x0 << 10) + +/* RT5663: Combo Jack Control (0x0251) */ +#define RT5663_GAIN_BST1_MASK (0xf) +#define RT5663_GAIN_BST1_SHIFT 0 + +/* RT5663: Dummy register 1 (0x02fa) */ +#define RT5663_EMB_CLK_MASK (0x1 << 9) +#define RT5663_EMB_CLK_SHIFT 9 +#define RT5663_EMB_CLK_EN (0x1 << 9) +#define RT5663_EMB_CLK_DIS (0x0 << 9) +#define RT5663_HPA_CPL_BIAS_MASK (0x7 << 6) +#define RT5663_HPA_CPL_BIAS_SHIFT 6 +#define RT5663_HPA_CPL_BIAS_0_5 (0x0 << 6) +#define RT5663_HPA_CPL_BIAS_1 (0x1 << 6) +#define RT5663_HPA_CPL_BIAS_2 (0x2 << 6) +#define RT5663_HPA_CPL_BIAS_3 (0x3 << 6) +#define RT5663_HPA_CPL_BIAS_4_1 (0x4 << 6) +#define RT5663_HPA_CPL_BIAS_4_2 (0x5 << 6) +#define RT5663_HPA_CPL_BIAS_6 (0x6 << 6) +#define RT5663_HPA_CPL_BIAS_8 (0x7 << 6) +#define RT5663_HPA_CPR_BIAS_MASK (0x7 << 3) +#define RT5663_HPA_CPR_BIAS_SHIFT 3 +#define RT5663_HPA_CPR_BIAS_0_5 (0x0 << 3) +#define RT5663_HPA_CPR_BIAS_1 (0x1 << 3) +#define RT5663_HPA_CPR_BIAS_2 (0x2 << 3) +#define RT5663_HPA_CPR_BIAS_3 (0x3 << 3) +#define RT5663_HPA_CPR_BIAS_4_1 (0x4 << 3) +#define RT5663_HPA_CPR_BIAS_4_2 (0x5 << 3) +#define RT5663_HPA_CPR_BIAS_6 (0x6 << 3) +#define RT5663_HPA_CPR_BIAS_8 (0x7 << 3) +#define RT5663_DUMMY_BIAS_MASK (0x7) +#define RT5663_DUMMY_BIAS_SHIFT 0 +#define RT5663_DUMMY_BIAS_0_5 (0x0) +#define RT5663_DUMMY_BIAS_1 (0x1) +#define RT5663_DUMMY_BIAS_2 (0x2) +#define RT5663_DUMMY_BIAS_3 (0x3) +#define RT5663_DUMMY_BIAS_4_1 (0x4) +#define RT5663_DUMMY_BIAS_4_2 (0x5) +#define RT5663_DUMMY_BIAS_6 (0x6) +#define RT5663_DUMMY_BIAS_8 (0x7) + + +/* System Clock Source */ +enum { + RT5663_SCLK_S_MCLK, + RT5663_SCLK_S_PLL1, + RT5663_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5663_PLL1_S_MCLK, + RT5663_PLL1_S_BCLK1, +}; + +enum { + RT5663_AIF, + RT5663_AIFS, +}; + +/* asrc clock source */ +enum { + RT5663_CLK_SEL_SYS = 0x0, + RT5663_CLK_SEL_I2S1_ASRC = 0x1, +}; + +/* filter mask */ +enum { + RT5663_DA_STEREO_FILTER = 0x1, + RT5663_AD_STEREO_FILTER = 0x2, +}; + +int rt5663_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack); +int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); + +#endif /* __RT5663_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 68268f2d68ca..abc802a5a479 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/acpi.h> #include <linux/fs.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -40,6 +41,15 @@ #define RT5677_PR_BASE (RT5677_PR_RANGE_BASE + (0 * RT5677_PR_SPACING)) +/* GPIO indexes defined by ACPI */ +enum { + RT5677_GPIO_PLUG_DET = 0, + RT5677_GPIO_MIC_PRESENT_L = 1, + RT5677_GPIO_HOTWORD_DET_L = 2, + RT5677_GPIO_DSP_INT = 3, + RT5677_GPIO_HP_AMP_SHDN_L = 4, +}; + static const struct regmap_range_cfg rt5677_ranges[] = { { .name = "PR", @@ -4657,7 +4667,7 @@ static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) return regmap_irq_get_virq(data, irq); } -static struct gpio_chip rt5677_template_chip = { +static const struct gpio_chip rt5677_template_chip = { .label = "rt5677", .owner = THIS_MODULE, .direction_output = rt5677_gpio_direction_out, @@ -5020,10 +5030,47 @@ static const struct regmap_config rt5677_regmap = { static const struct i2c_device_id rt5677_i2c_id[] = { { "rt5677", RT5677 }, { "rt5676", RT5676 }, + { "RT5677CE:00", RT5677 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); +static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; +static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; +static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; + +static const struct acpi_gpio_mapping bdw_rt5677_gpios[] = { + { "plug-det-gpios", &plug_det_gpio, 1 }, + { "mic-present-gpios", &mic_present_gpio, 1 }, + { "headphone-enable-gpios", &headphone_enable_gpio, 1 }, + { NULL }, +}; + +static void rt5677_read_acpi_properties(struct rt5677_priv *rt5677, + struct device *dev) +{ + int ret; + u32 val; + + ret = acpi_dev_add_driver_gpios(ACPI_COMPANION(dev), + bdw_rt5677_gpios); + if (ret) + dev_warn(dev, "Failed to add driver gpios\n"); + + if (!device_property_read_u32(dev, "DCLK", &val)) + rt5677->pdata.dmic2_clk_pin = val; + + rt5677->pdata.in1_diff = device_property_read_bool(dev, "IN1"); + rt5677->pdata.in2_diff = device_property_read_bool(dev, "IN2"); + rt5677->pdata.lout1_diff = device_property_read_bool(dev, "OUT1"); + rt5677->pdata.lout2_diff = device_property_read_bool(dev, "OUT2"); + rt5677->pdata.lout3_diff = device_property_read_bool(dev, "OUT3"); + + device_property_read_u32(dev, "JD1", &rt5677->pdata.jd1_gpio); + device_property_read_u32(dev, "JD2", &rt5677->pdata.jd2_gpio); + device_property_read_u32(dev, "JD3", &rt5677->pdata.jd3_gpio); +} + static void rt5677_read_device_properties(struct rt5677_priv *rt5677, struct device *dev) { @@ -5129,8 +5176,12 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; - else + else if (i2c->dev.of_node) rt5677_read_device_properties(rt5677, &i2c->dev); + else if (ACPI_HANDLE(&i2c->dev)) + rt5677_read_acpi_properties(rt5677, &i2c->dev); + else + return -EINVAL; /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index a635bd09d637..1589325855bc 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -411,6 +411,8 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { 0, 8, 0x7f, 1, headphone_volume), + SOC_SINGLE("Headphone Playback Switch", SGTL5000_CHIP_ANA_CTRL, + 4, 1, 1), SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL, 5, 1, 0), @@ -423,6 +425,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT, 0x1f, 1, lineout_volume), + SOC_SINGLE("Lineout Playback Switch", SGTL5000_CHIP_ANA_CTRL, 8, 1, 1), }; /* mute the codec used by alsa core */ diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 2c5941f3a234..27f30d352867 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -85,10 +85,10 @@ static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum, static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum, AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic); -static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0); -static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); -static const DECLARE_TLV_DB_LINEAR(beep_tlv, -4500, 0); -static const DECLARE_TLV_DB_LINEAR(mix_tlv, -3450, 1200); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(master_tlv, -4650, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(record_tlv, 0, 150, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(beep_tlv, -4500, 300, 0); +static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(mix_tlv, -3450, 150, 0); static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { SOC_DOUBLE_TLV("Speaker Volume", AC97_MASTER, 8, 0, 31, 1, master_tlv), diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index f1ea052a822e..3b6faed91d7e 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -52,7 +52,7 @@ struct tpa6130a2_data { static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable) { - int ret; + int ret = 0, ret2; if (enable) { ret = regulator_enable(data->supply); @@ -64,20 +64,34 @@ static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable) /* Power on */ if (data->power_gpio >= 0) gpio_set_value(data->power_gpio, 1); + + /* Sync registers */ + regcache_cache_only(data->regmap, false); + ret = regcache_sync(data->regmap); + if (ret != 0) { + dev_err(data->dev, + "Failed to sync registers: %d\n", ret); + goto regcache_sync_failed; + } } else { + /* Powered off device does not retain registers. While device + * is off, any register updates (i.e. volume changes) should + * happen in cache only. + */ + regcache_mark_dirty(data->regmap); +regcache_sync_failed: + regcache_cache_only(data->regmap, true); + /* Power off */ if (data->power_gpio >= 0) gpio_set_value(data->power_gpio, 0); - ret = regulator_disable(data->supply); - if (ret != 0) { + ret2 = regulator_disable(data->supply); + if (ret2 != 0) { dev_err(data->dev, - "Failed to disable supply: %d\n", ret); - return ret; + "Failed to disable supply: %d\n", ret2); + return ret ? ret : ret2; } - - /* device regs does not match the cache state anymore */ - regcache_mark_dirty(data->regmap); } return ret; @@ -88,25 +102,14 @@ static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w, { struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c); - int ret; - /* before widget power up */ if (SND_SOC_DAPM_EVENT_ON(event)) { - /* Turn on the chip */ - tpa6130a2_power(data, true); - /* Sync the registers */ - ret = regcache_sync(data->regmap); - if (ret < 0) { - dev_err(c->dev, "Failed to initialize chip\n"); - tpa6130a2_power(data, false); - return ret; - } - /* after widget power down */ + /* Before widget power up: turn chip on, sync registers */ + return tpa6130a2_power(data, true); } else { - tpa6130a2_power(data, false); + /* After widget power down: turn chip off */ + return tpa6130a2_power(data, false); } - - return 0; } /* diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index a4a3e9854086..5fdee874406d 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -546,6 +546,7 @@ static int uda134x_codec_probe(struct platform_device *pdev) { struct uda134x_platform_data *pd = pdev->dev.platform_data; struct uda134x_priv *uda134x; + int ret; if (!pd) { dev_err(&pdev->dev, "Missing L3 bitbang function\n"); @@ -559,6 +560,12 @@ static int uda134x_codec_probe(struct platform_device *pdev) uda134x->pd = pd; platform_set_drvdata(pdev, uda134x); + if (pd->l3.use_gpios) { + ret = l3_set_gpio_ops(&pdev->dev, &uda134x->pd->l3); + if (ret < 0) + return ret; + } + uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd, &uda134x_regmap_config); if (IS_ERR(uda134x->regmap)) diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index e553f7fd7e63..23cde3a0dc11 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -581,7 +581,7 @@ static int wm2000_anc_transition(struct wm2000_priv *wm2000, if (anc_transitions[i].dest == ANC_OFF) clk_disable_unprepare(wm2000->mclk); - return ret; + return 0; } static int wm2000_anc_set_mode(struct wm2000_priv *wm2000) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 278467d3b1ac..560575000cc5 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2285,7 +2285,7 @@ static int wm5100_gpio_direction_in(struct gpio_chip *chip, unsigned offset) (1 << WM5100_GP1_DIR_SHIFT)); } -static struct gpio_chip wm5100_template_chip = { +static const struct gpio_chip wm5100_template_chip = { .label = "wm5100", .owner = THIS_MODULE, .direction_output = wm5100_gpio_direction_out, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 05bb3cb02e70..93876c6d48ee 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1521,6 +1521,16 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "IN3L", NULL, "SYSCLK" }, { "IN3R", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "MICBIAS1", NULL, "MICVDD" }, { "MICBIAS2", NULL, "MICVDD" }, { "MICBIAS3", NULL, "MICVDD" }, @@ -1600,7 +1610,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { { "Slim3 Capture", NULL, "SYSCLK" }, { "Audio Trace DSP", NULL, "DSP1" }, - { "Audio Trace DSP", NULL, "SYSCLK" }, { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index e22d3dcb6fd7..06bae3b23fce 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1745,6 +1745,16 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "IN4L", NULL, "SYSCLK" }, { "IN4R", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "MICBIAS1", NULL, "MICVDD" }, { "MICBIAS2", NULL, "MICVDD" }, { "MICBIAS3", NULL, "MICVDD" }, @@ -1832,10 +1842,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "Slim3 Capture", NULL, "SYSCLK" }, { "Voice Control DSP", NULL, "DSP3" }, - { "Voice Control DSP", NULL, "SYSCLK" }, { "Audio Trace DSP", NULL, "DSP1" }, - { "Audio Trace DSP", NULL, "SYSCLK" }, { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 837c8b9f19e9..6e887c2c42b1 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1830,7 +1830,7 @@ static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) !!value << WM8903_GP1_LVL_SHIFT); } -static struct gpio_chip wm8903_template_chip = { +static const struct gpio_chip wm8903_template_chip = { .label = "wm8903", .owner = THIS_MODULE, .request = wm8903_gpio_request, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 392b92067011..a0dd7b05b7d6 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3357,7 +3357,7 @@ static int wm8962_gpio_direction_out(struct gpio_chip *chip, return 0; } -static struct gpio_chip wm8962_template_chip = { +static const struct gpio_chip wm8962_template_chip = { .label = "wm8962", .owner = THIS_MODULE, .request = wm8962_gpio_request, diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 5eba8ffba427..8affa4969120 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2184,7 +2184,7 @@ static int wm8996_gpio_direction_in(struct gpio_chip *chip, unsigned offset) (1 << WM8996_GP1_DIR_SHIFT)); } -static struct gpio_chip wm8996_template_chip = { +static const struct gpio_chip wm8996_template_chip = { .label = "wm8996", .owner = THIS_MODULE, .direction_output = wm8996_gpio_direction_out, diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index f6d18d77cec2..bcc2e1060a6c 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -966,6 +966,16 @@ static const struct snd_soc_dapm_route wm8998_dapm_routes[] = { { "IN2A", NULL, "SYSCLK" }, { "IN2B", NULL, "SYSCLK" }, + { "ASRC1L", NULL, "SYSCLK" }, + { "ASRC1R", NULL, "SYSCLK" }, + { "ASRC2L", NULL, "SYSCLK" }, + { "ASRC2R", NULL, "SYSCLK" }, + + { "ASRC1L", NULL, "ASYNCCLK" }, + { "ASRC1R", NULL, "ASYNCCLK" }, + { "ASRC2L", NULL, "ASYNCCLK" }, + { "ASRC2R", NULL, "ASYNCCLK" }, + { "SPD1", NULL, "SYSCLK" }, { "SPD1", NULL, "SPD1TX1" }, { "SPD1", NULL, "SPD1TX2" }, diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 21fbe7d07063..b943dde8dbe5 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -480,7 +480,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, mutex_lock(&dsp->pwr_lock); - if (!dsp->wmfw_file_name || !dsp->running) + if (!dsp->wmfw_file_name || !dsp->booted) ret = 0; else ret = simple_read_from_buffer(user_buf, count, ppos, @@ -500,7 +500,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file, mutex_lock(&dsp->pwr_lock); - if (!dsp->bin_file_name || !dsp->running) + if (!dsp->bin_file_name || !dsp->booted) ret = 0; else ret = simple_read_from_buffer(user_buf, count, ppos, @@ -554,6 +554,9 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, if (!root) goto err; + if (!debugfs_create_bool("booted", S_IRUGO, root, &dsp->booted)) + goto err; + if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running)) goto err; @@ -637,7 +640,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, mutex_lock(&dsp[e->shift_l].pwr_lock); - if (dsp[e->shift_l].running || dsp[e->shift_l].compr) + if (dsp[e->shift_l].booted || dsp[e->shift_l].compr) ret = -EBUSY; else dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; @@ -789,7 +792,7 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, memcpy(ctl->cache, p, ctl->len); ctl->set = 1; - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_write_control(ctl, p, ctl->len); mutex_unlock(&ctl->dsp->pwr_lock); @@ -811,7 +814,7 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, ret = -EFAULT; } else { ctl->set = 1; - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_write_control(ctl, ctl->cache, size); } @@ -871,12 +874,12 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, mutex_lock(&ctl->dsp->pwr_lock); if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, p, ctl->len); else ret = -EPERM; } else { - if (!ctl->flags && ctl->enabled) + if (!ctl->flags && ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); memcpy(p, ctl->cache, ctl->len); @@ -898,12 +901,12 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, mutex_lock(&ctl->dsp->pwr_lock); if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { - if (ctl->enabled) + if (ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, ctl->cache, size); else ret = -EPERM; } else { - if (!ctl->flags && ctl->enabled) + if (!ctl->flags && ctl->enabled && ctl->dsp->running) ret = wm_coeff_read_control(ctl, ctl->cache, size); } @@ -2166,13 +2169,20 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, if (ret != 0) goto err_ena; + dsp->booted = true; + /* Start the core running */ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_CORE_ENA | ADSP1_START, ADSP1_CORE_ENA | ADSP1_START); + + dsp->running = true; break; case SND_SOC_DAPM_PRE_PMD: + dsp->running = false; + dsp->booted = false; + /* Halt the core */ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_CORE_ENA | ADSP1_START, 0); @@ -2227,7 +2237,7 @@ static int wm_adsp2_ena(struct wm_adsp *dsp) if (val & ADSP2_RAM_RDY) break; - msleep(1); + usleep_range(250, 500); } if (!(val & ADSP2_RAM_RDY)) { @@ -2249,6 +2259,11 @@ static void wm_adsp2_boot_work(struct work_struct *work) mutex_lock(&dsp->pwr_lock); + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, ADSP2_MEM_ENA); + if (ret != 0) + goto err_mutex; + ret = wm_adsp2_ena(dsp); if (ret != 0) goto err_mutex; @@ -2270,13 +2285,14 @@ static void wm_adsp2_boot_work(struct work_struct *work) if (ret != 0) goto err_ena; - /* Sync set controls */ - ret = wm_coeff_sync_controls(dsp); + dsp->booted = true; + + /* Turn DSP back off until we are ready to run */ + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, 0); if (ret != 0) goto err_ena; - dsp->running = true; - mutex_unlock(&dsp->pwr_lock); return; @@ -2307,6 +2323,7 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; + struct wm_coeff_ctl *ctl; dsp->card = codec->component.card; @@ -2315,6 +2332,24 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, wm_adsp2_set_dspclk(dsp, freq); queue_work(system_unbound_wq, &dsp->boot_work); break; + case SND_SOC_DAPM_PRE_PMD: + wm_adsp_debugfs_clear(dsp); + + dsp->fw_id = 0; + dsp->fw_id_version = 0; + + dsp->booted = false; + + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); + + list_for_each_entry(ctl, &dsp->ctl_list, list) + ctl->enabled = 0; + + wm_adsp_free_alg_regions(dsp); + + adsp_dbg(dsp, "Shutdown complete\n"); + break; default: break; } @@ -2329,16 +2364,24 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); struct wm_adsp *dsp = &dsps[w->shift]; - struct wm_coeff_ctl *ctl; int ret; switch (event) { case SND_SOC_DAPM_POST_PMU: flush_work(&dsp->boot_work); - if (!dsp->running) + if (!dsp->booted) return -EIO; + ret = wm_adsp2_ena(dsp); + if (ret != 0) + goto err; + + /* Sync set controls */ + ret = wm_coeff_sync_controls(dsp); + if (ret != 0) + goto err; + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_CORE_ENA | ADSP2_START, @@ -2346,6 +2389,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, if (ret != 0) goto err; + dsp->running = true; + mutex_lock(&dsp->pwr_lock); if (wm_adsp_fw[dsp->fw].num_caps != 0) @@ -2361,10 +2406,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, mutex_lock(&dsp->pwr_lock); - wm_adsp_debugfs_clear(dsp); - - dsp->fw_id = 0; - dsp->fw_id_version = 0; dsp->running = false; regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, @@ -2378,17 +2419,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_SYS_ENA, 0); - list_for_each_entry(ctl, &dsp->ctl_list, list) - ctl->enabled = 0; - - wm_adsp_free_alg_regions(dsp); - if (wm_adsp_fw[dsp->fw].num_caps != 0) wm_adsp_buffer_free(dsp); mutex_unlock(&dsp->pwr_lock); - adsp_dbg(dsp, "Shutdown complete\n"); + adsp_dbg(dsp, "Execution stopped\n"); break; default: diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index be3b5bcb7f17..362dd7ce60d8 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -61,6 +61,8 @@ struct wm_adsp { int fw; int fw_ver; + + bool booted; bool running; struct list_head ctl_list; @@ -85,9 +87,10 @@ struct wm_adsp { wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) #define WM_ADSP2(wname, num, event_fn) \ -{ .id = snd_soc_dapm_dai_link, .name = wname " Preloader", \ +{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \ .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ - .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD }, \ + .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \ + .subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \ { .id = snd_soc_dapm_out_drv, .name = wname, \ .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } |