ASoC: msm: add support for MIC-GND swap switch

If the board has a switch to swap the GND and MIC connections for
headset jack, enable the support to flip the switch through gpio
to swap GND and MIC.

CRs-Fixed: 642944
Change-Id: Ifca2c10ef7789925f1c720a79088a376b4a0adcb
Signed-off-by: Simmi Pateriya <simmip@codeaurora.org>
This commit is contained in:
Simmi Pateriya 2014-04-15 12:50:20 +05:30
parent 44e45af813
commit 6380abb455
5 changed files with 110 additions and 4 deletions

View file

@ -504,9 +504,17 @@ normally open.
switch type on target typically the switch type will be normally open or
normally close, value for this property 0 for normally close and 1 for
normally open.
- pinctrl-names : Pincntrl entries to configure the PDM gpio lines accordingly
- pinctrl-0 : This exoplains the active state of the PDM gpio lines
- pinctrl-1 : This exoplains the suspend state of the PDM gpio lines
- pinctrl-names : Pincntrl entries to configure the PDM gpio lines and
cross connection switch gpio accordingly
- pinctrl-0 : This explains the active state of the PDM gpio lines
- pinctrl-1 : This explains the suspend state of the PDM gpio lines
- pinctrl-2 : This explains the active state of the cross connection
gpio lines
- pinctrl-3 : This explains the suspend state of the cross connection
gpio lines
Optional Properties:
- qcom,us-euro-gpios : GPIO on which gnd/mic swap signal is coming.
Example:
@ -517,6 +525,7 @@ Example:
qcom,msm-codec-type = "internal";
qcom,msm-mbhc-hphl-swh = <0>;
qcom,msm-mbhc-gnd-swh = <0>;
qcom,cdc-us-euro-gpios = <&msmgpio 120 0>;
qcom,audio-routing =
"RX_BIAS", "MCLK",
"INT_LDO_H", "MCLK",
@ -527,9 +536,13 @@ Example:
"AMIC2", "MIC BIAS Internal2",
"AMIC3", "MIC BIAS External";
pinctrl-names = "cdc_pdm_lines_act",
"cdc_pdm_lines_sus";
"cdc_pdm_lines_sus",
"cross_conn_det_act",
"cross_conn_det_sus";
pinctrl-0 = <&cdc_pdm_lines_act>;
pinctrl-1 = <&cdc_pdm_lines_sus>;
pinctrl-2 = <&cross_conn_det_act>;
pinctrl-3 = <&cross_conn_det_sus>;
};
* MSM8974 ASoC Machine driver

View file

@ -119,6 +119,7 @@ struct msm8x16_wcd_regulator {
struct msm8916_asoc_mach_data {
int codec_type;
int us_euro_gpio;
atomic_t mclk_rsc_ref;
atomic_t dis_work_mclk;
struct mutex cdc_mclk_mutex;

View file

@ -441,6 +441,7 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
if (!result1 && !(swap_res & 0x04)) {
plug_type = PLUG_TYPE_GND_MIC_SWAP;
pr_debug("%s: Cross connection identified", __func__);
goto eu_us_switch;
} else {
pr_debug("%s: No Cross connection found", __func__);
}
@ -468,6 +469,25 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
goto exit;
}
}
eu_us_switch:
if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
pr_debug("%s: cross connection found\n", __func__);
if (mbhc->mbhc_cfg->swap_gnd_mic) {
pr_debug("%s: US_EU gpio present, flip switch\n",
__func__);
if (mbhc->mbhc_cfg->swap_gnd_mic(codec))
plug_type = PLUG_TYPE_HEADSET;
}
/* Disable micbias and schmitt trigger */
snd_soc_update_bits(codec,
MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
0x6, 0x0);
snd_soc_update_bits(codec,
MSM8X16_WCD_A_ANALOG_MICB_2_EN,
0x80, 0x00);
}
pr_debug("%s: Valid plug found, plug type is %d\n",
__func__, plug_type);
wcd_mbhc_find_plug_and_report(mbhc, plug_type);

View file

