Commit ad45067a authored by Mark Brown's avatar Mark Brown

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
......@@ -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);
/* 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);
/* Switch LOL MUX to audio 3rd DAC */
regmap_write(priv->regmap, MT6359_AUDDEC_ANA_CON7, 0x311b);
/* 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);
/* 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",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment