Unverified Commit ad45067a authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: mt6359: kselftest fix and driver extension

Merge series from Trevor Wu <trevor.wu@mediatek.com>:

The patch series includes a kselftest fix and changes for extending
driver capability to support more use cases.
parents d8b44d8d 104ce27b
Loading
Loading
Loading
Loading
+137 −15
Original line number Diff line number Diff line
@@ -18,6 +18,20 @@

#include "mt6359.h"

static void mt6359_set_gpio_smt(struct mt6359_priv *priv)
{
	/* set gpio SMT mode */
	regmap_update_bits(priv->regmap, MT6359_SMT_CON1, 0x3ff0, 0x3ff0);
}

static void mt6359_set_gpio_driving(struct mt6359_priv *priv)
{
	/* 8:4mA(default), a:8mA, c:12mA, e:16mA */
	regmap_update_bits(priv->regmap, MT6359_DRV_CON2, 0xffff, 0x8888);
	regmap_update_bits(priv->regmap, MT6359_DRV_CON3, 0xffff, 0x8888);
	regmap_update_bits(priv->regmap, MT6359_DRV_CON4, 0x00ff, 0x88);
}

static void mt6359_set_playback_gpio(struct mt6359_priv *priv)
{
	/* set gpio mosi mode, clk / data mosi */
@@ -360,8 +374,34 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
			(struct soc_mixer_control *)kcontrol->private_value;
	unsigned int reg = 0;
	int index = ucontrol->value.integer.value[0];
	int orig_gain[2], new_gain[2];
	int ret;

	switch (mc->reg) {
	case MT6359_ZCD_CON2:
		orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
		orig_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR];
		break;
	case MT6359_ZCD_CON1:
		orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL];
		orig_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR];
		break;
	case MT6359_ZCD_CON3:
		orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL];
		break;
	case MT6359_AUDENC_ANA_CON0:
		orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1];
		break;
	case MT6359_AUDENC_ANA_CON1:
		orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2];
		break;
	case MT6359_AUDENC_ANA_CON2:
		orig_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3];
		break;
	default:
		return -EINVAL;
	}

	ret = snd_soc_put_volsw(kcontrol, ucontrol);
	if (ret < 0)
		return ret;
@@ -373,6 +413,8 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
			(reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
		priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
			(reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
		new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
		new_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR];
		break;
	case MT6359_ZCD_CON1:
		regmap_read(priv->regmap, MT6359_ZCD_CON1, &reg);
@@ -380,35 +422,82 @@ static int mt6359_put_volsw(struct snd_kcontrol *kcontrol,
			(reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK;
		priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] =
			(reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK;
		new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL];
		new_gain[1] = priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR];
		break;
	case MT6359_ZCD_CON3:
		regmap_read(priv->regmap, MT6359_ZCD_CON3, &reg);
		priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL] =
			(reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK;
		new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL];
		break;
	case MT6359_AUDENC_ANA_CON0:
		regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON0, &reg);
		priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] =
			(reg >> RG_AUDPREAMPLGAIN_SFT) & RG_AUDPREAMPLGAIN_MASK;
		new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1];
		break;
	case MT6359_AUDENC_ANA_CON1:
		regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON1, &reg);
		priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] =
			(reg >> RG_AUDPREAMPRGAIN_SFT) & RG_AUDPREAMPRGAIN_MASK;
		new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2];
		break;
	case MT6359_AUDENC_ANA_CON2:
		regmap_read(priv->regmap, MT6359_AUDENC_ANA_CON2, &reg);
		priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3] =
			(reg >> RG_AUDPREAMP3GAIN_SFT) & RG_AUDPREAMP3GAIN_MASK;
		new_gain[0] = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP3];
		break;
	}

	ret = 0;
	if (orig_gain[0] != new_gain[0]) {
		ret = 1;
	} else if (snd_soc_volsw_is_stereo(mc)) {
		if (orig_gain[1] != new_gain[1])
			ret = 1;
	}

	dev_dbg(priv->dev, "%s(), name %s, reg(0x%x) = 0x%x, set index = %x\n",
		__func__, kcontrol->id.name, mc->reg, reg, index);

	return ret;
}

static int mt6359_get_playback_volsw(struct snd_kcontrol *kcontrol,
				     struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *component =
			snd_soc_kcontrol_component(kcontrol);
	struct mt6359_priv *priv = snd_soc_component_get_drvdata(component);
	struct soc_mixer_control *mc =
			(struct soc_mixer_control *)kcontrol->private_value;

	switch (mc->reg) {
	case MT6359_ZCD_CON2:
		ucontrol->value.integer.value[0] =
			priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL];
		ucontrol->value.integer.value[1] =
			priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR];
		break;
	case MT6359_ZCD_CON1:
		ucontrol->value.integer.value[0] =
			priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL];
		ucontrol->value.integer.value[1] =
			priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR];
		break;
	case MT6359_ZCD_CON3:
		ucontrol->value.integer.value[0] =
			priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL];
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

/* MUX */

