Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a65b0bdc authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ASoC: msm8x16-wcd: changes to support compander and HD2"

parents cf206b9b 626c9e9a
Loading
Loading
Loading
Loading
+211 −7
Original line number Diff line number Diff line
@@ -2066,6 +2066,51 @@ static int msm8x16_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
	return 0;
}

static int msm8x16_wcd_hph_mode_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);

	if (msm8x16_wcd->hph_mode == NORMAL_MODE) {
		ucontrol->value.integer.value[0] = 0;
	} else if (msm8x16_wcd->hph_mode == HD2_MODE) {
		ucontrol->value.integer.value[0] = 1;
	} else  {
		dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n",
			__func__, msm8x16_wcd->hph_mode);
	}

	dev_dbg(codec->dev, "%s: msm8x16_wcd->hph_mode = %d\n", __func__,
			msm8x16_wcd->hph_mode);
	return 0;
}

static int msm8x16_wcd_hph_mode_set(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);

	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
		__func__, ucontrol->value.integer.value[0]);

	switch (ucontrol->value.integer.value[0]) {
	case 0:
		msm8x16_wcd->hph_mode = NORMAL_MODE;
		break;
	case 1:
		if (get_codec_version(msm8x16_wcd) >= DIANGU)
			msm8x16_wcd->hph_mode = HD2_MODE;
		break;
	default:
		msm8x16_wcd->hph_mode = NORMAL_MODE;
		break;
	}
	dev_dbg(codec->dev, "%s: msm8x16_wcd->hph_mode_set = %d\n",
		__func__, msm8x16_wcd->hph_mode);
	return 0;
}

static int msm8x16_wcd_boost_option_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
@@ -2362,6 +2407,56 @@ static int msm8x16_wcd_put_iir_band_audio_mixer(
	return 0;
}

static int msm8x16_wcd_compander_get(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
	int comp_idx = ((struct soc_multi_mixer_control *)
					kcontrol->private_value)->reg;
	int rx_idx = ((struct soc_multi_mixer_control *)
					kcontrol->private_value)->shift;

	dev_dbg(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n",
			__func__, comp_idx, rx_idx,
			msm8x16_wcd->comp_enabled[rx_idx]);

	ucontrol->value.integer.value[0] = msm8x16_wcd->comp_enabled[rx_idx];

	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
		__func__, ucontrol->value.integer.value[0]);

	return 0;
}

static int msm8x16_wcd_compander_set(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);
	int comp_idx = ((struct soc_multi_mixer_control *)
					kcontrol->private_value)->reg;
	int rx_idx = ((struct soc_multi_mixer_control *)
					kcontrol->private_value)->shift;
	int value = ucontrol->value.integer.value[0];

	dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
		__func__, ucontrol->value.integer.value[0]);

	if (get_codec_version(msm8x16_wcd) >= DIANGU) {
		if (!value)
			msm8x16_wcd->comp_enabled[rx_idx] = 0;
		else
			msm8x16_wcd->comp_enabled[rx_idx] = comp_idx;
	}

	dev_dbg(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n",
		__func__, comp_idx, rx_idx,
		msm8x16_wcd->comp_enabled[rx_idx]);

	return 0;
}

static const char * const msm8x16_wcd_loopback_mode_ctrl_text[] = {
		"DISABLE", "ENABLE"};
static const struct soc_enum msm8x16_wcd_loopback_mode_ctl_enum[] = {
@@ -2398,6 +2493,13 @@ static const struct soc_enum msm8x16_wcd_ext_spk_boost_ctl_enum[] = {
		SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ext_spk_boost_ctrl_text),
};

static const char * const msm8x16_wcd_hph_mode_ctrl_text[] = {
		"NORMAL", "HD2"};
static const struct soc_enum msm8x16_wcd_hph_mode_ctl_enum[] = {
		SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm8x16_wcd_hph_mode_ctrl_text),
			msm8x16_wcd_hph_mode_ctrl_text),
};

/*cut of frequency for high pass filter*/
static const char * const cf_text[] = {
	"MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
@@ -2420,6 +2522,9 @@ static const struct soc_enum cf_rxmix3_enum =

static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = {

	SOC_ENUM_EXT("RX HPH Mode", msm8x16_wcd_hph_mode_ctl_enum[0],
		msm8x16_wcd_hph_mode_get, msm8x16_wcd_hph_mode_set),

	SOC_ENUM_EXT("Boost Option", msm8x16_wcd_boost_option_ctl_enum[0],
		msm8x16_wcd_boost_option_get, msm8x16_wcd_boost_option_set),

@@ -2556,6 +2661,11 @@ static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = {
	msm8x16_wcd_get_iir_band_audio_mixer,
	msm8x16_wcd_put_iir_band_audio_mixer),

	SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM8X16_WCD_RX1, 1, 0,
	msm8x16_wcd_compander_get, msm8x16_wcd_compander_set),

	SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM8X16_WCD_RX2, 1, 0,
	msm8x16_wcd_compander_get, msm8x16_wcd_compander_set),
};