@ -31,6 +31,7 @@ struct wcd_mbhc_config {
void *calibration;
bool detect_extn_cable;
bool mono_stero_detection;
bool (*swap_gnd_mic) (struct snd_soc_codec *codec);
};
struct wcd_mbhc_intr {

View file

@ -56,6 +56,7 @@ static struct wcd_mbhc_config mbhc_cfg = {
.calibration = NULL,
.detect_extn_cable = true,
.mono_stero_detection = false,
.swap_gnd_mic = NULL,
};
static struct afe_clk_cfg mi2s_rx_clk = {
@ -82,6 +83,8 @@ struct cdc_pdm_pinctrl_info {
struct pinctrl *pinctrl;
struct pinctrl_state *cdc_pdm_sus;
struct pinctrl_state *cdc_pdm_act;
struct pinctrl_state *cross_conn_det_sus;
struct pinctrl_state *cross_conn_det_act;
};
static struct cdc_pdm_pinctrl_info pinctrl_info;
@ -970,7 +973,29 @@ static int cdc_pdm_get_pinctrl(struct platform_device *pdev)
pr_err("%s: Failed to disable the TLMM pins\n", __func__);
return -EIO;
}
/* get pinctrl handle for cross det pin*/
pinctrl_info.cross_conn_det_sus = pinctrl_lookup_state(pinctrl,
"cross_conn_det_sus");
if (IS_ERR(pinctrl_info.cross_conn_det_sus)) {
pr_err("%s: Unable to get pinctrl disable state handle\n",
__func__);
return -EINVAL;
}
pinctrl_info.cross_conn_det_act = pinctrl_lookup_state(pinctrl,
"cross_conn_det_act");
if (IS_ERR(pinctrl_info.cross_conn_det_act)) {
pr_err("%s: Unable to get pinctrl active state handle\n",
__func__);
return -EINVAL;
}
/* Reset cross conn det pins to default state*/
ret = pinctrl_select_state(pinctrl_info.pinctrl,
pinctrl_info.cross_conn_det_sus);
if (ret != 0) {
pr_err("%s: Failed to disable cross conn det pins\n", __func__);
return -EIO;
}
return 0;
}
@ -998,6 +1023,50 @@ void enable_mclk(struct work_struct *work)
mutex_unlock(&pdata->cdc_mclk_mutex);
}
static bool msm8x16_swap_gnd_mic(struct snd_soc_codec *codec)
{
struct snd_soc_card *card = codec->card;
struct msm8916_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
int value, ret;
if (!gpio_is_valid(pdata->us_euro_gpio)) {
pr_debug("%s: Invalid gpio: %d", __func__, pdata->us_euro_gpio);
return false;
}
ret = pinctrl_select_state(pinctrl_info.pinctrl,
pinctrl_info.cross_conn_det_act);
if (ret < 0) {
pr_err("failed to configure the gpio\n");
return ret;
}
value = gpio_get_value_cansleep(pdata->us_euro_gpio);
gpio_direction_output(pdata->us_euro_gpio, !value);
pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value);
ret = pinctrl_select_state(pinctrl_info.pinctrl,
pinctrl_info.cross_conn_det_sus);
if (ret < 0) {
pr_err("failed to configure the gpio\n");
return ret;
}
return true;
}
static void msm8x16_setup_hs_jack(struct platform_device *pdev,
struct msm8916_asoc_mach_data *pdata)
{
pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node,
"qcom,cdc-us-euro-gpios", 0);
if (pdata->us_euro_gpio < 0) {
dev_dbg(&pdev->dev,
"property %s in node %s not found %d\n",
"qcom,cdc-us-euro-gpios", pdev->dev.of_node->full_name,
pdata->us_euro_gpio);
} else {
mbhc_cfg.swap_gnd_mic = msm8x16_swap_gnd_mic;
}
}
static int msm8x16_asoc_machine_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
@ -1065,6 +1134,8 @@ static int msm8x16_asoc_machine_probe(struct platform_device *pdev)
}
card = &bear_cards[pdev->id];
msm8x16_setup_hs_jack(pdev, pdata);
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, pdata);