ASoC: rockchip: rk817-codec: add ext amplifier and loopback support

Change-Id: Icef0c8a72784260b0d49d8260b0f3377e53b953f
Signed-off-by: Binyuan Lan <lby@rock-chips.com>
This commit is contained in:
Binyuan Lan
2018-03-08 16:31:09 +08:00
committed by Tao Huang
parent e31aec5414
commit 2bb9ec21ad
2 changed files with 179 additions and 18 deletions

View File

@@ -5,6 +5,10 @@ Required properties:
- compatible: "rockchip,rk817-codec"
- clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names.
- clock-names: should be "mclk".
- spk-ctl-gpios: spk mute enable/disable
- hp-ctl-gpios: hp mute enable/disable
- spk-mute-delay-ms: spk mute delay time
- hp-mute-delay-ms: hp mute delay time
- spk-volume: DAC L/R volume digital setting for Speaker
- hp-volume: DAC L/R volume digital setting for Headphone
*
@@ -28,6 +32,10 @@ Required properties:
Boolean. Indicate MIC input are differential, rather than single-ended.
- pdmdata-out-enable:
Boolean. Indicate pdmdata output is enable or disable.
- use-ext-amplifier:
Boolean. Indicate use external amplifier or not.
- adc-for-loopback:
Boolean. Indicate adc use for loopback or not.
Example for rk817 codec:

View File

