From 3c3b858c0168ae826525595ef2fb5d275484f989 Mon Sep 17 00:00:00 2001 From: imilka Date: Sat, 10 Nov 2012 22:16:18 +0000 Subject: n7100 support Change-Id: I111e3be9a1c6ea8b68eab5c87fa6c084ba9bb5c3 --- sound/soc/samsung/t0_wm1811.c | 235 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 212 insertions(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/t0_wm1811.c b/sound/soc/samsung/t0_wm1811.c index 9a0ac52..30aa6c1 100644 --- a/sound/soc/samsung/t0_wm1811.c +++ b/sound/soc/samsung/t0_wm1811.c @@ -63,6 +63,11 @@ #define WM1811_MIC_IRQ_NUM (IRQ_BOARD_CODEC_START + WM8994_IRQ_MIC1_DET) #define WM1811_JACKDET_IRQ_NUM (IRQ_BOARD_CODEC_START + WM8994_IRQ_GPIO(6)) +#define MIC_DISABLE 0 +#define MIC_ENABLE 1 +#define MIC_FORCE_DISABLE 2 +#define MIC_FORCE_ENABLE 3 + static struct wm8958_micd_rate t0_det_rates[] = { { MIDAS_DEFAULT_MCLK2, true, 0, 0 }, { MIDAS_DEFAULT_MCLK2, false, 0, 0 }, @@ -82,16 +87,20 @@ const char *aif2_mode_text[] = { "Slave", "Master" }; -static int input_clamp; -const char *input_clamp_text[] = { +const char *switch_mode_text[] = { "Off", "On" }; -static int lineout_mode; -const char *lineout_mode_text[] = { - "Off", "On" +const char *mic_bias_mode_text[] = { + "Disable", "Force Disable", "Enable", "Force Enable" }; +static int input_clamp; +static int lineout_mode; +static int aif2_digital_mute; +static int main_mic_bias_mode; +static int sub_mic_bias_mode; + #ifndef CONFIG_SEC_DEV_JACK /* To support PBA function test */ static struct class *jack_class; @@ -109,8 +118,20 @@ struct wm1811_machine_priv { int (*get_g_det_irq_num_f) (void); }; -static const struct soc_enum lineout_mode_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lineout_mode_text), lineout_mode_text), +static const struct soc_enum switch_mode_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(switch_mode_text), switch_mode_text), +}; + +static const struct soc_enum aif2_mode_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aif2_mode_text), aif2_mode_text), +}; + +static const struct soc_enum mic_bias_mode_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mic_bias_mode_text), mic_bias_mode_text), +}; + +static const struct soc_enum sub_bias_mode_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mic_bias_mode_text), mic_bias_mode_text), }; static int get_lineout_mode(struct snd_kcontrol *kcontrol, @@ -140,17 +161,10 @@ static int set_lineout_mode(struct snd_kcontrol *kcontrol, } dev_info(codec->dev, "set lineout mode : %s\n", - lineout_mode_text[lineout_mode]); + switch_mode_text[lineout_mode]); return 0; } -static const struct soc_enum aif2_mode_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(aif2_mode_text), aif2_mode_text), -}; - -static const struct soc_enum input_clamp_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_clamp_text), input_clamp_text), -}; static int get_aif2_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -194,11 +208,161 @@ static int set_input_clamp(struct snd_kcontrol *kcontrol, snd_soc_update_bits(codec, WM8994_INPUT_MIXER_1, WM8994_INPUTS_CLAMP, 0); } - pr_info("set fm input_clamp : %s\n", input_clamp_text[input_clamp]); + pr_info("set fm input_clamp : %s\n", switch_mode_text[input_clamp]); + + return 0; +} + +static int get_aif2_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = aif2_digital_mute; + return 0; +} +static int set_aif2_mute_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int reg; + + aif2_digital_mute = ucontrol->value.integer.value[0]; + + if (snd_soc_read(codec, WM8994_POWER_MANAGEMENT_6) + & WM8994_AIF2_DACDAT_SRC) + aif2_digital_mute = 0; + + if (aif2_digital_mute) + reg = WM8994_AIF1DAC1_MUTE; + else + reg = 0; + + snd_soc_update_bits(codec, WM8994_AIF2_DAC_FILTERS_1, + WM8994_AIF1DAC1_MUTE, reg); + + pr_info("set aif2_digital_mute : %s\n", + switch_mode_text[aif2_digital_mute]); + + return 0; +} + +static int get_sub_mic_bias_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = sub_mic_bias_mode; return 0; } +static int set_sub_mic_bias_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm1811_machine_priv *wm1811 + = snd_soc_card_get_drvdata(codec->card); + int status = 0; + + status = ucontrol->value.integer.value[0]; + + switch (status) { + case MIC_FORCE_ENABLE: + sub_mic_bias_mode = status; + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_MICB1_ENA, WM8994_MICB1_ENA); + + if (wm1811->set_sub_mic_f) + wm1811->set_main_mic_f(1); + break; + case MIC_ENABLE: + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_MICB1_ENA, WM8994_MICB1_ENA); + if (wm1811->set_sub_mic_f) + wm1811->set_sub_mic_f(1); + if (sub_mic_bias_mode != MIC_FORCE_ENABLE) + msleep(100); + break; + case MIC_FORCE_DISABLE: + sub_mic_bias_mode = status; + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_MICB1_ENA, 0); + + if (wm1811->set_sub_mic_f) + wm1811->set_sub_mic_f(0); + break; + case MIC_DISABLE: + if (sub_mic_bias_mode != MIC_FORCE_ENABLE) { + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_MICB1_ENA, 0); + if (wm1811->set_sub_mic_f) + wm1811->set_sub_mic_f(0); + } else + dev_info(codec->dev, + "SKIP submic disable=%d\n", status); + break; + default: + break; + } + + dev_info(codec->dev, "sub_mic_bias_mod=%d: status=%d\n", + sub_mic_bias_mode, status); + + return 0; + +} + +static int get_main_mic_bias_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = main_mic_bias_mode; + return 0; +} + +static int set_main_mic_bias_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm1811_machine_priv *wm1811 + = snd_soc_card_get_drvdata(codec->card); + int status = 0; + + status = ucontrol->value.integer.value[0]; + + switch (status) { + case MIC_FORCE_ENABLE: + main_mic_bias_mode = status; + + if (wm1811->set_main_mic_f) + wm1811->set_main_mic_f(1); + break; + case MIC_ENABLE: + if (wm1811->set_main_mic_f) + wm1811->set_main_mic_f(1); + if (main_mic_bias_mode != MIC_FORCE_ENABLE) + msleep(100); + break; + case MIC_FORCE_DISABLE: + main_mic_bias_mode = status; + + if (wm1811->set_main_mic_f) + wm1811->set_main_mic_f(0); + break; + case MIC_DISABLE: + if (main_mic_bias_mode != MIC_FORCE_ENABLE) { + if (wm1811->set_main_mic_f) + wm1811->set_main_mic_f(0); + } else + dev_info(codec->dev, + "SKIP mainmic disable=%d\n", status); + break; + default: + break; + } + + dev_info(codec->dev, "main_mic_bias_mod=%d: status=%d\n", + main_mic_bias_mode, status); + + return 0; + +} static int set_ext_micbias(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -320,6 +484,8 @@ static void t0_micdet(u16 status, void *data) struct wm1811_machine_priv *wm1811 = data; struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(wm1811->codec); int report; + int reg; + bool present; /* * If the jack is inserted abnormally, @@ -417,6 +583,22 @@ static void t0_micdet(u16 status, void *data) if (status & WM1811_JACKDET_BTN2) report |= SND_JACK_BTN_2; + reg = snd_soc_read(wm1811->codec, WM1811_JACKDET_CTRL); + if (reg < 0) { + pr_err("%s: Failed to read jack status: %d\n", + __func__, reg); + return; + } + + pr_err("%s: JACKDET %x\n", __func__, reg); + + present = reg & WM1811_JACKDET_LVL; + + if (!present) { + pr_err("%s: button is ignored!!!\n", __func__); + return; + } + dev_info(wm1811->codec->dev, "Detected Button: %08x (%08X)\n", report, status); @@ -639,12 +821,20 @@ static const struct snd_kcontrol_new t0_controls[] = { SOC_ENUM_EXT("AIF2 Mode", aif2_mode_enum[0], get_aif2_mode, set_aif2_mode), - SOC_ENUM_EXT("Input Clamp", input_clamp_enum[0], + SOC_ENUM_EXT("Input Clamp", switch_mode_enum[0], get_input_clamp, set_input_clamp), - SOC_ENUM_EXT("LineoutSwitch Mode", lineout_mode_enum[0], + SOC_ENUM_EXT("LineoutSwitch Mode", switch_mode_enum[0], get_lineout_mode, set_lineout_mode), + SOC_ENUM_EXT("MainMicBias Mode", mic_bias_mode_enum[0], + get_main_mic_bias_mode, set_main_mic_bias_mode), + + SOC_ENUM_EXT("SubMicBias Mode", mic_bias_mode_enum[0], + get_sub_mic_bias_mode, set_sub_mic_bias_mode), + + SOC_ENUM_EXT("AIF2 digital mute", switch_mode_enum[0], + get_aif2_mute_status, set_aif2_mute_status), }; const struct snd_soc_dapm_widget t0_dapm_widgets[] = { @@ -655,8 +845,8 @@ const struct snd_soc_dapm_widget t0_dapm_widgets[] = { SND_SOC_DAPM_LINE("HDMI", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Main Mic", set_ext_micbias), - SND_SOC_DAPM_MIC("Sub Mic", set_ext_submicbias), + SND_SOC_DAPM_MIC("Main Mic", NULL), + SND_SOC_DAPM_MIC("Sub Mic", NULL), SND_SOC_DAPM_LINE("FM In", NULL), SND_SOC_DAPM_INPUT("S5P RP"), @@ -681,9 +871,8 @@ const struct snd_soc_dapm_route t0_dapm_routes[] = { { "IN2LP:VXRN", NULL, "Main Mic" }, { "IN2LN", NULL, "Main Mic" }, - { "IN1RP", NULL, "MICBIAS1" }, - { "IN1RN", NULL, "MICBIAS1" }, - { "MICBIAS1", NULL, "Sub Mic" }, + { "IN1RP", NULL, "Sub Mic" }, + { "IN1RN", NULL, "Sub Mic" }, { "IN1LP", NULL, "MICBIAS2" }, { "MICBIAS2", NULL, "Headset Mic" }, -- cgit v1.1