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

Commit 0d006333 authored by Meng Wang's avatar Meng Wang Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: msm8939: changes to connect external speaker to HPH



Add widgets to provide a switch that connect external speaker
PA to HPH left or right. Enable the external PA GPIO in the
dapm power up sequence when this switch connects external PA
to HPH left or right.

Change-Id: Ic3b430628a4cc15c8a5ac35d9f5335f6b97a2423
Signed-off-by: default avatarMeng Wang <mwang@codeaurora.org>
parent dd905e67
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -598,6 +598,7 @@ Optional Properties:
capacitor mode.
- qcom,msm-micbias2-ext-cap : Boolean. Enable micbias2 external
capacitor mode.
- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa.

Example:

@@ -612,6 +613,7 @@ Example:
		qcom,msm-mbhc-gnd-swh = <0>;
		qcom,msm-hs-micbias-type = "internal";
		qcom,cdc-us-euro-gpios = <&msmgpio 120 0>;
		qcom,msm-spk-ext-pa = <&msm_gpio 0 0>;
		qcom,audio-routing =
			"RX_BIAS", "MCLK",
			"INT_LDO_H", "MCLK",
+53 −0
Original line number Diff line number Diff line
@@ -196,6 +196,16 @@ static void *modem_state_notifier;

static struct snd_soc_codec *registered_codec;

void msm8x16_wcd_spk_ext_pa_cb(
		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
			int enable), struct snd_soc_codec *codec)
{
	struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec);

	pr_debug("%s: Enter\n", __func__);
	msm8x16_wcd->codec_spk_ext_pa_cb = codec_spk_ext_pa;
}

static void msm8x16_wcd_compute_impedance(s16 l, s16 r, uint32_t *zl,
				uint32_t *zr, bool high)
{
@@ -1522,6 +1532,10 @@ static const char * const adc2_mux_text[] = {
	"ZERO", "INP2", "INP3"
};

static const char * const ext_spk_text[] = {
	"Off", "On"
};

static const char * const rdac2_mux_text[] = {
	"ZERO", "RX2", "RX1"
};
@@ -1533,6 +1547,9 @@ static const char * const iir_inp1_text[] = {
static const struct soc_enum adc2_enum =
	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adc2_mux_text), adc2_mux_text);

static const struct soc_enum ext_spk_enum =
	SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(ext_spk_text), ext_spk_text);

/* RX1 MIX1 */
static const struct soc_enum rx_mix1_inp1_chain_enum =
	SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_RX1_B1_CTL,
@@ -1603,6 +1620,9 @@ static const struct soc_enum iir2_inp1_mux_enum =
	SOC_ENUM_SINGLE(MSM8X16_WCD_A_CDC_CONN_EQ2_B1_CTL,
		0, 6, iir_inp1_text);

static const struct snd_kcontrol_new ext_spk_mux =
	SOC_DAPM_ENUM_VIRT("Ext Spk Switch Mux", ext_spk_enum);

static const struct snd_kcontrol_new rx_mix1_inp1_mux =
	SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);

@@ -2773,6 +2793,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
	{"HEADPHONE", NULL, "HPHL PA"},
	{"HEADPHONE", NULL, "HPHR PA"},

	{"Ext Spk", NULL, "Ext Spk Switch"},
	{"Ext Spk Switch", "On", "HPHL PA"},
	{"Ext Spk Switch", "On", "HPHR PA"},

	{"HPHL PA", NULL, "HPHL"},
	{"HPHR PA", NULL, "HPHR"},
	{"HPHL", "Switch", "HPHL DAC"},
@@ -3207,6 +3231,30 @@ static int msm8x16_wcd_codec_enable_rx_chain(struct snd_soc_dapm_widget *w,
	return 0;
}

static int msm8x16_wcd_codec_enable_spk_ext_pa(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 event = %d\n", __func__, w->name, event);
	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		dev_dbg(w->codec->dev,
			"%s: enable external speaker PA\n", __func__);
		if (msm8x16_wcd->codec_spk_ext_pa_cb)
			msm8x16_wcd->codec_spk_ext_pa_cb(codec, 1);
		break;
	case SND_SOC_DAPM_PRE_PMD:
		dev_dbg(w->codec->dev,
			"%s: enable external speaker PA\n", __func__);
		if (msm8x16_wcd->codec_spk_ext_pa_cb)
			msm8x16_wcd->codec_spk_ext_pa_cb(codec, 0);
		break;
	}
	return 0;
}

static int msm8x16_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
	struct snd_kcontrol *kcontrol, int event)
{
@@ -3280,6 +3328,8 @@ static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = {

	SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),