@@ -18,6 +18,7 @@
#include <linux/mfd/rk808.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <sound/core.h>
@@ -62,6 +63,9 @@ module_param_named(dbg_level, dbg_enable, int, 0644);
*/
#define CAPTURE_VOLUME (0x0)
#define CODEC_SET_SPK 1
#define CODEC_SET_HP 2
struct rk817_codec_priv {
struct snd_soc_codec *codec;
struct regmap *regmap;
@@ -77,9 +81,16 @@ struct rk817_codec_priv {
bool mic_in_differential;
bool pdmdata_out_enable;
bool use_ext_amplifier;
bool adc_for_loopback;
long int playback_path;
long int capture_path;
struct gpio_desc *spk_ctl_gpio;
struct gpio_desc *hp_ctl_gpio;
int spk_mute_delay;
int hp_mute_delay;
};
static const struct reg_default rk817_reg_defaults[] = {
@@ -216,6 +227,26 @@ static bool rk817_codec_register(struct device *dev, unsigned int reg)
}
}
static int rk817_codec_ctl_gpio(struct rk817_codec_priv *rk817,
int gpio, int level)
{
if ((gpio & CODEC_SET_SPK) &&
rk817->spk_ctl_gpio) {
gpiod_set_value(rk817->spk_ctl_gpio, level);
DBG("%s set spk clt %d\n", __func__, level);
msleep(rk817->spk_mute_delay);
}
if ((gpio & CODEC_SET_HP) &&
rk817->hp_ctl_gpio) {
gpiod_set_value(rk817->hp_ctl_gpio, level);
DBG("%s set hp clt %d\n", __func__, level);
msleep(rk817->hp_mute_delay);
}
return 0;
}
static struct rk817_reg_val_typ playback_power_up_list[] = {
{RK817_CODEC_AREF_RTCFG1, 0x40},
{RK817_CODEC_DDAC_POPD_DACST, 0x02},
@@ -471,17 +502,29 @@ static int rk817_playback_path_put(struct snd_kcontrol *kcontrol,
case RING_SPK:
if (pre_path == OFF)
rk817_codec_power_up(codec, RK817_CODEC_PLAYBACK);
/* power on dac ibias/l/r */
snd_soc_write(codec, RK817_CODEC_ADAC_CFG1,
PWD_DACBIAS_ON | PWD_DACD_ON |
PWD_DACL_ON | PWD_DACR_ON);
/* CLASS D mode */
snd_soc_write(codec, RK817_CODEC_DDAC_MUTE_MIXCTL, 0x10);
/* CLASS D enable */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG1, 0xa5);
/* restart CLASS D, OCPP/N */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG2, 0xc4);
if (!rk817->use_ext_amplifier) {
/* power on dac ibias/l/r */
snd_soc_write(codec, RK817_CODEC_ADAC_CFG1,
PWD_DACBIAS_ON | PWD_DACD_ON |
PWD_DACL_ON | PWD_DACR_ON);
/* CLASS D mode */
snd_soc_write(codec, RK817_CODEC_DDAC_MUTE_MIXCTL, 0x10);
/* CLASS D enable */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG1, 0xa5);
/* restart CLASS D, OCPP/N */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG2, 0xc4);
} else {
/* HP_CP_EN , CP 2.3V */
snd_soc_write(codec, RK817_CODEC_AHP_CP, 0x11);
/* power on HP two stage opamp ,HP amplitude 0db */
snd_soc_write(codec, RK817_CODEC_AHP_CFG0, 0x80);
/* power on dac ibias/l/r */
snd_soc_write(codec, RK817_CODEC_ADAC_CFG1,
PWD_DACBIAS_ON | PWD_DACD_DOWN |
PWD_DACL_ON | PWD_DACR_ON);
snd_soc_update_bits(codec, RK817_CODEC_DDAC_MUTE_MIXCTL,
DACMT_ENABLE, DACMT_DISABLE);
}
snd_soc_write(codec, RK817_CODEC_DDAC_VOLL, rk817->spk_volume);
snd_soc_write(codec, RK817_CODEC_DDAC_VOLR, rk817->spk_volume);
break;
@@ -511,6 +554,7 @@ static int rk817_playback_path_put(struct snd_kcontrol *kcontrol,
case RING_SPK_HP:
if (pre_path == OFF)
rk817_codec_power_up(codec, RK817_CODEC_PLAYBACK);
/* HP_CP_EN , CP 2.3V */
snd_soc_write(codec, RK817_CODEC_AHP_CP, 0x11);
/* power on HP two stage opamp ,HP amplitude 0db */
@@ -520,12 +564,15 @@ static int rk817_playback_path_put(struct snd_kcontrol *kcontrol,
snd_soc_write(codec, RK817_CODEC_ADAC_CFG1,
PWD_DACBIAS_ON | PWD_DACD_ON |
PWD_DACL_ON | PWD_DACR_ON);
/* CLASS D mode */
snd_soc_write(codec, RK817_CODEC_DDAC_MUTE_MIXCTL, 0x10);
/* CLASS D enable */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG1, 0xa5);
/* restart CLASS D, OCPP/N */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG2, 0xc4);
if (!rk817->use_ext_amplifier) {
/* CLASS D mode */
snd_soc_write(codec, RK817_CODEC_DDAC_MUTE_MIXCTL, 0x10);
/* CLASS D enable */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG1, 0xa5);
/* restart CLASS D, OCPP/N */
snd_soc_write(codec, RK817_CODEC_ACLASSD_CFG2, 0xc4);
}
snd_soc_write(codec, RK817_CODEC_DDAC_VOLL, rk817->hp_volume);
snd_soc_write(codec, RK817_CODEC_DDAC_VOLR, rk817->hp_volume);
@@ -534,6 +581,10 @@ static int rk817_playback_path_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
if (rk817->capture_path != 0 && rk817->pdmdata_out_enable)
snd_soc_update_bits(codec, RK817_CODEC_DI2S_CKM,
PDM_EN_MASK, PDM_EN_ENABLE);
return 0;
}
@@ -584,6 +635,14 @@ static int rk817_capture_path_put(struct snd_kcontrol *kcontrol,
if (pre_path == MIC_OFF)
rk817_codec_power_up(codec, RK817_CODEC_CAPTURE);
if (rk817->adc_for_loopback) {
/* don't need to gain when adc use for loopback */
snd_soc_write(codec, RK817_CODEC_AMIC_CFG0, 0x00);
snd_soc_write(codec, RK817_CODEC_DMIC_PGA_GAIN, 0x66);
snd_soc_write(codec, RK817_CODEC_DADC_VOLL, 0x00);
snd_soc_write(codec, RK817_CODEC_DADC_VOLR, 0x00);
break;
}
if (!rk817->mic_in_differential) {
snd_soc_write(codec, RK817_CODEC_DADC_VOLR, 0xff);
snd_soc_update_bits(codec, RK817_CODEC_AADC_CFG0,
@@ -596,13 +655,21 @@ static int rk817_capture_path_put(struct snd_kcontrol *kcontrol,
if (pre_path == MIC_OFF)
rk817_codec_power_up(codec, RK817_CODEC_CAPTURE);
if (rk817->adc_for_loopback) {
/* don't need to gain when adc use for loopback */
snd_soc_write(codec, RK817_CODEC_AMIC_CFG0, 0x00);
snd_soc_write(codec, RK817_CODEC_DMIC_PGA_GAIN, 0x66);
snd_soc_write(codec, RK817_CODEC_DADC_VOLL, 0x00);
snd_soc_write(codec, RK817_CODEC_DADC_VOLR, 0x00);
break;
}
if (!rk817->mic_in_differential) {
snd_soc_write(codec, RK817_CODEC_DADC_VOLL, 0xff);
snd_soc_update_bits(codec, RK817_CODEC_AADC_CFG0,
ADC_L_PWD_MASK, ADC_L_PWD_EN);
snd_soc_update_bits(codec, RK817_CODEC_AMIC_CFG0,
PWD_PGA_L_MASK, PWD_PGA_L_EN);
}
}
break;
case BT_SCO_MIC:
break;
@@ -692,6 +759,7 @@ static int rk817_hw_params(struct snd_pcm_substream *substream,
static int rk817_digital_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct rk817_codec_priv *rk817 = snd_soc_codec_get_drvdata(codec);
DBG("%s %d\n", __func__, mute);
if (mute)
@@ -701,6 +769,33 @@ static int rk817_digital_mute(struct snd_soc_dai *dai, int mute)
snd_soc_update_bits(codec, RK817_CODEC_DDAC_MUTE_MIXCTL,
DACMT_ENABLE, DACMT_DISABLE);
if (mute) {
rk817_codec_ctl_gpio(rk817, CODEC_SET_SPK, 0);
rk817_codec_ctl_gpio(rk817, CODEC_SET_HP, 0);
} else {
switch (rk817->playback_path) {
case SPK_PATH:
case RING_SPK:
rk817_codec_ctl_gpio(rk817, CODEC_SET_SPK, 1);
rk817_codec_ctl_gpio(rk817, CODEC_SET_HP, 0);
break;
case HP_PATH:
case HP_NO_MIC:
case RING_HP:
case RING_HP_NO_MIC:
rk817_codec_ctl_gpio(rk817, CODEC_SET_SPK, 0);
rk817_codec_ctl_gpio(rk817, CODEC_SET_HP, 1);
break;
case SPK_HP:
case RING_SPK_HP:
rk817_codec_ctl_gpio(rk817, CODEC_SET_SPK, 1);
rk817_codec_ctl_gpio(rk817, CODEC_SET_HP, 1);
break;
default:
break;
}
}
return 0;
}
@@ -750,6 +845,26 @@ static struct snd_soc_dai_driver rk817_dai[] = {
},
.ops = &rk817_dai_ops,
},
{
.name = "rk817-voice",
.id = RK817_VOICE,
.playback = {
.stream_name = "Voice Playback",
.channels_min = 1,
.channels_max = 2,
.rates = RK817_PLAYBACK_RATES,
.formats = RK817_FORMATS,
},
.capture = {
.stream_name = "Voice Capture",
.channels_min = 2,
.channels_max = 8,
.rates = RK817_CAPTURE_RATES,
.formats = RK817_FORMATS,
},
.ops = &rk817_dai_ops,
},
};
static int rk817_suspend(struct snd_soc_codec *codec)
@@ -837,6 +952,38 @@ static int rk817_codec_parse_dt_property(struct device *dev,
return -ENODEV;
}
rk817->hp_ctl_gpio = devm_gpiod_get_optional(dev, "hp-ctl",
GPIOD_OUT_LOW);
if (!IS_ERR_OR_NULL(rk817->hp_ctl_gpio)) {
DBG("%s : hp-ctl-gpio %d\n", __func__,
desc_to_gpio(rk817->hp_ctl_gpio));
}
rk817->spk_ctl_gpio = devm_gpiod_get_optional(dev, "spk-ctl",
GPIOD_OUT_LOW);
if (!IS_ERR_OR_NULL(rk817->spk_ctl_gpio)) {
DBG("%s : spk-ctl-gpio %d\n", __func__,
desc_to_gpio(rk817->spk_ctl_gpio));
}
ret = of_property_read_u32(node, "spk-mute-delay-ms",
&rk817->spk_mute_delay);
if (ret < 0) {
DBG("%s() Can not read property spk-mute-delay-ms\n",
__func__);
rk817->spk_mute_delay = 0;
}
ret = of_property_read_u32(node, "hp-mute-delay-ms",
&rk817->hp_mute_delay);
if (ret < 0) {
DBG("%s() Can not read property hp-mute-delay-ms\n",
__func__);
rk817->hp_mute_delay = 0;
}
DBG("spk mute delay %dms --- hp mute delay %dms\n",
rk817->spk_mute_delay, rk817->hp_mute_delay);
ret = of_property_read_u32(node, "skp-volume", &rk817->spk_volume);
if (ret < 0) {
DBG("%s() Can not read property skp-volume\n", __func__);
@@ -869,6 +1016,12 @@ static int rk817_codec_parse_dt_property(struct device *dev,
rk817->pdmdata_out_enable =
of_property_read_bool(node, "pdmdata-out-enable");
rk817->use_ext_amplifier =
of_property_read_bool(node, "use-ext-amplifier");
rk817->adc_for_loopback =
of_property_read_bool(node, "adc-for-loopback");
return 0;
}