diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b3f5f7e87bc8..fa128b8cdfc4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1080,6 +1080,9 @@ config SND_SOC_RK817 depends on MFD_RK808 select REGMAP_I2C +config SND_SOC_RK_CODEC_DIGITAL + tristate "Rockchip Codec Digital Interface" + config SND_SOC_RL6231 tristate default y if SND_SOC_RT5514=y diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index e3a1d2261f1a..d94d074c18ad 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -168,6 +168,7 @@ snd-soc-rk3228-objs := rk3228_codec.o snd-soc-rk3308-objs := rk3308_codec.o snd-soc-rk3328-objs := rk3328_codec.o snd-soc-rk817-objs := rk817_codec.o +snd-soc-rk-codec-digital-objs := rk_codec_digital.o snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt1011-objs := rt1011.o @@ -489,6 +490,7 @@ obj-$(CONFIG_SND_SOC_RK3228) += snd-soc-rk3228.o obj-$(CONFIG_SND_SOC_RK3308) += snd-soc-rk3308.o obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o obj-$(CONFIG_SND_SOC_RK817) += snd-soc-rk817.o +obj-$(CONFIG_SND_SOC_RK_CODEC_DIGITAL) += snd-soc-rk-codec-digital.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT1011) += snd-soc-rt1011.o diff --git a/sound/soc/codecs/rk_codec_digital.c b/sound/soc/codecs/rk_codec_digital.c index cd5221096432..ec91b72fa6de 100644 --- a/sound/soc/codecs/rk_codec_digital.c +++ b/sound/soc/codecs/rk_codec_digital.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,8 @@ struct rk_codec_digital_priv { struct clk *pclk; bool pwmout; bool sync; + unsigned int pa_ctl_delay_ms; + struct gpio_desc *pa_ctl; struct reset_control *rc; const struct rk_codec_digital_soc_data *data; }; @@ -66,14 +69,19 @@ static const char * const dac_hpf_cutoff_text[] = { static SOC_ENUM_SINGLE_DECL(dac_hpf_cutoff_enum, DACHPF, 4, dac_hpf_cutoff_text); +static const char * const pa_ctl[] = {"Off", "On"}; + +static const struct soc_enum pa_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pa_ctl), pa_ctl); + static int rk_codec_digital_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int val = snd_soc_component_read32(component, mc->reg); - unsigned int sign = snd_soc_component_read32(component, ADCVOGP); + unsigned int val = snd_soc_component_read(component, mc->reg); + unsigned int sign = snd_soc_component_read(component, ADCVOGP); unsigned int mask = (1 << fls(mc->max)) - 1; unsigned int shift = mc->shift; int mid = mc->max / 2; @@ -154,8 +162,8 @@ static int rk_codec_digital_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int val = snd_soc_component_read32(component, mc->reg); - unsigned int sign = snd_soc_component_read32(component, DACVOGP); + unsigned int val = snd_soc_component_read(component, mc->reg); + unsigned int sign = snd_soc_component_read(component, DACVOGP); unsigned int mask = (1 << fls(mc->max)) - 1; unsigned int shift = mc->shift; int mid = mc->max / 2; @@ -207,6 +215,34 @@ static int rk_codec_digital_dac_vol_put(struct snd_kcontrol *kcontrol, return 0; } +static int rk_codec_digital_dac_pa_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_codec_digital_priv *rcd = snd_soc_component_get_drvdata(component); + + if (!rcd->pa_ctl) + return -EINVAL; + + ucontrol->value.enumerated.item[0] = gpiod_get_value(rcd->pa_ctl); + + return 0; +} + +static int rk_codec_digital_dac_pa_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct rk_codec_digital_priv *rcd = snd_soc_component_get_drvdata(component); + + if (!rcd->pa_ctl) + return -EINVAL; + + gpiod_set_value(rcd->pa_ctl, ucontrol->value.enumerated.item[0]); + + return 0; +} + static const struct snd_kcontrol_new rk_codec_digital_snd_controls[] = { SOC_SINGLE_EXT_TLV("ADCL0 Digital Volume", ADCVOLL0, 0, 0X1fe, 0, @@ -244,6 +280,9 @@ static const struct snd_kcontrol_new rk_codec_digital_snd_controls[] = { SOC_ENUM("DAC HPF Cutoff", dac_hpf_cutoff_enum), SOC_SINGLE("DAC HPF Switch", DACHPF, 0, 1, 0), + SOC_ENUM_EXT("Power Amplifier", pa_enum, + rk_codec_digital_dac_pa_get, + rk_codec_digital_dac_pa_put), }; static void rk_codec_digital_reset(struct rk_codec_digital_priv *rcd) @@ -701,14 +740,32 @@ static int rk_codec_digital_hw_params(struct snd_pcm_substream *substream, return 0; } +static int rk_codec_digital_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rk_codec_digital_priv *rcd = + snd_soc_component_get_drvdata(dai->component); + + if (rcd->pa_ctl) { + gpiod_set_value_cansleep(rcd->pa_ctl, 1); + if (rcd->pa_ctl_delay_ms) + msleep(rcd->pa_ctl_delay_ms); + } + + return 0; +} + static void rk_codec_digital_pcm_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rk_codec_digital_priv *rcd = snd_soc_component_get_drvdata(dai->component); + if (rcd->pa_ctl) + gpiod_set_value_cansleep(rcd->pa_ctl, 0); + if (rcd->sync) { - if (!snd_soc_component_is_active(dai->component)) { + if (!snd_soc_component_active(dai->component)) { rk_codec_digital_disable_sync(rcd); rk_codec_digital_reset(rcd); } @@ -755,6 +812,7 @@ static void rk_codec_digital_pcm_shutdown(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops rcd_dai_ops = { .hw_params = rk_codec_digital_hw_params, .set_fmt = rk_codec_digital_set_dai_fmt, + .startup = rk_codec_digital_pcm_startup, .shutdown = rk_codec_digital_pcm_shutdown, }; @@ -931,6 +989,9 @@ static int rk_codec_digital_platform_probe(struct platform_device *pdev) rcd->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); rcd->pwmout = of_property_read_bool(np, "rockchip,pwm-output-mode"); rcd->sync = of_property_read_bool(np, "rockchip,clk-sync-mode"); + if (of_property_read_u32(np, "rockchip,pa-ctl-delay-ms", + &rcd->pa_ctl_delay_ms)) + rcd->pa_ctl_delay_ms = 0; rcd->rc = devm_reset_control_get(&pdev->dev, "reset"); @@ -982,6 +1043,17 @@ static int rk_codec_digital_platform_probe(struct platform_device *pdev) ACDCDIG_DACPWM_CTRL_PWM_MODE_MASK, ACDCDIG_DACPWM_CTRL_PWM_MODE_0); + rcd->pa_ctl = devm_gpiod_get_optional(&pdev->dev, "pa-ctl", + GPIOD_OUT_LOW); + + if (!rcd->pa_ctl) { + dev_info(&pdev->dev, "no need pa-ctl gpio\n"); + } else if (IS_ERR(rcd->pa_ctl)) { + ret = PTR_ERR(rcd->pa_ctl); + dev_err(&pdev->dev, "fail to request gpio pa-ctl\n"); + goto err_suspend; + } + ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_rcd, rcd_dai, ARRAY_SIZE(rcd_dai));