/* LOL MUX */
@@ -1070,9 +1159,10 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w,
{
	struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
	struct mt6359_priv *priv = snd_soc_component_get_drvdata(cmpnt);
	unsigned int mux = dapm_kcontrol_get_value(w->kcontrols[0]);

	dev_dbg(priv->dev, "%s(), event 0x%x, mux %u\n",
		__func__, event, dapm_kcontrol_get_value(w->kcontrols[0]));
		__func__, event, mux);

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
@@ -1110,14 +1200,29 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w,
		/* Enable AUD_CLK */
		mt6359_set_decoder_clk(priv, true);

		/* Switch LOL MUX to audio DAC */
		if (mux == LO_MUX_L_DAC) {
			if (priv->dev_counter[DEVICE_HP] > 0) {
				dev_info(priv->dev, "%s(), can not enable DAC, hp count %d\n",
					 __func__, priv->dev_counter[DEVICE_HP]);
				break;
			}
			/* Enable DACL and switch HP MUX to open*/
			regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON0, 0x3009);
			/* Disable low-noise mode of DAC */
			regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0xf200);
			usleep_range(100, 120);
			/* Switch LOL MUX to DACL */
			regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x0117);
		} else if (mux == LO_MUX_3RD_DAC) {
			/* Enable Audio DAC (3rd DAC) */
			regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x3113);
			/* Enable low-noise mode of DAC */
			if (priv->dev_counter[DEVICE_HP] == 0)
			regmap_write(priv->regmap,
				     MT6359_AUDDEC_ANA_CON9, 0x0001);
				regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON9, 0x0001);
			/* Switch LOL MUX to audio 3rd DAC */
			regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x311b);
		}
		break;
	case SND_SOC_DAPM_PRE_PMD:
		/* Switch LOL MUX to open */
@@ -1129,6 +1234,15 @@ static int mt_lo_event(struct snd_soc_dapm_widget *w,
		regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0,
				   0x000f, 0x0000);

		if (mux == LO_MUX_L_DAC) {
			/* Disable HP driver core circuits */
			regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0,
					   0x3 << 4, 0x0);
			/* Disable HP driver bias circuits */
			regmap_update_bits(priv->regmap, MT6359_AUDDEC_ANA_CON0,
					   0x3 << 6, 0x0);
		}

		/* Disable AUD_CLK */
		mt6359_set_decoder_clk(priv, false);

@@ -2358,6 +2472,10 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {
	{"MISO2_MUX", "UL2_CH1", "UL2_SRC_MUX"},
	{"MISO2_MUX", "UL2_CH2", "UL2_SRC_MUX"},

	{"MISO0_MUX", NULL, "UL_SRC"},
	{"MISO1_MUX", NULL, "UL_SRC"},
	{"MISO2_MUX", NULL, "UL_SRC_34"},

	{"UL_SRC_MUX", "AMIC", "ADC_L"},
	{"UL_SRC_MUX", "AMIC", "ADC_R"},
	{"UL_SRC_MUX", "DMIC", "DMIC0_MUX"},
@@ -2497,6 +2615,7 @@ static const struct snd_soc_dapm_route mt6359_dapm_routes[] = {

	/* Lineout Path */
	{"LOL Mux", "Playback", "DAC_3RD"},
	{"LOL Mux", "Playback_L_DAC", "DACL"},
	{"LINEOUT L", NULL, "LOL Mux"},

	/* Headphone Path */
@@ -2666,6 +2785,8 @@ static int mt6359_codec_init_reg(struct snd_soc_component *cmpnt)
			   0x1 << RG_AUDLOLSCDISABLE_VAUDP32_SFT);

	/* set gpio */
	mt6359_set_gpio_smt(priv);
	mt6359_set_gpio_driving(priv);
	mt6359_reset_playback_gpio(priv);
	mt6359_reset_capture_gpio(priv);

@@ -2697,22 +2818,23 @@ static void mt6359_codec_remove(struct snd_soc_component *cmpnt)
	cmpnt->regmap = NULL;
}

static const DECLARE_TLV_DB_SCALE(hp_playback_tlv, -2200, 100, 0);
static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0);

static const struct snd_kcontrol_new mt6359_snd_controls[] = {
	/* dl pga gain */
	SOC_DOUBLE_EXT_TLV("Headset Volume",
			   MT6359_ZCD_CON2, 0, 7, 0x1E, 0,
			   snd_soc_get_volsw, mt6359_put_volsw,
			   hp_playback_tlv),
			   MT6359_ZCD_CON2, 0, 7, 0x12, 0,
			   mt6359_get_playback_volsw, mt6359_put_volsw,
			   playback_tlv),
	SOC_DOUBLE_EXT_TLV("Lineout Volume",
			   MT6359_ZCD_CON1, 0, 7, 0x12, 0,
			   snd_soc_get_volsw, mt6359_put_volsw, playback_tlv),
			   mt6359_get_playback_volsw, mt6359_put_volsw,
			   playback_tlv),
	SOC_SINGLE_EXT_TLV("Handset Volume",
			   MT6359_ZCD_CON3, 0, 0x12, 0,
			   snd_soc_get_volsw, mt6359_put_volsw, playback_tlv),
			   mt6359_get_playback_volsw, mt6359_put_volsw,
			   playback_tlv),

	/* ul pga gain */
	SOC_SINGLE_EXT_TLV("PGA1 Volume",