static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol,
@@ -3707,6 +3817,59 @@ static int msm89xx_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
	return 0;
}

static int msm8x16_wcd_codec_config_compander(struct snd_soc_codec *codec,
					int interp_n, int event)
{
	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);

	dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n",
		__func__, event, interp_n,
		msm8x16_wcd->comp_enabled[interp_n]);

	/* compander is not enabled */
	if (!msm8x16_wcd->comp_enabled[interp_n])
		return 0;

	switch (msm8x16_wcd->comp_enabled[interp_n]) {
	case COMPANDER_1:
		if (SND_SOC_DAPM_EVENT_ON(event)) {
			/* Enable Compander Clock */
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0x0F, 0x09);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL, 0x01, 0x01);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B1_CTL,
				1 << interp_n, 1 << interp_n);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B3_CTL, 0xFF, 0x01);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0xF0, 0x50);
			/* add sleep for compander to settle */
			usleep_range(1000, 1100);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B3_CTL, 0xFF, 0x28);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0xF0, 0xB0);
		} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0x0F, 0x05);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_COMP0_B1_CTL,
				1 << interp_n, 0);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL, 0x01, 0x00);
		}
		break;
	default:
		dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__,
				msm8x16_wcd->comp_enabled[interp_n]);
		break;
	};

	return 0;
}

static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
						 struct snd_kcontrol *kcontrol,
						 int event)
@@ -3718,6 +3881,7 @@ static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		msm8x16_wcd_codec_config_compander(codec, w->shift, event);
		/* apply the digital gain after the interpolator is enabled*/
		if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
			snd_soc_write(codec,
@@ -3727,6 +3891,7 @@ static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
				  );
		break;
	case SND_SOC_DAPM_POST_PMD:
		msm8x16_wcd_codec_config_compander(codec, w->shift, event);
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL,
			1 << w->shift, 1 << w->shift);
@@ -3933,6 +4098,14 @@ static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w,
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN,
				0x08, 0x00);
		if (HD2_MODE == msm8x16_wcd->hph_mode) {
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x1C, 0x14);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX1_B4_CTL, 0x18, 0x10);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x80, 0x80);
		}
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02);
		snd_soc_update_bits(codec,
@@ -3955,6 +4128,14 @@ static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w,
			MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00);
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00);
		if (HD2_MODE == msm8x16_wcd->hph_mode) {
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x1C, 0x00);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX1_B4_CTL, 0x18, 0xFF);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x80, 0x00);
		}
		break;
	}
	return 0;
@@ -3979,8 +4160,6 @@ static int msm8x16_wcd_lo_dac_event(struct snd_soc_dapm_widget *w,
			MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08);
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40);
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC, 0xff, 0x98);
		break;
	case SND_SOC_DAPM_POST_PMU:
		snd_soc_update_bits(codec,
@@ -3989,8 +4168,6 @@ static int msm8x16_wcd_lo_dac_event(struct snd_soc_dapm_widget *w,
			MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00);
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_RX_LO_EN_CTL, 0x40, 0x40);
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC, 0xff, 0x98);
		break;
	case SND_SOC_DAPM_POST_PMD:
		usleep_range(20000, 20100);
@@ -4017,11 +4194,20 @@ static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{
	struct snd_soc_codec *codec = w->codec;
	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);

	dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		if (HD2_MODE == msm8x16_wcd->hph_mode) {
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x1C, 0x14);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX2_B4_CTL, 0x18, 0x10);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x80, 0x80);
		}
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02);
		snd_soc_update_bits(codec,
@@ -4038,6 +4224,14 @@ static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
			MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00);
		snd_soc_update_bits(codec,
			MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00);
		if (HD2_MODE == msm8x16_wcd->hph_mode) {
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x1C, 0x00);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX2_B4_CTL, 0x18, 0xFF);
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x80, 0x00);
		}
		break;
	}
	return 0;
@@ -4816,15 +5010,15 @@ static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = {
	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),

	SND_SOC_DAPM_MIXER_E("RX1 MIX2",
		MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
		MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX1, 0, NULL,
		0, msm8x16_wcd_codec_enable_interpolator,
		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
	SND_SOC_DAPM_MIXER_E("RX2 MIX2",
		MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
		MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX2, 0, NULL,
		0, msm8x16_wcd_codec_enable_interpolator,
		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
	SND_SOC_DAPM_MIXER_E("RX3 MIX1",
		MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
		MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX3, 0, NULL,
		0, msm8x16_wcd_codec_enable_interpolator,
		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),

@@ -5185,6 +5379,7 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec)
	struct msm8916_asoc_mach_data *pdata = NULL;
	struct msm8x16_wcd_priv *msm8x16_wcd_priv =
		snd_soc_codec_get_drvdata(codec);
	int i;

	pdata = snd_soc_card_get_drvdata(codec->component.card);
	dev_dbg(codec->dev, "%s: device down!\n", __func__);
@@ -5231,6 +5426,10 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec)
		}
	}
	msm8x16_wcd_boost_off(codec);
	msm8x16_wcd_priv->hph_mode = NORMAL_MODE;
	for (i = 0; i < MSM8X16_WCD_RX_MAX; i++)
		msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE;

	/* 40ms to allow boost to discharge */
	msleep(40);
	/* Disable PA to avoid pop during codec bring up */
@@ -5507,6 +5706,11 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec)
	 * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen.
	 */
	msm8x16_wcd_priv->boost_option = BOOST_SWITCH;
	msm8x16_wcd_priv->hph_mode = NORMAL_MODE;

	for (i = 0; i < MSM8X16_WCD_RX_MAX; i++)
		msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE;

	msm8x16_wcd_dt_parse_boost_info(codec);
	msm8x16_wcd_set_boost_v(codec);

+16 −0
Original line number Diff line number Diff line
@@ -71,6 +71,18 @@ enum codec_versions {
	UNSUPPORTED,
};

/* Support different hph modes */
enum {
	NORMAL_MODE = 0,
	HD2_MODE,
};

/* Codec supports 1 compander */
enum {
	COMPANDER_NONE = 0,
	COMPANDER_1, /* HPHL/R */
	COMPANDER_MAX,
};

enum wcd_curr_ref {
	I_h4_UA = 0,
@@ -287,6 +299,10 @@ struct msm8x16_wcd_priv {
	bool clock_active;
	bool config_mode_active;
	u16 boost_option;
	/* mode to select hd2 */
	u32 hph_mode;
	/* compander used for each rx chain */
	u32 comp_enabled[MSM8X16_WCD_RX_MAX];
	bool spk_boost_set;
	bool ear_pa_boost_set;
	bool ext_spk_boost_set;
+21 −1
Original line number Diff line number Diff line
 /* Copyright (c) 2015, The Linux Foundation. All rights reserved.
 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -350,6 +350,8 @@
#define MSM8X16_WCD_A_CDC_CLK_SD_CTL__POR				(0x00)
#define MSM8X16_WCD_A_CDC_CLK_WSA_VI_B1_CTL		(0x230)
#define MSM8X16_WCD_A_CDC_CLK_WSA_VI_B1_CTL__POR			(0x00)
#define MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL			(0x234)
#define MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL__POR				(0x00)
#define MSM8X16_WCD_A_CDC_RX1_B1_CTL			(0x240)
#define MSM8X16_WCD_A_CDC_RX1_B1_CTL__POR				(0x00)
#define MSM8X16_WCD_A_CDC_RX2_B1_CTL			(0x260)
@@ -402,6 +404,24 @@
#define MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE__POR				(0x00)
#define MSM8X16_WCD_A_CDC_TOP_CTL				(0x2A4)
#define MSM8X16_WCD_A_CDC_TOP_CTL__POR					(0x01)
#define MSM8X16_WCD_A_CDC_COMP0_B1_CTL				(0x2B0)
#define MSM8X16_WCD_A_CDC_COMP0_B1_CTL__POR				(0x30)
#define MSM8X16_WCD_A_CDC_COMP0_B2_CTL				(0x2B4)
#define MSM8X16_WCD_A_CDC_COMP0_B2_CTL__POR				(0xB5)
#define MSM8X16_WCD_A_CDC_COMP0_B3_CTL				(0x2B8)
#define MSM8X16_WCD_A_CDC_COMP0_B3_CTL__POR				(0x28)
#define MSM8X16_WCD_A_CDC_COMP0_B4_CTL				(0x2BC)
#define MSM8X16_WCD_A_CDC_COMP0_B4_CTL__POR				(0x37)
#define MSM8X16_WCD_A_CDC_COMP0_B5_CTL				(0x2C0)
#define MSM8X16_WCD_A_CDC_COMP0_B5_CTL__POR				(0x7F)
#define MSM8X16_WCD_A_CDC_COMP0_B6_CTL				(0x2C4)
#define MSM8X16_WCD_A_CDC_COMP0_B6_CTL__POR				(0x00)
#define MSM8X16_WCD_A_CDC_COMP0_SHUT_DOWN_STATUS		(0x2C8)
#define MSM8X16_WCD_A_CDC_COMP0_SHUT_DOWN_STATUS__POR			(0x03)
#define MSM8X16_WCD_A_CDC_COMP0_FS_CFG				(0x2CC)
#define MSM8X16_WCD_A_CDC_COMP0_FS_CFG__POR				(0x03)
#define MSM8X16_WCD_A_CDC_COMP0_DELAY_BUF_CTL			(0x2D0)
#define MSM8X16_WCD_A_CDC_COMP0_DELAY_BUF_CTL__POR			(0x02)
#define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL			(0x2E0)
#define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL__POR				(0x00)
#define MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL			(0x2E4)