ASoC: codecs: Add support for rockchip codec digital interface

This patch adds support for rockchip codec digital interface,
which is used to communicate with external codec analog part
with pdm link.

Change-Id: I9ea7020d904b63f7a34696b0f538accd8c700076
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
Sugar Zhang
2020-03-05 09:31:02 +08:00
parent 970d35ba6b
commit 88b08f7ee7
3 changed files with 82 additions and 5 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -10,6 +10,7 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
@@ -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));