	SND_SOC_DAPM_SPK("Ext Spk", msm8x16_wcd_codec_enable_spk_ext_pa),

	SND_SOC_DAPM_OUTPUT("HEADPHONE"),
	SND_SOC_DAPM_PGA_E("HPHL PA", MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN,
		5, 0, NULL, 0,
@@ -3326,6 +3376,9 @@ static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = {
			    msm89xx_wcd_codec_enable_vdd_spkr,
			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),

	SND_SOC_DAPM_VIRT_MUX("Ext Spk Switch", SND_SOC_NOPM, 0, 0,
		&ext_spk_mux),

	SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
	SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),

+6 −1
Original line number Diff line number Diff line
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2015, 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
@@ -160,6 +160,7 @@ struct msm8916_asoc_mach_data {
	int codec_type;
	int ext_pa;
	int us_euro_gpio;
	int spk_ext_pa_gpio;
	int mclk_freq;
	int lb_mode;
	u8 micbias1_cap_mode;
@@ -238,6 +239,7 @@ struct msm8x16_wcd_priv {
	/* cal info for codec */
	struct fw_info *fw_data;
	struct blocking_notifier_head notifier;
	int (*codec_spk_ext_pa_cb)(struct snd_soc_codec *codec, int enable);

};

@@ -255,5 +257,8 @@ extern int msm8x16_register_notifier(struct snd_soc_codec *codec,
extern int msm8x16_unregister_notifier(struct snd_soc_codec *codec,
				     struct notifier_block *nblock);

extern void msm8x16_wcd_spk_ext_pa_cb(
		int (*codec_spk_ext_pa)(struct snd_soc_codec *codec,
		int enable), struct snd_soc_codec *codec);
#endif
+36 −2
Original line number Diff line number Diff line
 /* Copyright (c) 2014, The Linux Foundation. All rights reserved.
 /* Copyright (c) 2014-2015, 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
@@ -276,6 +276,24 @@ static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
	return 0;
}

static int enable_spk_ext_pa(struct snd_soc_codec *codec, int enable)
{
	struct snd_soc_card *card = codec->card;
	struct msm8916_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);

	if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) {
		pr_err("%s: Invalid gpio: %d\n", __func__,
			pdata->spk_ext_pa_gpio);
		return false;
	}

	pr_debug("%s: %s external speaker PA\n", __func__,
		enable ? "Enable" : "Disable");
	gpio_set_value_cansleep(pdata->spk_ext_pa_gpio, enable);

	return 0;
}

static int msm_pri_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
				struct snd_pcm_hw_params *params)
{
@@ -1375,6 +1393,8 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)

	snd_soc_dapm_sync(dapm);

	msm8x16_wcd_spk_ext_pa_cb(enable_spk_ext_pa, codec);

	mbhc_cfg.calibration = def_msm8x16_wcd_mbhc_cal();
	if (mbhc_cfg.calibration) {
		ret = msm8x16_wcd_hs_detect(codec, &mbhc_cfg);
@@ -2491,6 +2511,7 @@ static int msm8x16_asoc_machine_probe(struct platform_device *pdev)
	const char *hs_micbias_type = "qcom,msm-hs-micbias-type";
	const char *ext_pa = "qcom,msm-ext-pa";
	const char *mclk = "qcom,msm-mclk-freq";
	const char *spk_ext_pa = "qcom,msm-spk-ext-pa";
	const char *ptr = NULL;
	const char *type = NULL;
	const char *ext_pa_str = NULL;
@@ -2548,11 +2569,24 @@ static int msm8x16_asoc_machine_probe(struct platform_device *pdev)
	ret = of_property_read_u32(pdev->dev.of_node, mclk, &id);
	if (ret) {
		dev_err(&pdev->dev,
			"%s: missing %s in dt node\n", __func__, card_dev_id);
			"%s: missing %s in dt node\n", __func__, mclk);
		id = DEFAULT_MCLK_RATE;
	}
	pdata->mclk_freq = id;

	pdata->spk_ext_pa_gpio = of_get_named_gpio(pdev->dev.of_node,
				spk_ext_pa, 0);
	if (pdata->spk_ext_pa_gpio < 0) {
		dev_dbg(&pdev->dev,
			"%s: missing %s in dt node\n", __func__, spk_ext_pa);
	} else {
		if (!gpio_is_valid(pdata->spk_ext_pa_gpio)) {
			pr_err("%s: Invalid external speaker gpio: %d",
				__func__, pdata->spk_ext_pa_gpio);
			return -EINVAL;
		}
	}

	ret = of_property_read_string(pdev->dev.of_node, codec_type, &ptr);
	if (ret) {
		dev_err(&pdev->dev,