diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/wm8994_herring.c | 2629 | ||||
-rwxr-xr-x | sound/soc/codecs/wm8994_samsung.c | 1528 | ||||
-rwxr-xr-x | sound/soc/codecs/wm8994_samsung.h | 119 | ||||
-rw-r--r-- | sound/soc/samsung/herring-wm8994.c | 2 |
4 files changed, 2799 insertions, 1479 deletions
diff --git a/sound/soc/codecs/wm8994_herring.c b/sound/soc/codecs/wm8994_herring.c index 10be23c..73ef22d 100644 --- a/sound/soc/codecs/wm8994_herring.c +++ b/sound/soc/codecs/wm8994_herring.c @@ -1,5 +1,5 @@ /* - * wm8994_aries.c -- WM8994 ALSA Soc Audio driver related Aries + * wm8994_crespo.c -- WM8994 ALSA Soc Audio driver related Aries * * Copyright (C) 2010 Samsung Electronics. * @@ -15,11 +15,11 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/clk.h> #include <plat/gpio-cfg.h> #include <plat/map-base.h> #include <mach/regs-clock.h> -#include <mach/gpio-crespo.h> -#include "wm8994.h" +#include "wm8994_samsung.h" /* * Debug Feature @@ -36,244 +36,141 @@ /* DAC */ #define TUNING_DAC1L_VOL 0xC0 /* 610h */ #define TUNING_DAC1R_VOL 0xC0 /* 611h */ +#define TUNING_DAC2L_VOL 0xC0 /* 612h */ +#define TUNING_DAC2R_VOL 0xC0 /* 613h */ /* Speaker */ #define TUNING_SPKMIXL_ATTEN 0x0 /* 22h */ #define TUNING_SPKMIXR_ATTEN 0x0 /* 23h */ -#define TUNING_MP3_SPKL_VOL 0x3E /* 26h */ -#define TUNING_MP3_CLASSD_VOL 0x5 /* 25h */ - -#define TUNING_FMRADIO_SPKL_VOL 0x3E /* 26h */ -#define TUNING_FMRADIO_CLASSD_VOL 0x5 /* 25h */ +/* Headset */ +#define TUNING_EAR_OUTMIX5_VOL 0x0 /* 31h */ +#define TUNING_EAR_OUTMIX6_VOL 0x0 /* 32h */ -#define TUNING_CALL_SPKL_VOL 0x3E /* 26h */ -#define TUNING_CALL_CLASSD_VOL 0x7 /* 25h */ +/* + * Normal + */ +/* Speaker */ +#define TUNING_MP3_SPKL_VOL 0x3E /*26h */ +#define TUNING_MP3_CLASSD_VOL 0x5 /* 25h */ /* Headset */ -#define TUNING_EAR_OUTMIX5_VOL 0x0 /* 31h */ -#define TUNING_EAR_OUTMIX6_VOL 0x0 /* 32h */ - -#define TUNING_MP3_OUTPUTL_VOL 0x34 /* 1Ch */ -#define TUNING_MP3_OUTPUTR_VOL 0x34 /* 1Dh */ -#define TUNING_MP3_OPGAL_VOL 0x39 /* 20h */ -#define TUNING_MP3_OPGAR_VOL 0x39 /* 21h */ +#define TUNING_MP3_OUTPUTL_VOL 0x2F /* 1Ch */ +#define TUNING_MP3_OUTPUTR_VOL 0x2F /* 1Dh */ +#define TUNING_MP3_OPGAL_VOL 0x39 /* 20h */ +#define TUNING_MP3_OPGAR_VOL 0x39 /* 21h */ -#define TUNING_CALL_OUTPUTL_VOL 0x39 /* 1Ch */ -#define TUNING_CALL_OUTPUTR_VOL 0x39 /* 1Dh */ -#define TUNING_CALL_OPGAL_VOL 0x39 /* 20h */ -#define TUNING_CALL_OPGAR_VOL 0x39 /* 21h */ +/* Speaker_Headset */ +#define TUNING_MP3_DUAL_OUTPUTL_VOL 0x1E /* 1Ch */ +#define TUNING_MP3_DUAL_OUTPUTR_VOL 0x1E /* 1Dh */ -#define TUNING_FMRADIO_OUTPUTL_VOL 0x38 /* 1Ch */ -#define TUNING_FMRADIO_OUTPUTR_VOL 0x38 /* 1Dh */ -#define TUNING_FMRADIO_OPGAL_VOL 0x39 /* 20h */ -#define TUNING_FMRADIO_OPGAR_VOL 0x39 /* 21h */ +/* + * Ringtone + */ +/* Speaker */ +#define TUNING_RING_SPKL_VOL 0x3E /* 26h */ +#define TUNING_RING_CLASSD_VOL 0x5 /* 25h */ -#define TUNING_HPOUTMIX_VOL 0x0 +/* Headset */ +#define TUNING_RING_OUTPUTL_VOL 0x34 /* 1Ch */ +#define TUNING_RING_OUTPUTR_VOL 0x34 /* 1Dh */ +#define TUNING_RING_OPGAL_VOL 0x39 /* 20h */ +#define TUNING_RING_OPGAR_VOL 0x39 /* 21h */ /* Dual */ -#define TUNING_DUAL_OUTPUTL_VOL 0x1E /* 1Ch */ -#define TUNING_DUAL_OUTPUTR_VOL 0x1E /* 1Dh */ +#define TUNING_RING_DUAL_OUTPUTL_VOL 0x1E /* 1Ch */ +#define TUNING_RING_DUAL_OUTPUTR_VOL 0x1E /* 1Dh */ /* - * Recording + * Call */ -/* Main MIC */ -#define TUNING_RECORD_MAIN_INPUTLINE_VOL 0x18 /* 18h */ +/* Speaker */ +#define TUNING_CALL_SPKL_VOL 0x35 /* 26h */ +#define TUNING_CALL_CLASSD_VOL 0x7 /* 25h */ -/* Ear MIC */ -#define TUNING_RECORD_SUB_INPUTMIX_VOL 0x17 /* 1Ah */ +/* Headset */ +#define TUNING_CALL_OUTPUTL_VOL 0x30 /* 1Ch */ +#define TUNING_CALL_OUTPUTR_VOL 0x30 /* 1Dh */ +#define TUNING_CALL_OPGAL_VOL 0x39 /* 20h */ +#define TUNING_CALL_OPGAR_VOL 0x39 /* 21h */ -/* Call Main MIC */ -#define TUNING_CALL_RCV_INPUTMIX_VOL 0x16 /* 18h */ -#define TUNING_CALL_SPK_INPUTMIX_VOL 0x17 /* 18h */ +/* Receiver */ +#define TUNING_RCV_OUTMIX5_VOL 0x0 /* 31h */ +#define TUNING_RCV_OUTMIX6_VOL 0x0 /* 32h */ +#define TUNING_RCV_OPGAL_VOL 0x3F /* 20h */ +#define TUNING_RCV_OPGAR_VOL 0x3F /* 21h */ +#define TUNING_HPOUT2_VOL 0x0 /* 1Fh */ -/* Ear MIC */ -#define TUNING_CALL_EAR_INPUTMIX_VOL 0x1F /* 1Ah */ +/* Call Main MIC */ +#define TUNING_CALL_RCV_INPUTMIX_VOL 0x17 /* 18h */ +#define TUNING_CALL_RCV_MIXER_VOL WM8994_IN1L_MIXINL_VOL /* 29h */ -/* Receiver */ -#define TUNING_RCV_OUTMIX5_VOL 0x0 /* 31h */ -#define TUNING_RCV_OUTMIX6_VOL 0x0 /* 32h */ -#define TUNING_RCV_OPGAL_VOL 0x3D /* 20h */ -#define TUNING_RCV_OPGAR_VOL 0x3D /* 21h */ -#define TUNING_HPOUT2_VOL 0x0 /* 1Fh */ +#define TUNING_CALL_SPK_INPUTMIX_VOL 0x11 /* 18h */ +#define TUNING_CALL_SPK_MIXER_VOL WM8994_IN1L_MIXINL_VOL /* 29h */ -int audio_init(void) -{ +/* Call Ear MIC */ +#define TUNING_CALL_EAR_INPUTMIX_VOL 0x1D /* 1Ah */ - /* CODEC LDO SETTING */ - if (gpio_is_valid(GPIO_CODEC_LDO_EN)) { - if (gpio_request(GPIO_CODEC_LDO_EN, "CODEC_LDO_EN")) - DEBUG_LOG_ERR("Failed to request CODEC_LDO_EN!\n"); - gpio_direction_output(GPIO_CODEC_LDO_EN, 0); - } +/*Input */ +#define TUNING_DAC1L_RADIO_VOL 0xA8 /* 402h */ +#define TUNING_DAC1R_RADIO_VOL 0xA8 /* 403h */ - s3c_gpio_setpull(GPIO_CODEC_LDO_EN, S3C_GPIO_PULL_NONE); +/* Dual */ +#define TUNING_DUAL_DAC1L_RADIO_VOL 0x70 /* 402h */ +#define TUNING_DUAL_DAC1R_RADIO_VOL 0x70 /* 403h */ - /* CODEC XTAL CLK SETTING */ -#if (defined CONFIG_JUPITER_VER_B5) || (defined CONFIG_ARIES_VER_B0) || \ - (defined CONFIG_MACH_S5PC110_ARIES) - if (gpio_is_valid(GPIO_CODEC_XTAL_EN)) { - if (gpio_request(GPIO_CODEC_XTAL_EN, "GPIO_CODEC_XTAL_EN")) - DEBUG_LOG_ERR - ("Failed to request GPIO_CODEC_XTAL_EN!\n"); +/* + * Recording + */ +/* Main MIC */ +#define TUNING_RECORD_MAIN_INPUTLINE_VOL 0x18 /* 18h */ +#define TUNING_RECORD_MAIN_AIF1ADCL_VOL 0xC0 /* 400h */ +#define TUNING_RECORD_MAIN_AIF1ADCR_VOL 0xC0 /* 401h */ - gpio_direction_output(GPIO_CODEC_XTAL_EN, 0); - } - s3c_gpio_setpull(GPIO_CODEC_XTAL_EN, S3C_GPIO_PULL_NONE); -#endif - if (gpio_is_valid(GPIO_MICBIAS_EN)) { - if (gpio_request(GPIO_MICBIAS_EN, "GPJ4")) - pr_err("Failed to request GPIO_MICBIAS_EN!\n"); - gpio_direction_output(GPIO_MICBIAS_EN, 0); - } - s3c_gpio_setpull(GPIO_MICBIAS_EN, S3C_GPIO_PULL_NONE); - - /* For preserving output of codec related pins. */ - s3c_gpio_slp_cfgpin(GPIO_CODEC_LDO_EN, S3C_GPIO_SLP_PREV); - s3c_gpio_slp_setpull_updown(GPIO_CODEC_LDO_EN, S3C_GPIO_PULL_NONE); - s3c_gpio_slp_cfgpin(GPIO_MICBIAS_EN, S3C_GPIO_SLP_PREV); - s3c_gpio_slp_setpull_updown(GPIO_MICBIAS_EN, S3C_GPIO_PULL_NONE); - /* PCM_SEL Setting */ -#if (defined CONFIG_JUPITER_VER_B5) || (defined CONFIG_ARIES_VER_B0) || \ - (defined CONFIG_ARIES_VER_B1) || (defined CONFIG_MACH_S5PC110_ARIES) - s3c_gpio_slp_cfgpin(GPIO_EARPATH_SEL, S3C_GPIO_SLP_PREV); - s3c_gpio_slp_setpull_updown(GPIO_EARPATH_SEL, S3C_GPIO_PULL_NONE); -#endif - -#if (defined CONFIG_JUPITER_VER_B5) || (defined CONFIG_ARIES_VER_B0) || \ - (defined CONFIG_MACH_S5PC110_ARIES) - s3c_gpio_slp_setpull_updown(GPIO_CODEC_XTAL_EN, S3C_GPIO_PULL_NONE); -#endif +#define TUNING_RECOGNITION_MAIN_INPUTLINE_VOL 0x1C /* 18h */ +#define TUNING_RECOGNITION_MAIN_AIF1ADCL_VOL 0xD0 /* 400h */ +#define TUNING_RECOGNITION_MAIN_AIF1ADCR_VOL 0xD0 /* 401h */ - return 0; +/* Ear MIC */ +#define TUNING_RECORD_SUB_INPUTMIX_VOL 0x15 /* 1Ah */ +#define TUNING_RECORD_SUB_AIF1ADCL_VOL 0xC0 /* 400h */ +#define TUNING_RECORD_SUB_AIF1ADCR_VOL 0xC0 /* 401h */ -} +#define TUNING_RECOGNITION_SUB_INPUTMIX_VOL 0x10 /* 1Ah */ +#define TUNING_RECOGNITION_SUB_AIF1ADCL_VOL 0xC0 /* 400h */ +#define TUNING_RECOGNITION_SUB_AIF1ADCR_VOL 0xC0 /* 401h */ -int audio_power(int en) +/* S5P_SLEEP_CONFIG must be controlled by codec if codec use XUSBTI */ +int wm8994_configure_clock(struct snd_soc_codec *codec, int en) { -#if (defined CONFIG_JUPITER_VER_B4) - u32 val; - - DEBUG_LOG("LDO Enable = %d, XTAL CLK From AP EMUL", en); - val = __raw_readl(S5P_CLK_OUT); - val &= 0xFFFE0FFF; -#endif + struct wm8994_priv *wm8994 = codec->drvdata; if (en) { - /* Turn on LDO for codec.*/ - gpio_set_value(GPIO_CODEC_LDO_EN, 1); - - /* wait for warming up */ - /* commenting sleep as not required in SLSI platform */ - /* msleep(10);*/ - - /* Turn on master clock.*/ -#if (defined CONFIG_JUPITER_VER_B5) || (defined CONFIG_ARIES_VER_B0) || \ - (defined CONFIG_ARIES_VER_B1) || \ - (defined CONFIG_ARIES_VER_B2) || \ - (defined CONFIG_ARIES_VER_B3) || \ - (defined CONFIG_MACH_S5PC110_P1) || \ - (defined CONFIG_MACH_S5PC110_ARIES) || \ - (defined CONFIG_MACH_S5PC110_CRESPO) - DEBUG_LOG("LDO Enable = %d, XTAL CLK From OSI", en); -#ifdef CONFIG_MACH_S5PC110_ARIES - gpio_set_value(GPIO_CODEC_XTAL_EN, 1); -#if (defined CONFIG_SND_S5P_WM8994_MASTER) - else - __raw_writel(__raw_readl(S5P_OTHERS) | (3 << 8), - S5P_OTHERS); -#endif -#else -#if (defined CONFIG_SND_S5P_WM8994_MASTER) - __raw_writel(__raw_readl(S5P_OTHERS) | (3 << 8), S5P_OTHERS); -#endif -#endif -#elif (defined CONFIG_JUPITER_VER_B4) -#ifdef CONFIG_SND_S5P_WM8994_MASTER - val |= (0x11 << 12); -#else - val |= (0x02 << 12); - val |= (0x5 << 20); -#endif /* end of CONFIG_SND_S5P_WM8994_MASTER */ - __raw_writel(val, S5P_CLK_OUT); -#endif /* end of CONFIG_JUPITER_VER_05 */ + clk_enable(wm8994->codec_clk); + DEBUG_LOG("USBOSC Enabled in Sleep Mode\n"); } else { - /* Turn off LDO for codec. */ - gpio_set_value(GPIO_CODEC_LDO_EN, 0); - - /* wait to turn off codec entirely */ - /* commenting sleep as not required in SLSI platform */ - /*msleep(125);*/ - - /* Turn on master clock.*/ -#if (defined CONFIG_JUPITER_VER_B5) - DEBUG_LOG("LDO Disable = %d, XTAL CLK From OSI", en); - gpio_set_value(GPIO_CODEC_XTAL_EN, 0); -#elif (defined CONFIG_JUPITER_VER_B4) - DEBUG_LOG("LDO Disable = %d, XTAL CLK From AP EMUL", en); -#ifdef CONFIG_SND_S5P_WM8994_MASTER - val &= ~(0x11 << 12); -#else - val &= ~(0x02 << 12); - val &= ~(0x5 << 20); -#endif /* end of CONFIG_SND_S5P_WM8994_MASTER*/ -#elif (defined CONFIG_ARIES_VER_B0) || (defined CONFIG_ARIES_VER_B1) || \ - (defined CONFIG_ARIES_VER_B2) || \ - (defined CONFIG_ARIES_VER_B3) || \ - (defined CONFIG_MACH_S5PC110_P1) || \ - (defined CONFIG_MACH_S5PC110_ARIES) || \ - (defined CONFIG_MACH_S5PC110_CRESPO) -#ifdef CONFIG_MACH_S5PC110_ARIES - gpio_set_value(GPIO_CODEC_XTAL_EN, 0); -#if (defined CONFIG_SND_S5P_WM8994_MASTER) - else { - __raw_writel(__raw_readl(S5P_OTHERS) & (~(0x3 << 8)), - S5P_OTHERS); - __raw_writel(__raw_readl(S5P_CLK_OUT) & (0xFFFFFFFE), - S5P_CLK_OUT); - } -#endif -#else -#if (defined CONFIG_SND_S5P_WM8994_MASTER) - __raw_writel(__raw_readl(S5P_OTHERS) & (~(0x3 << 8)), - S5P_OTHERS); - __raw_writel(__raw_readl(S5P_CLK_OUT) & (0xFFFFFFFE), - S5P_CLK_OUT); -#endif -#endif -#else -#if (defined CONFIG_JUPITER_VER_B4) - __raw_writel(val, S5P_CLK_OUT); -#endif -#endif + clk_disable(wm8994->codec_clk); + DEBUG_LOG("USBOSC disable in Sleep Mode\n"); } - DEBUG_LOG("AUDIO POWER COMPLETED : %d", en); - return 0; } -void audio_ctrl_mic_bias_gpio(int enable) +void audio_ctrl_mic_bias_gpio(struct wm8994_platform_data *pdata, int enable) { - int headset_state; - DEBUG_LOG("enable = [%d]", enable); - if (enable) { - /* commented as this function is not present in SLSI platform */ - /* set_recording_status(1); */ - gpio_set_value(GPIO_MICBIAS_EN, 1); - } else { - /* commented as this function is not present in SLSI platform */ - /* set_recording_status(0);*/ - /* headset_state = get_headset_status();*/ -/* if( headset_state == 0 ||headset_state == 0x1 << 5 ) */ - gpio_set_value(GPIO_MICBIAS_EN, 0); + if (!pdata) + pr_err("failed to turn off micbias pin\n"); + else { + if (enable) + gpio_set_value(pdata->micbias, 1); + else + gpio_set_value(pdata->micbias, 0); } } -/*Audio Routing routines for the universal board..wm8994 codec*/ +/* Audio Routing routines for the universal board..wm8994 codec*/ void wm8994_disable_playback_path(struct snd_soc_codec *codec, enum audio_path path) { @@ -315,7 +212,7 @@ void wm8994_disable_playback_path(struct snd_soc_codec *codec, break; case SPK: - /*Disbale the SPKOUTL */ + /* Disbale the SPKOUTL */ val &= ~(WM8994_SPKOUTL_ENA_MASK); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); @@ -331,7 +228,7 @@ void wm8994_disable_playback_path(struct snd_soc_codec *codec, WM8994_SPKMIXR_TO_SPKOUTR_MASK); wm8994_write(codec, WM8994_SPKOUT_MIXERS, val); - /*Mute Speaker mixer */ + /* Mute Speaker mixer */ val = wm8994_read(codec, WM8994_SPEAKER_MIXER); val &= ~(WM8994_DAC1L_TO_SPKMIXL_MASK); wm8994_write(codec, WM8994_SPEAKER_MIXER, val); @@ -374,12 +271,25 @@ void wm8994_disable_playback_path(struct snd_soc_codec *codec, wm8994_write(codec, WM8994_CHARGE_PUMP_1, 0x1F25); break; + case BT: + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_6); + val &= ~(WM8994_AIF3_ADCDAT_SRC_MASK | + WM8994_AIF2_ADCDAT_SRC_MASK | + WM8994_AIF2_DACDAT_SRC_MASK | + WM8994_AIF1_DACDAT_SRC_MASK); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); + val &= ~(WM8994_AIF1DAC1_MUTE_MASK | WM8994_AIF1DAC1_MONO_MASK); + val |= (WM8994_AIF1DAC1_MUTE); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); + break; + case SPK_HP: val &= ~(WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK | WM8994_SPKOUTL_ENA_MASK); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); - /* ------------------ Ear path setting ------------------ */ /* Disable DAC1L to HPOUT1L path */ val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | @@ -392,10 +302,10 @@ void wm8994_disable_playback_path(struct snd_soc_codec *codec, WM8994_DAC1R_TO_MIXOUTR_MASK); wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - /*Disable Charge Pump */ + /* Disable Charge Pump */ val = wm8994_read(codec, WM8994_CHARGE_PUMP_1); val &= ~WM8994_CP_ENA_MASK; - val |= WM8994_CP_ENA_DEFAULT; /* this is from wolfson */ + val |= WM8994_CP_ENA_DEFAULT; wm8994_write(codec, WM8994_CHARGE_PUMP_1, val); /* Intermediate HP settings */ @@ -405,7 +315,6 @@ void wm8994_disable_playback_path(struct snd_soc_codec *codec, WM8994_HPOUT1L_OUTP_MASK | WM8994_HPOUT1L_RMV_SHORT_MASK); wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); - /* ------------------ Spk path setting ------------------ */ /* Disable SPKLVOL */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); val &= ~(WM8994_SPKLVOL_ENA_MASK); @@ -418,7 +327,7 @@ void wm8994_disable_playback_path(struct snd_soc_codec *codec, WM8994_SPKMIXR_TO_SPKOUTR_MASK); wm8994_write(codec, WM8994_SPKOUT_MIXERS, val); - /*Mute Speaker mixer */ + /* Mute Speaker mixer */ val = wm8994_read(codec, WM8994_SPEAKER_MIXER); val &= ~(WM8994_DAC1L_TO_SPKMIXL_MASK); wm8994_write(codec, WM8994_SPEAKER_MIXER, val); @@ -431,21 +340,19 @@ void wm8994_disable_playback_path(struct snd_soc_codec *codec, } } -void wm8994_disable_rec_path(struct snd_soc_codec *codec, - enum mic_path rec_path) +void wm8994_disable_rec_path(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = codec->drvdata; u16 val; + enum mic_path mic = wm8994->rec_path; wm8994->rec_path = MIC_OFF; - audio_ctrl_mic_bias_gpio(0); - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_MICB1_ENA_MASK); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); + if (!(wm8994->call_state & DISCONNECT)) + audio_ctrl_mic_bias_gpio(wm8994->pdata, 0); - switch (rec_path) { + switch (mic) { case MAIN: DEBUG_LOG("Disabling MAIN Mic Path..\n"); @@ -453,35 +360,34 @@ void wm8994_disable_rec_path(struct snd_soc_codec *codec, val &= ~(WM8994_IN1L_ENA_MASK | WM8994_MIXINL_ENA_MASK); wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, val); - if (!wm8994->testmode_config_flag) { - /* Mute IN1L PGA, update volume */ - val = wm8994_read(codec, - WM8994_LEFT_LINE_INPUT_1_2_VOLUME); - val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); - val |= (WM8994_IN1L_VU | WM8994_IN1L_MUTE); - wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, - val); - - /*Mute the PGA */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_3); - val &= ~(WM8994_IN1L_TO_MIXINL_MASK | - WM8994_IN1L_MIXINL_VOL_MASK | - WM8994_MIXOUTL_MIXINL_VOL_MASK); - wm8994_write(codec, WM8994_INPUT_MIXER_3, val); - } - /*Disconnect IN1LN ans IN1LP to the inputs */ + /* Mute IN1L PGA, update volume */ + val = wm8994_read(codec, + WM8994_LEFT_LINE_INPUT_1_2_VOLUME); + val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); + val |= (WM8994_IN1L_VU | WM8994_IN1L_MUTE); + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, + val); + + /*Mute the PGA */ + val = wm8994_read(codec, WM8994_INPUT_MIXER_3); + val &= ~(WM8994_IN1L_TO_MIXINL_MASK | + WM8994_IN1L_MIXINL_VOL_MASK | + WM8994_MIXOUTL_MIXINL_VOL_MASK); + wm8994_write(codec, WM8994_INPUT_MIXER_3, val); + + /* Disconnect IN1LN ans IN1LP to the inputs */ val = wm8994_read(codec, WM8994_INPUT_MIXER_2); val &= (WM8994_IN1LN_TO_IN1L_MASK | WM8994_IN1LP_TO_IN1L_MASK); wm8994_write(codec, WM8994_INPUT_MIXER_2, val); - /*Digital Paths */ + /* Digital Paths */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_4); val &= ~(WM8994_ADCL_ENA_MASK | WM8994_AIF1ADC1L_ENA_MASK); wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, val); - /*Disable timeslots */ + /* Disable timeslots */ val = wm8994_read(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING); - val |= WM8994_ADC1L_TO_AIF1ADC1L; + val &= ~(WM8994_ADC1L_TO_AIF1ADC1L); wm8994_write(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, val); break; @@ -491,22 +397,21 @@ void wm8994_disable_rec_path(struct snd_soc_codec *codec, val &= ~(WM8994_IN1R_ENA_MASK | WM8994_MIXINR_ENA_MASK); wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, val); - if (!wm8994->testmode_config_flag) { - /* Disable volume,unmute Right Line */ - val = wm8994_read(codec, - WM8994_RIGHT_LINE_INPUT_1_2_VOLUME); - val &= ~WM8994_IN1R_MUTE_MASK; /* Unmute IN1R */ - val |= (WM8994_IN1R_VU | WM8994_IN1R_MUTE); - wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, - val); - - /* Mute right pga, set volume */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_4); - val &= ~(WM8994_IN1R_TO_MIXINR_MASK | - WM8994_IN1R_MIXINR_VOL_MASK | - WM8994_MIXOUTR_MIXINR_VOL_MASK); - wm8994_write(codec, WM8994_INPUT_MIXER_4, val); - } + /* Disable volume,unmute Right Line */ + val = wm8994_read(codec, + WM8994_RIGHT_LINE_INPUT_1_2_VOLUME); + val &= ~WM8994_IN1R_MUTE_MASK; /* Unmute IN1R */ + val |= (WM8994_IN1R_VU | WM8994_IN1R_MUTE); + wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, + val); + + /* Mute right pga, set volume */ + val = wm8994_read(codec, WM8994_INPUT_MIXER_4); + val &= ~(WM8994_IN1R_TO_MIXINR_MASK | + WM8994_IN1R_MIXINR_VOL_MASK | + WM8994_MIXOUTR_MIXINR_VOL_MASK); + wm8994_write(codec, WM8994_INPUT_MIXER_4, val); + /* Disconnect in1rn to inr1 and in1rp to inrp */ val = wm8994_read(codec, WM8994_INPUT_MIXER_2); val &= ~(WM8994_IN1RN_TO_IN1R_MASK | WM8994_IN1RP_TO_IN1R_MASK); @@ -524,296 +429,126 @@ void wm8994_disable_rec_path(struct snd_soc_codec *codec, wm8994_write(codec, WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, val); break; + case BT_REC: + val = wm8994_read(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING); + val &= ~(WM8994_AIF2DACL_TO_AIF1ADC1L_MASK | + WM8994_ADC1L_TO_AIF1ADC1L_MASK); + wm8994_write(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_AIF2DACR_TO_AIF1ADC1R_MASK | + WM8994_ADC1R_TO_AIF1ADC1R_MASK); + wm8994_write(codec, WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_AIF2_DAC_FILTERS_1); + val &= ~(WM8994_AIF2DAC_MUTE_MASK); + val |= (WM8994_AIF2DAC_MUTE); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, val); + break; + default: - DEBUG_LOG_ERR("Path[%d] is not invaild!\n", rec_path); + DEBUG_LOG_ERR("Path[%d] is not invaild!\n", mic); break; } } -void wm8994_disable_fmradio_path(struct snd_soc_codec *codec, - enum fmradio_audio_path path) +void wm8994_record_headset_mic(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = codec->drvdata; u16 val; - DEBUG_LOG("Turn off fmradio_path = [%d]", path); - - switch (path) { - case FMR_OFF: - wm8994->fmradio_path = FMR_OFF; - - /* Disable speaker setting for FM radio */ - /* disbale the SPKOUTL */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_SPKOUTL_ENA_MASK); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); - - /* Disable SPK Volume. */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); - val &= ~(WM8994_SPKRVOL_ENA_MASK | WM8994_SPKLVOL_ENA_MASK); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val); - - if (!wm8994->testmode_config_flag) { - /* Mute the SPKMIXVOLUME */ - val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); - val &= ~(WM8994_SPKMIXL_VOL_MASK); - wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); - val &= ~(WM8994_SPKMIXR_VOL_MASK); - wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); - val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | - WM8994_SPKOUTL_VOL_MASK); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); - val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | - WM8994_SPKOUTR_VOL_MASK); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); - - val = wm8994_read(codec, WM8994_CLASSD); - val &= ~(WM8994_SPKOUTL_BOOST_MASK); - wm8994_write(codec, WM8994_CLASSD, val); - } - - /*Output MIxer-Output PGA */ - val = wm8994_read(codec, WM8994_SPKOUT_MIXERS); - val &= ~(WM8994_SPKMIXL_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTR_MASK); - wm8994_write(codec, WM8994_SPKOUT_MIXERS, val); - - /* Output mixer setting */ - val = wm8994_read(codec, WM8994_SPEAKER_MIXER); - val &= ~(WM8994_MIXINL_TO_SPKMIXL_MASK | - WM8994_MIXINR_TO_SPKMIXR_MASK); - wm8994_write(codec, WM8994_SPEAKER_MIXER, val); - - /* Disable earpath setting for FM radio */ - /* Disable end point for preventing pop up noise. */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); - - /* Disable MIXOUT */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); - val &= ~(WM8994_MIXOUTLVOL_ENA_MASK | - WM8994_MIXOUTRVOL_ENA_MASK | - WM8994_MIXOUTL_ENA_MASK | - WM8994_MIXOUTR_ENA_MASK); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val); - - if (!wm8994->testmode_config_flag) { - /* Output setting */ - val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | - WM8994_HPOUT1L_VOL_MASK); - wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); - - val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | - WM8994_HPOUT1R_VOL_MASK); - wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); - } - /*Disable Charge Pump */ - val = wm8994_read(codec, WM8994_CHARGE_PUMP_1); - val &= ~WM8994_CP_ENA_MASK; - val |= WM8994_CP_ENA_DEFAULT; /* this is from wolfson */ - wm8994_write(codec, WM8994_CHARGE_PUMP_1, val); - - /* Intermediate HP settings */ - val = wm8994_read(codec, WM8994_ANALOGUE_HP_1); - val &= ~(WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1R_OUTP_MASK | - WM8994_HPOUT1R_RMV_SHORT_MASK | WM8994_HPOUT1L_DLY_MASK | - WM8994_HPOUT1L_OUTP_MASK | WM8994_HPOUT1L_RMV_SHORT_MASK); - wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); - - /* Disable Output mixer setting */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | - WM8994_MIXINL_TO_MIXOUTL_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); - - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | - WM8994_MIXINR_TO_MIXOUTR_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - - /* Disable common setting for FM radio */ - /* Disable IN2 and MIXIN */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_2); - val &= ~(WM8994_TSHUT_ENA_MASK | WM8994_TSHUT_OPDIS_MASK | - WM8994_OPCLK_ENA_MASK | WM8994_MIXINL_ENA_MASK | - WM8994_MIXINR_ENA_MASK | WM8994_IN2L_ENA_MASK | - WM8994_IN2R_ENA_MASK); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, val); - - /* Disable Input mixer setting */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_2); - val &= ~(WM8994_IN2LN_TO_IN2L_MASK | WM8994_IN2RN_TO_IN2R_MASK); - wm8994_write(codec, WM8994_INPUT_MIXER_2, val); - - if (!wm8994->testmode_config_flag) { - /* Disable IN2L to MIXINL */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_3); - val &= ~(WM8994_IN2L_TO_MIXINL_MASK); - wm8994_write(codec, WM8994_INPUT_MIXER_3, val); - - /*Disable IN2R to MIXINR */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_4); - val &= ~(WM8994_IN2R_TO_MIXINR_MASK); - wm8994_write(codec, WM8994_INPUT_MIXER_4, val); - } - /* Mute IN2L PGA volume */ - val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_3_4_VOLUME); - val &= ~(WM8994_IN2L_VU_MASK | WM8994_IN2L_MUTE_MASK | - WM8994_IN2L_VOL_MASK); - val |= (WM8994_IN2L_VU | WM8994_IN2L_MUTE); - wm8994_write(codec, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, val); - - val = wm8994_read(codec, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME); - val &= ~(WM8994_IN2R_VU_MASK | WM8994_IN2R_MUTE_MASK | - WM8994_IN2R_VOL_MASK); - val |= (WM8994_IN2R_VU | WM8994_IN2R_MUTE); - wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, val); - - /* Disable path setting for mixing */ - val = wm8994_read(codec, WM8994_SPEAKER_MIXER); - val &= ~(WM8994_DAC1L_TO_SPKMIXL_MASK); - wm8994_write(codec, WM8994_SPEAKER_MIXER, val); - - /* Disable DAC1L to HPOUT1L path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | - WM8994_DAC1L_TO_MIXOUTL_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); - - /* Disable DAC1R to HPOUT1R path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | - WM8994_DAC1R_TO_MIXOUTR_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - break; - - case FMR_SPK: - /* Output mixer setting */ - val = wm8994_read(codec, WM8994_SPEAKER_MIXER); - val &= ~(WM8994_MIXINL_TO_SPKMIXL_MASK | - WM8994_MIXINR_TO_SPKMIXR_MASK); - wm8994_write(codec, WM8994_SPEAKER_MIXER, val); - break; - - case FMR_HP: - /* Disable end point for preventing pop up noise. */ - /* Disable Output mixer setting */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | - WM8994_MIXINL_TO_MIXOUTL_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); - - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | - WM8994_MIXINR_TO_MIXOUTR_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - break; - - case FMR_SPK_MIX: - /*Mute the DAC path */ - val = wm8994_read(codec, WM8994_SPEAKER_MIXER); - val &= ~(WM8994_DAC1L_TO_SPKMIXL_MASK); - wm8994_write(codec, WM8994_SPEAKER_MIXER, val); - break; - - case FMR_HP_MIX: - /* Disable DAC1L to HPOUT1L path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | - WM8994_DAC1L_TO_MIXOUTL_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); + audio_ctrl_mic_bias_gpio(wm8994->pdata, 1); - /* Disable DAC1R to HPOUT1R path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | - WM8994_DAC1R_TO_MIXOUTR_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - break; - - case FMR_SPK_HP_MIX: - /*Mute the DAC path */ - val = wm8994_read(codec, WM8994_SPEAKER_MIXER); - val &= ~(WM8994_DAC1L_TO_SPKMIXL_MASK); - wm8994_write(codec, WM8994_SPEAKER_MIXER, val); + DEBUG_LOG("Recording through Headset Mic\n"); - /* Disable DAC1L to HPOUT1L path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | - WM8994_DAC1L_TO_MIXOUTL_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); + val = wm8994_read(codec, WM8994_SPEAKER_MIXER); + val &= ~WM8994_MIXINL_TO_SPKMIXL_MASK; + wm8994_write(codec, WM8994_SPEAKER_MIXER, val); - /* Disable DAC1R to HPOUT1R path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | - WM8994_DAC1R_TO_MIXOUTR_MASK); - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - break; + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); + val &= ~WM8994_MIXINL_TO_MIXOUTL_MASK; + wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); - default: - DEBUG_LOG_ERR("fmradio path[%d] is not invaild!\n", path); - return; - break; - } -} + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); + val &= ~WM8994_MIXINR_TO_MIXOUTR_MASK; + wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); -void wm8994_record_headset_mic(struct snd_soc_codec *codec) -{ - struct wm8994_priv *wm8994 = codec->drvdata; + val = wm8994_read(codec, WM8994_DAC2_LEFT_MIXER_ROUTING); + val &= ~(WM8994_ADC1_TO_DAC2L_MASK); + wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, val); - u16 val; + val = wm8994_read(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_ADC1_TO_DAC2R_MASK); + wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, val); - audio_ctrl_mic_bias_gpio(1); + /* Mixing left channel output to right channel */ + val = wm8994_read(codec, WM8994_AIF1_CONTROL_1); + val &= ~(WM8994_AIF1ADCL_SRC_MASK | WM8994_AIF1ADCR_SRC_MASK); + val |= (WM8994_AIF1ADCL_SRC | WM8994_AIF1ADCR_SRC); + wm8994_write(codec, WM8994_AIF1_CONTROL_1, val); - DEBUG_LOG("Recording through Headset Mic\n"); + wm8994_write(codec, WM8994_ANTIPOP_2, 0x68); - /*Enable mic bias, vmid, bias generator */ + /* Enable mic bias, vmid, bias generator */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | - WM8994_MICB1_ENA_MASK); - val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | WM8994_MICB1_ENA); + val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK); + val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); val = (WM8994_MIXINR_ENA | WM8994_IN1R_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, val); - if (!wm8994->testmode_config_flag) { - /* Enable volume,unmute Right Line */ - val = wm8994_read(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME); - val &= ~WM8994_IN1R_MUTE_MASK; /* Unmute IN1R */ - val |= (WM8994_IN1R_VU | TUNING_RECORD_SUB_INPUTMIX_VOL); - wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, val); - - /* unmute right pga, set volume */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_4); - val &= ~(WM8994_IN1R_TO_MIXINR_MASK | - WM8994_IN1R_MIXINR_VOL_MASK | - WM8994_MIXOUTR_MIXINR_VOL_MASK); - val |= (WM8994_IN1R_TO_MIXINR); /* 0db */ - wm8994_write(codec, WM8994_INPUT_MIXER_4, val); - } + val = wm8994_read(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME); + val &= ~(WM8994_IN1R_MUTE_MASK | WM8994_IN1R_VOL_MASK); + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_IN1R_VU | + TUNING_RECOGNITION_SUB_INPUTMIX_VOL); + else + val |= (WM8994_IN1R_VU | TUNING_RECORD_SUB_INPUTMIX_VOL); + wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, val); + + val = wm8994_read(codec, WM8994_INPUT_MIXER_4); + val &= ~(WM8994_IN1R_TO_MIXINR_MASK | + WM8994_IN1R_MIXINR_VOL_MASK | + WM8994_MIXOUTR_MIXINR_VOL_MASK); + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_IN1R_TO_MIXINR | WM8994_IN1R_MIXINR_VOL); + else + val |= (WM8994_IN1R_TO_MIXINR | WM8994_IN1R_MIXINR_VOL); + wm8994_write(codec, WM8994_INPUT_MIXER_4 , val); + + val = wm8994_read(codec, WM8994_AIF1_ADC1_LEFT_VOLUME); + val &= ~(WM8994_AIF1ADC1L_VOL_MASK); + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_AIF1ADC1_VU | + TUNING_RECOGNITION_SUB_AIF1ADCL_VOL); + else + val |= (WM8994_AIF1ADC1_VU | TUNING_RECORD_SUB_AIF1ADCL_VOL); + wm8994_write(codec, WM8994_AIF1_ADC1_LEFT_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME); + val &= ~(WM8994_AIF1ADC1R_VOL_MASK); + + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_AIF1ADC1_VU | + TUNING_RECOGNITION_SUB_AIF1ADCR_VOL); + else + val |= (WM8994_AIF1ADC1_VU | + TUNING_RECORD_SUB_AIF1ADCR_VOL); + wm8994_write(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, val); val = (WM8994_IN1RN_TO_IN1R | WM8994_IN1RP_TO_IN1R); wm8994_write(codec, WM8994_INPUT_MIXER_2, val); - /*Digital Paths */ - /*Enable right ADC and time slot */ + /* Digital Paths */ + /* Enable right ADC and time slot */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_4); val &= ~(WM8994_ADCR_ENA_MASK | WM8994_AIF1ADC1R_ENA_MASK); val |= (WM8994_AIF1ADC1R_ENA | WM8994_ADCR_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, val); - /*ADC Right mixer routing */ + /* ADC Right mixer routing */ val = wm8994_read(codec, WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING); val &= ~(WM8994_ADC1R_TO_AIF1ADC1R_MASK); val |= WM8994_ADC1R_TO_AIF1ADC1R; @@ -833,46 +568,95 @@ void wm8994_record_main_mic(struct snd_soc_codec *codec) u16 val; DEBUG_LOG("Recording through Main Mic\n"); - /* audio_ctrl_mic_bias_gpio(1); */ + audio_ctrl_mic_bias_gpio(wm8994->pdata, 1); + + val = wm8994_read(codec, WM8994_SPEAKER_MIXER); + val &= ~WM8994_MIXINL_TO_SPKMIXL_MASK; + wm8994_write(codec, WM8994_SPEAKER_MIXER, val); + + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); + val &= ~WM8994_MIXINL_TO_MIXOUTL_MASK; + wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); + + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); + val &= ~WM8994_MIXINR_TO_MIXOUTR_MASK; + wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); + + val = wm8994_read(codec, WM8994_DAC2_LEFT_MIXER_ROUTING); + val &= ~(WM8994_ADC1_TO_DAC2L_MASK); + wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_ADC1_TO_DAC2R_MASK); + wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_AIF1_CONTROL_1); + val &= ~(WM8994_AIF1ADCL_SRC_MASK | WM8994_AIF1ADCR_SRC_MASK); + wm8994_write(codec, WM8994_AIF1_CONTROL_1, val); + + /* Main mic volume issue fix: requested H/W */ + wm8994_write(codec, WM8994_ANTIPOP_2, 0x68); - /*Enable micbias,vmid,mic1 */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | - WM8994_MICB1_ENA_MASK); - val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | WM8994_MICB1_ENA); + val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK); + val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); val = (WM8994_MIXINL_ENA | WM8994_IN1L_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, val); - if (!wm8994->testmode_config_flag) { - /* Unmute IN1L PGA, update volume */ - val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); - val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); - val |= (WM8994_IN1L_VU | TUNING_RECORD_MAIN_INPUTLINE_VOL); - wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, val); + if (wm8994->recognition_active == REC_ON) { + val = wm8994_read(codec, WM8994_AIF1_ADC1_FILTERS); + val &= ~(WM8994_AIF1ADC1L_HPF_MASK | WM8994_AIF1ADC1R_HPF_MASK); + val |= (WM8994_AIF1ADC1L_HPF | WM8994_AIF1ADC1R_HPF); + wm8994_write(codec, WM8994_AIF1_ADC1_FILTERS, val); + } - /*Unmute the PGA */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_3); - val &= ~(WM8994_IN1L_TO_MIXINL_MASK | - WM8994_IN1L_MIXINL_VOL_MASK | - WM8994_MIXOUTL_MIXINL_VOL_MASK); + val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); + val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_IN1L_VU | + TUNING_RECOGNITION_MAIN_INPUTLINE_VOL); + else + val |= (WM8994_IN1L_VU | TUNING_RECORD_MAIN_INPUTLINE_VOL); + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, val); + + val = wm8994_read(codec, WM8994_INPUT_MIXER_3); + val &= ~(WM8994_IN1L_TO_MIXINL_MASK | + WM8994_IN1L_MIXINL_VOL_MASK | + WM8994_MIXOUTL_MIXINL_VOL_MASK); + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_IN1L_TO_MIXINL); + else val |= (WM8994_IN1L_MIXINL_VOL | WM8994_IN1L_TO_MIXINL); - wm8994_write(codec, WM8994_INPUT_MIXER_3, val); - } + wm8994_write(codec, WM8994_INPUT_MIXER_3, val); - val = wm8994_read(codec, WM8994_INPUT_MIXER_2); - val &= (WM8994_IN1LN_TO_IN1L_MASK | WM8994_IN1LP_TO_IN1L_MASK); - val |= (WM8994_IN1LP_TO_IN1L | WM8994_IN1LN_TO_IN1L); + val = (WM8994_IN1LP_TO_IN1L | WM8994_IN1LN_TO_IN1L); wm8994_write(codec, WM8994_INPUT_MIXER_2, val); - /*Digital Paths */ + val = wm8994_read(codec, WM8994_AIF1_ADC1_LEFT_VOLUME); + val &= ~(WM8994_AIF1ADC1L_VOL_MASK); + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_AIF1ADC1_VU | + TUNING_RECOGNITION_MAIN_AIF1ADCL_VOL); + else + val |= (WM8994_AIF1ADC1_VU | TUNING_RECORD_MAIN_AIF1ADCL_VOL); + wm8994_write(codec, WM8994_AIF1_ADC1_LEFT_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME); + val &= ~(WM8994_AIF1ADC1R_VOL_MASK); + if (wm8994->recognition_active == REC_ON) + val |= (WM8994_AIF1ADC1_VU | + TUNING_RECOGNITION_MAIN_AIF1ADCR_VOL); + else + val |= (WM8994_AIF1ADC1_VU | TUNING_RECORD_MAIN_AIF1ADCR_VOL); + wm8994_write(codec, WM8994_AIF1_ADC1_RIGHT_VOLUME, val); val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_4); val &= ~(WM8994_ADCL_ENA_MASK | WM8994_AIF1ADC1L_ENA_MASK); val |= (WM8994_AIF1ADC1L_ENA | WM8994_ADCL_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, val); - /*Enable timeslots */ + /* Enable timeslots */ val = wm8994_read(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING); val |= WM8994_ADC1L_TO_AIF1ADC1L; wm8994_write(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, val); @@ -882,56 +666,127 @@ void wm8994_record_main_mic(struct snd_soc_codec *codec) wm8994_write(codec, WM8994_AIF1_MASTER_SLAVE, val); wm8994_write(codec, WM8994_GPIO_1, 0xA101); + if (wm8994->recognition_active == REC_ON) + msleep(60); } -void wm8994_set_playback_receiver(struct snd_soc_codec *codec) +void wm8994_record_bluetooth(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + u16 val; + + DEBUG_LOG("BT Record Path for Voice Command\n"); + + wm8994_set_voicecall_common_setting(codec); + + val = wm8994_read(codec, WM8994_DAC2_LEFT_MIXER_ROUTING); + val &= ~(WM8994_ADC1_TO_DAC2L_MASK); + wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_ADC1_TO_DAC2R_MASK); + wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); + val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK); + val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); + + wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, 0x0000); + + wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, 0x0000); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_4); + val &= ~(WM8994_AIF1ADC1L_ENA_MASK | WM8994_AIF1ADC1R_ENA_MASK); + val |= (WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC1R_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_4 , val); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_5); + val &= ~(WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK); + val |= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, val); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_6); + val &= ~(WM8994_AIF3_ADCDAT_SRC_MASK | WM8994_AIF2_DACDAT_SRC_MASK); + val |= (0x1 << WM8994_AIF3_ADCDAT_SRC_SHIFT | WM8994_AIF2_DACDAT_SRC); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, val); + + val = wm8994_read(codec, WM8994_AIF2_DAC_FILTERS_1); + val &= ~(WM8994_AIF2DAC_MUTE_MASK); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, val); + val = wm8994_read(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING); + val &= ~(WM8994_AIF2DACL_TO_AIF1ADC1L_MASK); + val |= (WM8994_AIF2DACL_TO_AIF1ADC1L); + wm8994_write(codec, WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_AIF2DACR_TO_AIF1ADC1R_MASK); + val |= (WM8994_AIF2DACR_TO_AIF1ADC1R); + wm8994_write(codec, WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, val); + + wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); + + wm8994_write(codec, WM8994_OVERSAMPLING, 0X0000); + + wm8994_write(codec, WM8994_GPIO_8, WM8994_GP8_DIR | WM8994_GP8_DB); + wm8994_write(codec, WM8994_GPIO_9, WM8994_GP9_DB); + wm8994_write(codec, WM8994_GPIO_10, WM8994_GP10_DB); + wm8994_write(codec, WM8994_GPIO_11, WM8994_GP11_DB); +} +void wm8994_set_playback_receiver(struct snd_soc_codec *codec) +{ u16 val; DEBUG_LOG(""); - if (!wm8994->testmode_config_flag) { - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_5); - val &= ~(WM8994_DACL_MIXOUTL_VOL_MASK); - val |= TUNING_RCV_OUTMIX5_VOL << WM8994_DACL_MIXOUTL_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_5, val); + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_5); + val &= ~(WM8994_DACL_MIXOUTL_VOL_MASK); + val |= TUNING_RCV_OUTMIX5_VOL << WM8994_DACL_MIXOUTL_VOL_SHIFT; + wm8994_write(codec, WM8994_OUTPUT_MIXER_5, val); - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_6); - val &= ~(WM8994_DACR_MIXOUTR_VOL_MASK); - val |= TUNING_RCV_OUTMIX6_VOL << WM8994_DACR_MIXOUTR_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_6, val); + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_6); + val &= ~(WM8994_DACR_MIXOUTR_VOL_MASK); + val |= TUNING_RCV_OUTMIX6_VOL << WM8994_DACR_MIXOUTR_VOL_SHIFT; + wm8994_write(codec, WM8994_OUTPUT_MIXER_6, val); - val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | - TUNING_RCV_OPGAL_VOL); - wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); + val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | + TUNING_RCV_OPGAL_VOL); + wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); - val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | - TUNING_RCV_OPGAR_VOL); - wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); + val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | + TUNING_RCV_OPGAR_VOL); + wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); - val = wm8994_read(codec, WM8994_HPOUT2_VOLUME); - val &= ~(WM8994_HPOUT2_MUTE_MASK | WM8994_HPOUT2_VOL_MASK); - val |= TUNING_HPOUT2_VOL << WM8994_HPOUT2_VOL_SHIFT; - wm8994_write(codec, WM8994_HPOUT2_VOLUME, val); + val = wm8994_read(codec, WM8994_HPOUT2_VOLUME); + val &= ~(WM8994_HPOUT2_MUTE_MASK | WM8994_HPOUT2_VOL_MASK); + val |= TUNING_HPOUT2_VOL << WM8994_HPOUT2_VOL_SHIFT; + wm8994_write(codec, WM8994_HPOUT2_VOLUME, val); - /* Unmute DAC1 left */ - val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); - val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); - val |= TUNING_DAC1L_VOL; - wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); + /* Unmute DAC1 left */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); + val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); + val |= TUNING_DAC1L_VOL; + wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); - /* Unmute and volume ctrl RightDAC */ - val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); - val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); - val |= TUNING_DAC1R_VOL; - wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - } + /* Unmute and volume ctrl RightDAC */ + val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); + val |= TUNING_DAC1R_VOL; + wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_LEFT_VOLUME); + val &= ~(WM8994_AIF1DAC1L_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1L_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_AIF1DAC1R_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1R_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, val); val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); val &= ~(WM8994_DAC1L_TO_MIXOUTL_MASK); @@ -997,63 +852,15 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) u16 val; - u16 TestReturn1 = 0; - u16 TestReturn2 = 0; - u16 TestLow1 = 0; - u16 TestHigh1 = 0; - u8 TestLow = 0; - u8 TestHigh = 0; + u16 testreturn1 = 0; + u16 testreturn2 = 0; + u16 testlow1 = 0; + u16 testhigh1 = 0; + u8 testlow = 0; + u8 testhigh = 0; DEBUG_LOG(""); - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_NORMAL); - val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, 0x0003); - - if (!wm8994->testmode_config_flag) { - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_5); - val &= ~(WM8994_DACL_MIXOUTL_VOL_MASK); - val |= TUNING_EAR_OUTMIX5_VOL << WM8994_DACL_MIXOUTL_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_5, val); - - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_6); - val &= ~(WM8994_DACR_MIXOUTR_VOL_MASK); - val |= TUNING_EAR_OUTMIX6_VOL << WM8994_DACR_MIXOUTR_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_6, val); - - val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | WM8994_HPOUT1L_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | - TUNING_MP3_OUTPUTL_VOL); - wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); - - val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | WM8994_HPOUT1R_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | - TUNING_MP3_OUTPUTR_VOL); - wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); - - val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | - TUNING_MP3_OPGAL_VOL); - wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); - - val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | - TUNING_MP3_OPGAR_VOL); - wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); - } - /* Configuring the Digital Paths */ - - /* Unmute the AF1DAC1 */ - val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); - val &= ~(WM8994_AIF1DAC1_MUTE_MASK); - val |= WM8994_AIF1DAC1_UNMUTE; - wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); - /* Enable the Timeslot0 to DAC1L */ val = wm8994_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING); val &= ~(WM8994_AIF1DAC1L_TO_DAC1L_MASK); @@ -1066,18 +873,6 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) val |= WM8994_AIF1DAC1R_TO_DAC1R; wm8994_write(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING, val); - /* Enable DAC1L to HPOUT1L path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | WM8994_DAC1L_TO_MIXOUTL_MASK); - val |= WM8994_DAC1L_TO_MIXOUTL; - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); - - /* Enable DAC1R to HPOUT1R path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | WM8994_DAC1R_TO_MIXOUTR_MASK); - val |= WM8994_DAC1R_TO_MIXOUTR; - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - val = wm8994_read(codec, 0x102); val &= ~(0x0003); val = 0x0003; @@ -1093,16 +888,61 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) val = 0x0000; wm8994_write(codec, 0x102, val); - val = wm8994_read(codec, 0x5D); - val &= ~(0x0002); - val = 0x0002; - wm8994_write(codec, 0x5D, val); - val = wm8994_read(codec, WM8994_CLASS_W_1); val &= ~(0x0005); val |= 0x0005; wm8994_write(codec, WM8994_CLASS_W_1, val); + val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); + val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | WM8994_HPOUT1L_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | + TUNING_RING_OUTPUTL_VOL); + else + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | + TUNING_MP3_OUTPUTL_VOL); + wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); + + val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); + val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | WM8994_HPOUT1R_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | + TUNING_RING_OUTPUTR_VOL); + else + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | + TUNING_MP3_OUTPUTR_VOL); + wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); + + val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | + TUNING_RING_OPGAL_VOL); + else + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | + TUNING_MP3_OPGAL_VOL); + wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); + + val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | + TUNING_RING_OPGAR_VOL); + else + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | + TUNING_MP3_OPGAR_VOL); + wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_LEFT_VOLUME); + val &= ~(WM8994_AIF1DAC1L_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1L_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_AIF1DAC1R_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1R_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, val); + val = wm8994_read(codec, WM8994_DC_SERVO_2); val &= ~(0x03E0); val = 0x03E0; @@ -1111,7 +951,8 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) /* Enable vmid,bias, hp left and right */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | - WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK); + WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK | + WM8994_SPKOUTR_ENA_MASK | WM8994_SPKOUTL_ENA_MASK); val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | WM8994_HPOUT1R_ENA | WM8994_HPOUT1L_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); @@ -1122,60 +963,76 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); /* Enable Charge Pump */ + /* this is from wolfson */ val = wm8994_read(codec, WM8994_CHARGE_PUMP_1); - val &= ~WM8994_CP_ENA_MASK; + val &= ~WM8994_CP_ENA_MASK ; val |= WM8994_CP_ENA | WM8994_CP_ENA_DEFAULT; wm8994_write(codec, WM8994_CHARGE_PUMP_1, val); + msleep(5); + + /* Enable Dac1 and DAC2 and the Timeslot0 for AIF1 */ + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_5); + val &= ~(WM8994_DAC1R_ENA_MASK | WM8994_DAC1L_ENA_MASK | + WM8994_AIF1DAC1R_ENA_MASK | WM8994_AIF1DAC1L_ENA_MASK); + val |= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | + WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, val); + + /* Enable DAC1L to HPOUT1L path */ + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); + val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | WM8994_DAC1L_TO_MIXOUTL_MASK); + val |= WM8994_DAC1L_TO_MIXOUTL; + wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); + + /* Enable DAC1R to HPOUT1R path */ + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); + val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | WM8994_DAC1R_TO_MIXOUTR_MASK); + val |= WM8994_DAC1R_TO_MIXOUTR; + wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); + val &= ~(WM8994_MIXOUTLVOL_ENA_MASK | WM8994_MIXOUTRVOL_ENA_MASK | + WM8994_MIXOUTL_ENA_MASK | WM8994_MIXOUTR_ENA_MASK | + WM8994_SPKRVOL_ENA_MASK | WM8994_SPKLVOL_ENA_MASK); + val |= (WM8994_MIXOUTLVOL_ENA | WM8994_MIXOUTRVOL_ENA | + WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, 0x0030); + val = wm8994_read(codec, WM8994_DC_SERVO_1); val &= ~(0x0303); val = 0x0303; wm8994_write(codec, WM8994_DC_SERVO_1, val); - TestReturn1 = wm8994_read(codec, WM8994_DC_SERVO_4); + msleep(160); + + testreturn1 = wm8994_read(codec, WM8994_DC_SERVO_4); - TestLow = (u8) (TestReturn1 & 0xff); - TestHigh = (u8) ((TestReturn1 >> 8) & 0xff); + testlow = (signed char)(testreturn1 & 0xff); + testhigh = (signed char)((testreturn1>>8) & 0xff); - TestLow1 = ((u16) TestLow - 4) & 0x00ff; - TestHigh1 = (((u16) TestHigh - 4 << 8) & 0xff00); - TestReturn2 = TestLow1 | TestHigh1; - wm8994_write(codec, WM8994_DC_SERVO_4, TestReturn2); + testlow1 = ((signed short)(testlow-5)) & 0x00ff; + testhigh1 = (((signed short)(testhigh-5)<<8) & 0xff00); + testreturn2 = testlow1|testhigh1; + wm8994_write(codec, WM8994_DC_SERVO_4, testreturn2); val = wm8994_read(codec, WM8994_DC_SERVO_1); val &= ~(0x000F); val = 0x000F; wm8994_write(codec, WM8994_DC_SERVO_1, val); - /* msleep(20);*/ /* commenting sleep as not required in SLSI platform */ - DEBUG_LOG("Sleep 15ms"); + msleep(20); /* Intermediate HP settings */ val = wm8994_read(codec, WM8994_ANALOGUE_HP_1); val &= ~(WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1R_OUTP_MASK | WM8994_HPOUT1R_RMV_SHORT_MASK | WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK | WM8994_HPOUT1L_RMV_SHORT_MASK); - val = (WM8994_HPOUT1L_RMV_SHORT | WM8994_HPOUT1L_OUTP | + val = (WM8994_HPOUT1L_RMV_SHORT | WM8994_HPOUT1L_OUTP| WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_RMV_SHORT | WM8994_HPOUT1R_OUTP | WM8994_HPOUT1R_DLY); wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); - /* Enable Dac1 and DAC2 and the Timeslot0 for AIF1 */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_5); - val &= ~(WM8994_DAC1R_ENA_MASK | WM8994_DAC1L_ENA_MASK | - WM8994_AIF1DAC1R_ENA_MASK | WM8994_AIF1DAC1L_ENA_MASK); - val |= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | - WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, val); - - /* Enable MIXOUT */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); - val &= ~(WM8994_MIXOUTLVOL_ENA_MASK | WM8994_MIXOUTRVOL_ENA_MASK | - WM8994_MIXOUTL_ENA_MASK | WM8994_MIXOUTR_ENA_MASK); - val |= (WM8994_MIXOUTLVOL_ENA | WM8994_MIXOUTRVOL_ENA | - WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, 0x0030); - /* Unmute DAC1 left */ val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); @@ -1188,6 +1045,12 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) val |= TUNING_DAC1R_VOL; wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); + /* Unmute the AF1DAC1 */ + val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); + val &= ~(WM8994_AIF1DAC1_MUTE_MASK | WM8994_AIF1DAC1_MONO_MASK); + val |= WM8994_AIF1DAC1_UNMUTE; + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); + } void wm8994_set_playback_speaker(struct snd_soc_codec *codec) @@ -1204,49 +1067,68 @@ void wm8994_set_playback_speaker(struct snd_soc_codec *codec) wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); - val &= ~(WM8994_SPKLVOL_ENA_MASK); + val &= ~(WM8994_MIXOUTLVOL_ENA_MASK | WM8994_MIXOUTRVOL_ENA_MASK | + WM8994_MIXOUTL_ENA_MASK | WM8994_MIXOUTR_ENA_MASK | + WM8994_SPKRVOL_ENA_MASK | WM8994_SPKLVOL_ENA_MASK); val |= WM8994_SPKLVOL_ENA; wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val); /* Speaker Volume Control */ - if (!wm8994->testmode_config_flag) { - /* Unmute the SPKMIXVOLUME */ - val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); - val &= ~(WM8994_SPKMIXL_VOL_MASK); - val |= TUNING_SPKMIXL_ATTEN; - wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); - val &= ~(WM8994_SPKMIXR_VOL_MASK); - wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); - val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | WM8994_SPKOUTL_VOL_MASK); + /* Unmute the SPKMIXVOLUME */ + val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); + val &= ~(WM8994_SPKMIXL_VOL_MASK); + val |= TUNING_SPKMIXL_ATTEN; + wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); + + val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); + val &= ~(WM8994_SPKMIXR_VOL_MASK); + wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); + + val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); + val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | WM8994_SPKOUTL_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_SPKOUT_VU | WM8994_SPKOUTL_MUTE_N | + TUNING_RING_SPKL_VOL); + else val |= (WM8994_SPKOUT_VU | WM8994_SPKOUTL_MUTE_N | - TUNING_MP3_SPKL_VOL); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); + TUNING_MP3_SPKL_VOL); + wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); + + val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); + val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | WM8994_SPKOUTR_VOL_MASK); + wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); + + val = wm8994_read(codec, WM8994_CLASSD); + val &= ~(WM8994_SPKOUTL_BOOST_MASK); + if (wm8994->ringtone_active) + val |= TUNING_RING_CLASSD_VOL << + WM8994_SPKOUTL_BOOST_SHIFT; + else + val |= TUNING_MP3_CLASSD_VOL << + WM8994_SPKOUTL_BOOST_SHIFT; + wm8994_write(codec, WM8994_CLASSD, val); - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); - val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | WM8994_SPKOUTR_VOL_MASK); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); + /* Unmute DAC1 left */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); + val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); + val |= TUNING_DAC1L_VOL; + wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); - val = wm8994_read(codec, WM8994_CLASSD); - val &= ~(WM8994_SPKOUTL_BOOST_MASK); - val |= TUNING_MP3_CLASSD_VOL << WM8994_SPKOUTL_BOOST_SHIFT; - wm8994_write(codec, WM8994_CLASSD, val); + /* Unmute and volume ctrl RightDAC */ + val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); + val |= TUNING_DAC1R_VOL; + wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - /* Unmute DAC1 left */ - val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); - val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); - val |= TUNING_DAC1L_VOL; - wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); + val = wm8994_read(codec, WM8994_AIF1_DAC1_LEFT_VOLUME); + val &= ~(WM8994_AIF1DAC1L_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1L_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, val); - /* Unmute and volume ctrl RightDAC */ - val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); - val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); - val |= TUNING_DAC1R_VOL; - wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - } + val = wm8994_read(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_AIF1DAC1R_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1R_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, val); val = wm8994_read(codec, WM8994_SPKOUT_MIXERS); val &= ~(WM8994_SPKMIXL_TO_SPKOUTL_MASK | @@ -1263,14 +1145,15 @@ void wm8994_set_playback_speaker(struct snd_soc_codec *codec) /* Eable DAC1 Left and timeslot left */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_5); - val &= ~(WM8994_DAC1L_ENA_MASK | WM8994_AIF1DAC1L_ENA_MASK); - val |= (WM8994_AIF1DAC1L_ENA | WM8994_DAC1L_ENA); + val &= ~(WM8994_DAC1L_ENA_MASK | WM8994_AIF1DAC1R_ENA_MASK | + WM8994_AIF1DAC1L_ENA_MASK); + val |= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | WM8994_DAC1L_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, val); /* Unmute */ val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); - val &= ~(WM8994_AIF1DAC1_MUTE_MASK); - val |= WM8994_AIF1DAC1_UNMUTE; + val &= ~(WM8994_AIF1DAC1_MUTE_MASK | WM8994_AIF1DAC1_MONO_MASK); + val |= (WM8994_AIF1DAC1_UNMUTE | WM8994_AIF1DAC1_MONO); wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); /* enable timeslot0 to left dac */ @@ -1282,9 +1165,11 @@ void wm8994_set_playback_speaker(struct snd_soc_codec *codec) /* Enbale bias,vmid and Left speaker */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | - WM8994_SPKOUTL_ENA_MASK); + WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK | + WM8994_SPKOUTR_ENA_MASK | WM8994_SPKOUTL_ENA_MASK); val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | WM8994_SPKOUTL_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); + } void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) @@ -1292,23 +1177,13 @@ void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) struct wm8994_priv *wm8994 = codec->drvdata; u16 val; - int ret; - - u16 nReadServo4Val = NULL; - u16 ncompensationResult = NULL; - u16 nServo4Low = NULL; - u16 nServo4High = NULL; - u8 nCompensationResultLow = 0; - u8 nCompensationResultHigh = 0; - - DEBUG_LOG("testmode_config_flag = [%d]", wm8994->testmode_config_flag); - /* ------------------ Common Settings ------------------ */ - /* Unmute the AIF1DAC1 */ - val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); - val &= ~(WM8994_AIF1DAC1_MUTE_MASK); - val |= WM8994_AIF1DAC1_UNMUTE; - wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); + u16 nreadservo4val = 0; + u16 ncompensationresult = 0; + u16 ncompensationresultlow = 0; + u16 ncompensationresulthigh = 0; + u8 nservo4low = 0; + u8 nservo4high = 0; /* Enable the Timeslot0 to DAC1L */ val = wm8994_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING); @@ -1316,57 +1191,51 @@ void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) val |= WM8994_AIF1DAC1L_TO_DAC1L; wm8994_write(codec, WM8994_DAC1_LEFT_MIXER_ROUTING, val); - /* Disable end point for preventing pop up noise. */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK | - WM8994_SPKOUTL_ENA_MASK); - ret = wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); + /* Enable the Timeslot0 to DAC1R */ + val = wm8994_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_AIF1DAC1R_TO_DAC1R_MASK); + val |= WM8994_AIF1DAC1R_TO_DAC1R; + wm8994_write(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING, val); - /* ------------------ Speaker Path Settings ------------------ */ + val = wm8994_read(codec, WM8994_AIF1_DAC1_LEFT_VOLUME); + val &= ~(WM8994_AIF1DAC1L_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1L_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, val); - /* Speaker Volume Control */ - if (!wm8994->testmode_config_flag) { - /* Unmute the SPKMIXVOLUME */ - val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); - val &= ~(WM8994_SPKMIXL_VOL_MASK); - val |= TUNING_SPKMIXL_ATTEN; - wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); - val &= ~(WM8994_SPKMIXR_VOL_MASK); - wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); - val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | WM8994_SPKOUTL_VOL_MASK); - val |= (WM8994_SPKOUTL_MUTE_N | TUNING_MP3_SPKL_VOL); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); - val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | WM8994_SPKOUTR_VOL_MASK); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); - - val = wm8994_read(codec, WM8994_CLASSD); - val &= ~(WM8994_SPKOUTL_BOOST_MASK); - val |= TUNING_MP3_CLASSD_VOL << WM8994_SPKOUTL_BOOST_SHIFT; - wm8994_write(codec, WM8994_CLASSD, val); - - /* Unmute DAC1 left */ - val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); - val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); - val |= TUNING_DAC1L_VOL; - wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); + val = wm8994_read(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_AIF1DAC1R_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1R_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, val); - /* Unmute and volume ctrl RightDAC */ - val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); - val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); - val |= TUNING_DAC1R_VOL; - wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - } + /* Speaker Volume Control */ + val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); + val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | WM8994_SPKOUTL_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_SPKOUT_VU | WM8994_SPKOUTL_MUTE_N | + TUNING_RING_SPKL_VOL); + else + val |= (WM8994_SPKOUT_VU | WM8994_SPKOUTL_MUTE_N | + TUNING_MP3_SPKL_VOL); + wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); + + val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); + val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | WM8994_SPKOUTR_VOL_MASK); + wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); + + val = wm8994_read(codec, WM8994_CLASSD); + val &= ~(WM8994_SPKOUTL_BOOST_MASK); + if (wm8994->ringtone_active) + val |= TUNING_RING_CLASSD_VOL << + WM8994_SPKOUTL_BOOST_SHIFT; + else + val |= TUNING_MP3_CLASSD_VOL << + WM8994_SPKOUTL_BOOST_SHIFT; + wm8994_write(codec, WM8994_CLASSD, val); val = wm8994_read(codec, WM8994_SPKOUT_MIXERS); val &= ~(WM8994_SPKMIXL_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTR_MASK); + WM8994_SPKMIXR_TO_SPKOUTL_MASK | + WM8994_SPKMIXR_TO_SPKOUTR_MASK); val |= WM8994_SPKMIXL_TO_SPKOUTL; wm8994_write(codec, WM8994_SPKOUT_MIXERS, val); @@ -1376,28 +1245,7 @@ void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) val |= WM8994_DAC1L_TO_SPKMIXL; wm8994_write(codec, WM8994_SPEAKER_MIXER, val); - /* ------------------ Ear Path Settings ------------------ */ - - /* Enbale DAC1L to HPOUT1L path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | WM8994_DAC1L_TO_MIXOUTL_MASK); - val |= WM8994_DAC1L_TO_MIXOUTL; - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); - - /* Enbale DAC1R to HPOUT1R path */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | WM8994_DAC1R_TO_MIXOUTR_MASK); - val |= WM8994_DAC1R_TO_MIXOUTR; - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); - /* Configuring the Digital Paths */ - - /* Enable the Timeslot0 to DAC1R */ - val = wm8994_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING); - val &= ~(WM8994_AIF1DAC1R_TO_DAC1R_MASK); - val |= WM8994_AIF1DAC1R_TO_DAC1R; - wm8994_write(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING, val); - val = wm8994_read(codec, 0x102); val &= ~(0x0003); val = 0x0003; @@ -1413,16 +1261,31 @@ void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) val = 0x0000; wm8994_write(codec, 0x102, val); - val = wm8994_read(codec, 0x5D); - val &= ~(0x0002); - val = 0x0002; - wm8994_write(codec, 0x5D, val); - val = wm8994_read(codec, WM8994_CLASS_W_1); val &= ~(0x0005); val = 0x0005; wm8994_write(codec, WM8994_CLASS_W_1, val); + val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); + val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | WM8994_HPOUT1L_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | + TUNING_RING_DUAL_OUTPUTL_VOL); + else + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | + TUNING_MP3_DUAL_OUTPUTL_VOL); + wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); + + val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); + val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | WM8994_HPOUT1R_VOL_MASK); + if (wm8994->ringtone_active) + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | + TUNING_RING_DUAL_OUTPUTR_VOL); + else + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | + TUNING_MP3_DUAL_OUTPUTR_VOL); + wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); + /* DC Servo Series Count */ val = 0x03E0; wm8994_write(codec, WM8994_DC_SERVO_2, val); @@ -1431,20 +1294,50 @@ void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK | WM8994_SPKOUTL_ENA_MASK); - val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | WM8994_HPOUT1R_ENA | - WM8994_HPOUT1L_ENA | WM8994_SPKOUTL_ENA); + val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | + WM8994_HPOUT1R_ENA | WM8994_HPOUT1L_ENA | + WM8994_SPKOUTL_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); val = (WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY); wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); /* Enable Charge Pump */ + /* this is from wolfson */ val = wm8994_read(codec, WM8994_CHARGE_PUMP_1); - val &= ~WM8994_CP_ENA_MASK; + val &= ~WM8994_CP_ENA_MASK ; val |= WM8994_CP_ENA | WM8994_CP_ENA_DEFAULT; wm8994_write(codec, WM8994_CHARGE_PUMP_1, val); - msleep(20); + msleep(5); + + /* Enable DAC1 and DAC2 and the Timeslot0 for AIF1 */ + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_5); + val &= ~(WM8994_DAC1R_ENA_MASK | WM8994_DAC1L_ENA_MASK | + WM8994_AIF1DAC1R_ENA_MASK | WM8994_AIF1DAC1L_ENA_MASK); + val |= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | + WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, val); + + /* Enbale DAC1L to HPOUT1L path */ + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); + val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | WM8994_DAC1L_TO_MIXOUTL_MASK); + val |= WM8994_DAC1L_TO_MIXOUTL; + wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); + + /* Enbale DAC1R to HPOUT1R path */ + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); + val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | WM8994_DAC1R_TO_MIXOUTR_MASK); + val |= WM8994_DAC1R_TO_MIXOUTR; + wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); + + /* Enbale bias,vmid, hp left and right and Left speaker */ + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); + val &= ~(WM8994_MIXOUTLVOL_ENA_MASK | WM8994_MIXOUTRVOL_ENA_MASK | + WM8994_MIXOUTL_ENA_MASK | WM8994_MIXOUTR_ENA_MASK | + WM8994_SPKLVOL_ENA_MASK); + val |= (WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA | WM8994_SPKLVOL_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val); /* DC Servo */ val = (WM8994_DCS_TRIG_SERIES_1 | WM8994_DCS_TRIG_SERIES_0 | @@ -1453,109 +1346,204 @@ void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec) msleep(160); - nReadServo4Val = wm8994_read(codec, WM8994_DC_SERVO_4); - nServo4Low = (u8) (nReadServo4Val & 0xff); - nServo4High = (u8) ((nReadServo4Val >> 8) & 0xff); + nreadservo4val = wm8994_read(codec, WM8994_DC_SERVO_4); + nservo4low = (signed char)(nreadservo4val & 0xff); + nservo4high = (signed char)((nreadservo4val>>8) & 0xff); - nCompensationResultLow = ((u16) nServo4Low - 4) & 0x00ff; - nCompensationResultHigh = (((u16) nServo4High - 4) << 8) & 0xff00; - ncompensationResult = nCompensationResultLow | nCompensationResultHigh; - wm8994_write(codec, WM8994_DC_SERVO_4, ncompensationResult); + ncompensationresultlow = ((signed short)nservo4low - 5) & 0x00ff; + ncompensationresulthigh = ((signed short)(nservo4high - 5)<<8) & 0xff00; + ncompensationresult = ncompensationresultlow|ncompensationresulthigh; + wm8994_write(codec, WM8994_DC_SERVO_4, ncompensationresult); val = (WM8994_DCS_TRIG_DAC_WR_1 | WM8994_DCS_TRIG_DAC_WR_0 | WM8994_DCS_ENA_CHAN_1 | WM8994_DCS_ENA_CHAN_0); wm8994_write(codec, WM8994_DC_SERVO_1, val); - msleep(20); + msleep(15); - /* Intermediate HP settings */ val = wm8994_read(codec, WM8994_ANALOGUE_HP_1); val &= ~(WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1R_OUTP_MASK | - WM8994_HPOUT1R_RMV_SHORT_MASK | WM8994_HPOUT1L_DLY_MASK | + WM8994_HPOUT1R_RMV_SHORT_MASK | WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK | WM8994_HPOUT1L_RMV_SHORT_MASK); val |= (WM8994_HPOUT1L_RMV_SHORT | WM8994_HPOUT1L_OUTP | WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_RMV_SHORT | WM8994_HPOUT1R_OUTP | WM8994_HPOUT1R_DLY); wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); - /* Enable DAC1 and DAC2 and the Timeslot0 for AIF1 */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); + val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); + val |= TUNING_DAC1L_VOL; + wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); + + val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); + val |= TUNING_DAC1R_VOL; + wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); + val &= ~(WM8994_AIF1DAC1_MUTE_MASK | WM8994_AIF1DAC1_MONO_MASK); + val |= (WM8994_AIF1DAC1_UNMUTE | WM8994_AIF1DAC1_MONO); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); + + val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); + val &= ~(WM8994_SPKMIXL_VOL_MASK); + val |= TUNING_SPKMIXL_ATTEN; + wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); + + val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); + val &= ~(WM8994_SPKMIXR_VOL_MASK); + wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); + +} + +void wm8994_set_playback_bluetooth(struct snd_soc_codec *codec) +{ + u16 val; + + DEBUG_LOG("BT Playback Path for Voice Command\n"); + + wm8994_set_voicecall_common_setting(codec); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); + val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK); + val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); + + wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, 0x0000); + + wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, 0x0000); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_4); + val &= ~(WM8994_AIF2ADCL_ENA_MASK | WM8994_AIF2ADCR_ENA_MASK); + val |= (WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, val); + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_5); - val &= ~(WM8994_DAC1R_ENA_MASK | WM8994_DAC1L_ENA_MASK | - WM8994_AIF1DAC1R_ENA_MASK | WM8994_AIF1DAC1L_ENA_MASK); - val |= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | + val &= ~(WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK | + WM8994_AIF1DAC1L_ENA_MASK | WM8994_AIF1DAC1R_ENA_MASK | + WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK); + val |= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | + WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, val); - /* Enbale bias,vmid, hp left and right and Left speaker */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); - val &= ~(WM8994_MIXOUTLVOL_ENA_MASK | WM8994_MIXOUTRVOL_ENA_MASK | - WM8994_MIXOUTL_ENA_MASK | WM8994_MIXOUTR_ENA_MASK | - WM8994_SPKLVOL_ENA_MASK); - val |= (WM8994_MIXOUTLVOL_ENA | WM8994_MIXOUTRVOL_ENA | - WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA | - WM8994_SPKLVOL_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val); + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_6); + val &= ~(WM8994_AIF3_ADCDAT_SRC_MASK); + val |= (0x0001 << WM8994_AIF3_ADCDAT_SRC_SHIFT); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, val); - if (!wm8994->testmode_config_flag) { - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_5); - val &= ~(WM8994_DACL_MIXOUTL_VOL_MASK); - val |= TUNING_EAR_OUTMIX5_VOL << WM8994_DACL_MIXOUTL_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_5, val); + /* Un-Mute*/ + val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); + val &= ~(WM8994_AIF1DAC1_MUTE_MASK | WM8994_AIF1DAC1_MONO_MASK); + val |= (WM8994_AIF1DAC1_UNMUTE); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_6); - val &= ~(WM8994_DACR_MIXOUTR_VOL_MASK); - val |= TUNING_EAR_OUTMIX6_VOL << WM8994_DACR_MIXOUTR_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_6, val); + /* Mixer Routing*/ + val = wm8994_read(codec, WM8994_DAC2_LEFT_MIXER_ROUTING); + val &= ~(WM8994_AIF1DAC1L_TO_DAC2L_MASK); + val |= (WM8994_AIF1DAC1L_TO_DAC2L); + wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, val); - val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | WM8994_HPOUT1L_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | - TUNING_DUAL_OUTPUTL_VOL); - wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); + val = wm8994_read(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_AIF1DAC1R_TO_DAC2R_MASK); + val |= (WM8994_AIF1DAC1R_TO_DAC2R); + wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, val); - val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | WM8994_HPOUT1R_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | - TUNING_DUAL_OUTPUTR_VOL); - wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); - } + /* Volume*/ + wm8994_write(codec, WM8994_DAC2_LEFT_VOLUME, 0x01C0); + wm8994_write(codec, WM8994_DAC2_RIGHT_VOLUME, 0x01C0); + + wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); + + wm8994_write(codec, WM8994_OVERSAMPLING, 0X0000); + /* GPIO Configuration*/ + wm8994_write(codec, WM8994_GPIO_8, WM8994_GP8_DIR | WM8994_GP8_DB); + wm8994_write(codec, WM8994_GPIO_9, WM8994_GP9_DB); + wm8994_write(codec, WM8994_GPIO_10, WM8994_GP10_DB); + wm8994_write(codec, WM8994_GPIO_11, WM8994_GP11_DB); } void wm8994_set_voicecall_common_setting(struct snd_soc_codec *codec) { - /*GPIO Configuration */ + int val; + + /* GPIO Configuration */ wm8994_write(codec, WM8994_GPIO_1, 0xA101); wm8994_write(codec, WM8994_GPIO_2, 0x8100); - wm8994_write(codec, WM8994_GPIO_3, 0x8100); - wm8994_write(codec, WM8994_GPIO_4, 0x8100); + wm8994_write(codec, WM8994_GPIO_3, 0x0100); + wm8994_write(codec, WM8994_GPIO_4, 0x0100); wm8994_write(codec, WM8994_GPIO_5, 0x8100); wm8994_write(codec, WM8994_GPIO_6, 0xA101); wm8994_write(codec, WM8994_GPIO_7, 0x0100); + wm8994_write(codec, WM8994_GPIO_8, 0xA101); + wm8994_write(codec, WM8994_GPIO_9, 0xA101); + wm8994_write(codec, WM8994_GPIO_10, 0xA101); + wm8994_write(codec, WM8994_GPIO_11, 0xA101); - /*FLL2 Setting */ wm8994_write(codec, WM8994_FLL2_CONTROL_2, 0x2F00); wm8994_write(codec, WM8994_FLL2_CONTROL_3, 0x3126); wm8994_write(codec, WM8994_FLL2_CONTROL_4, 0x0100); wm8994_write(codec, WM8994_FLL2_CONTROL_5, 0x0C88); - wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); wm8994_write(codec, WM8994_FLL2_CONTROL_1, - WM8994_FLL2_FRACN_ENA | WM8994_FLL2_ENA); - - /*Clocking */ - wm8994_write(codec, WM8994_CLOCKING_1, WM8994_DSP_FS2CLK_ENA | - WM8994_DSP_FSINTCLK_ENA | WM8994_SYSCLK_SRC); - wm8994_write(codec, WM8994_CLOCKING_2, 0x1 << WM8994_TOCLK_DIV_SHIFT | - 0x6 << WM8994_DBCLK_DIV_SHIFT | - 0x3 << WM8994_OPCLK_DIV_SHIFT); + WM8994_FLL2_FRACN_ENA | WM8994_FLL2_ENA); + + val = wm8994_read(codec, WM8994_AIF2_CLOCKING_1); + if (!(val & WM8994_AIF2CLK_ENA)) + wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0018); + wm8994_write(codec, WM8994_AIF2_RATE, 0x3 << WM8994_AIF2CLK_RATE_SHIFT); - /* AIF2 Interface */ + /* AIF2 Interface - PCM Stereo mode */ + /* Left Justified, BCLK invert, LRCLK Invert */ wm8994_write(codec, WM8994_AIF2_CONTROL_1, - WM8994_AIF2ADCR_SRC | WM8994_AIF2_BCLK_INV | - WM8994_AIF2_LRCLK_INV | 0x1 << WM8994_AIF2_FMT_SHIFT); + WM8994_AIF2ADCR_SRC | WM8994_AIF2_BCLK_INV | 0x18); + + wm8994_write(codec, WM8994_AIF2_BCLK, 0x70); wm8994_write(codec, WM8994_AIF2_CONTROL_2, 0x0000); - wm8994_write(codec, WM8994_AIF2_MASTER_SLAVE, WM8994_AIF2_MSTR); + wm8994_write(codec, WM8994_AIF2_MASTER_SLAVE, WM8994_AIF2_MSTR | + WM8994_AIF2_CLK_FRC | WM8994_AIF2_LRCLK_FRC); + + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_5); + val &= ~(WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK | + WM8994_AIF1DAC1L_ENA_MASK | WM8994_AIF1DAC1R_ENA_MASK | + WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK); + val |= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | + WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | + WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, val); + + /* Clocking */ + val = wm8994_read(codec, WM8994_CLOCKING_1); + val |= (WM8994_DSP_FS2CLK_ENA); + wm8994_write(codec, WM8994_CLOCKING_1, val); + + wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, 0x0); + + /* AIF1 & AIF2 Output is connected to DAC1 */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING); + val &= ~(WM8994_AIF1DAC1L_TO_DAC1L_MASK | + WM8994_AIF2DACL_TO_DAC1L_MASK); + val |= (WM8994_AIF1DAC1L_TO_DAC1L | WM8994_AIF2DACL_TO_DAC1L); + wm8994_write(codec, WM8994_DAC1_LEFT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING); + val &= ~(WM8994_AIF1DAC1R_TO_DAC1R_MASK | + WM8994_AIF2DACR_TO_DAC1R_MASK); + val |= (WM8994_AIF1DAC1R_TO_DAC1R | WM8994_AIF2DACR_TO_DAC1R); + wm8994_write(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_LEFT_VOLUME); + val &= ~(WM8994_AIF1DAC1L_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1L_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, val); + + val = wm8994_read(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_AIF1DAC1R_VOL_MASK); + val |= (WM8994_AIF1DAC1_VU | TUNING_DAC1R_VOL); + wm8994_write(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, val); + + wm8994_write(codec, 0x6, 0x0); } void wm8994_set_voicecall_receiver(struct snd_soc_codec *codec) @@ -1566,26 +1554,22 @@ void wm8994_set_voicecall_receiver(struct snd_soc_codec *codec) DEBUG_LOG(""); - audio_ctrl_mic_bias_gpio(1); + audio_ctrl_mic_bias_gpio(wm8994->pdata, 1); + + wm8994_set_voicecall_common_setting(codec); wm8994_write(codec, WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_DEFAULT); - /* Analogue Input Configuration -Main MIC */ wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, - WM8994_TSHUT_ENA | WM8994_TSHUT_OPDIS | WM8994_MIXINL_ENA | - WM8994_IN1L_ENA); + WM8994_TSHUT_ENA | WM8994_TSHUT_OPDIS | WM8994_MIXINL_ENA | + WM8994_IN1L_ENA); wm8994_write(codec, WM8994_INPUT_MIXER_2, WM8994_IN1LP_TO_IN1L | WM8994_IN1LN_TO_IN1L); /* Digital Path Enables and Unmutes */ wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, - WM8994_AIF2ADCL_ENA | WM8994_ADCL_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, - WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | - WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | - WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, 0x0000); + WM8994_AIF2ADCL_ENA | WM8994_ADCL_ENA); wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, 0x0000); wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x0000); @@ -1594,90 +1578,80 @@ void wm8994_set_voicecall_receiver(struct snd_soc_codec *codec) wm8994_write(codec, WM8994_DAC2_LEFT_VOLUME, 0x01C0); wm8994_write(codec, WM8994_DAC2_RIGHT_VOLUME, 0x01C0); - /* AIF1 & AIF2 Output is connected to DAC1 */ - wm8994_write(codec, WM8994_DAC1_LEFT_MIXER_ROUTING, - WM8994_AIF2DACL_TO_DAC1L | WM8994_AIF1DAC1L_TO_DAC1L); - wm8994_write(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING, - WM8994_AIF2DACR_TO_DAC1R | WM8994_AIF1DAC1R_TO_DAC1R); - /* Tx -> AIF2 Path */ wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, - WM8994_ADC1_TO_DAC2L); + WM8994_ADC1_TO_DAC2L); wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, - WM8994_ADC1_TO_DAC2R); - - if (!wm8994->testmode_config_flag) { - /* Unmute IN1L PGA, update volume */ - val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); - val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); - val |= (WM8994_IN1L_VU | TUNING_CALL_RCV_INPUTMIX_VOL); - wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, val); - - /* Unmute the PGA */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_3); - val &= ~(WM8994_IN1L_TO_MIXINL_MASK | - WM8994_IN1L_MIXINL_VOL_MASK | - WM8994_MIXOUTL_MIXINL_VOL_MASK); - val |= (WM8994_IN1L_TO_MIXINL | WM8994_IN1L_MIXINL_VOL); - wm8994_write(codec, WM8994_INPUT_MIXER_3, val); - - /* Volume Control - Output */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_5); - val &= ~(WM8994_DACL_MIXOUTL_VOL_MASK); - val |= TUNING_RCV_OUTMIX5_VOL << WM8994_DACL_MIXOUTL_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_5, val); + WM8994_ADC1_TO_DAC2R); - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_6); - val &= ~(WM8994_DACR_MIXOUTR_VOL_MASK); - val |= TUNING_RCV_OUTMIX6_VOL << WM8994_DACR_MIXOUTR_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_6, val); + wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); - val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | - TUNING_RCV_OPGAL_VOL); - wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); + /* Unmute IN1L PGA, update volume */ + val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); + val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); + val |= (WM8994_IN1L_VU | TUNING_CALL_RCV_INPUTMIX_VOL); + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, val); + + /* Unmute the PGA */ + val = wm8994_read(codec, WM8994_INPUT_MIXER_3); + val &= ~(WM8994_IN1L_TO_MIXINL_MASK | + WM8994_IN1L_MIXINL_VOL_MASK | + WM8994_MIXOUTL_MIXINL_VOL_MASK); + val |= (WM8994_IN1L_TO_MIXINL | TUNING_CALL_RCV_MIXER_VOL); + wm8994_write(codec, WM8994_INPUT_MIXER_3, val); + + /* Volume Control - Output */ + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_5); + val &= ~(WM8994_DACL_MIXOUTL_VOL_MASK); + val |= TUNING_RCV_OUTMIX5_VOL << WM8994_DACL_MIXOUTL_VOL_SHIFT; + wm8994_write(codec, WM8994_OUTPUT_MIXER_5, val); + + val = wm8994_read(codec, WM8994_OUTPUT_MIXER_6); + val &= ~(WM8994_DACR_MIXOUTR_VOL_MASK); + val |= TUNING_RCV_OUTMIX6_VOL << WM8994_DACR_MIXOUTR_VOL_SHIFT; + wm8994_write(codec, WM8994_OUTPUT_MIXER_6, val); + + val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | + TUNING_RCV_OPGAL_VOL); + wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); + + val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | + TUNING_RCV_OPGAR_VOL); + wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); + + val = wm8994_read(codec, WM8994_HPOUT2_VOLUME); + val &= ~(WM8994_HPOUT2_MUTE_MASK | WM8994_HPOUT2_VOL_MASK); + val |= TUNING_HPOUT2_VOL << WM8994_HPOUT2_VOL_SHIFT; + wm8994_write(codec, WM8994_HPOUT2_VOLUME, val); - val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | - TUNING_RCV_OPGAR_VOL); - wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); - - val = wm8994_read(codec, WM8994_HPOUT2_VOLUME); - val &= ~(WM8994_HPOUT2_MUTE_MASK | WM8994_HPOUT2_VOL_MASK); - val |= TUNING_HPOUT2_VOL << WM8994_HPOUT2_VOL_SHIFT; - wm8994_write(codec, WM8994_HPOUT2_VOLUME, val); + /* Unmute DAC1 left */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); + val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); + val |= TUNING_DAC1L_VOL; + wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); - /* Unmute DAC1 left */ - val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); - val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); - val |= TUNING_DAC1L_VOL; - wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); + /* Unmute and volume ctrl RightDAC */ + val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); + val |= TUNING_DAC1R_VOL; + wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - /* Unmute and volume ctrl RightDAC */ - val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); - val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); - val |= TUNING_DAC1R_VOL; /* 0 db volume */ - wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - } /* Output Mixing */ wm8994_write(codec, WM8994_OUTPUT_MIXER_1, WM8994_DAC1L_TO_MIXOUTL); wm8994_write(codec, WM8994_OUTPUT_MIXER_2, WM8994_DAC1R_TO_MIXOUTR); - wm8994_set_voicecall_common_setting(codec); - /* Analogue Output Configuration */ wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, - WM8994_MIXOUTLVOL_ENA | WM8994_MIXOUTRVOL_ENA | - WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA); - wm8994_write(codec, WM8994_HPOUT2_MIXER, - WM8994_MIXOUTLVOL_TO_HPOUT2 | WM8994_MIXOUTRVOL_TO_HPOUT2); + WM8994_MIXOUTLVOL_ENA | WM8994_MIXOUTRVOL_ENA | + WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA); + wm8994_write(codec, WM8994_HPOUT2_MIXER, WM8994_MIXOUTLVOL_TO_HPOUT2 | + WM8994_MIXOUTRVOL_TO_HPOUT2); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, - WM8994_HPOUT2_ENA | WM8994_VMID_SEL_NORMAL | - WM8994_BIAS_ENA); - - /* wm8994_write(codec, WM8994_INPUT_MIXER_4, 0x0000 ); */ + WM8994_HPOUT2_ENA | WM8994_VMID_SEL_NORMAL | WM8994_BIAS_ENA); } void wm8994_set_voicecall_headset(struct snd_soc_codec *codec) @@ -1686,642 +1660,341 @@ void wm8994_set_voicecall_headset(struct snd_soc_codec *codec) int val; - DEBUG_LOG(""); - - audio_ctrl_mic_bias_gpio(1); + u16 testreturn1 = 0; + u16 testreturn2 = 0; + u16 testlow1 = 0; + u16 testhigh1 = 0; + u8 testlow = 0; + u8 testhigh = 0; - /*DCS*/ wm8994_write(codec, WM8994_DC_SERVO_4, 0x9C9C); - wm8994_write(codec, WM8994_DC_SERVO_2, 0x054E); - wm8994_write(codec, WM8994_DC_SERVO_1, 0x300f); - wm8994_write(codec, WM8994_DC_SERVO_ANA_1, 0x0080); - wm8994_write(codec, WM8994_DC_SERVO_ANA_2, 0x0080); - - /* Power - UP seqeunce- COLD Start Up */ - wm8994_write(codec, WM8994_ANTIPOP_2, 0x006C); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, 0x0003); - wm8994_write(codec, WM8994_DC_SERVO_ANA_1, 0x00FF); - wm8994_write(codec, WM8994_DC_SERVO_ANA_2, 0x00FF); - wm8994_write(codec, WM8994_CHARGE_PUMP_1, 0x9F25); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, 0x0313); - wm8994_write(codec, WM8994_ANALOGUE_HP_1, 0x0022); - wm8994_write(codec, WM8994_DC_SERVO_1, 0x333F); - wm8994_write(codec, WM8994_ANALOGUE_HP_1, 0x00EE); - - /*Analogue Input Configuration */ - wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, 0x6110); - wm8994_write(codec, WM8994_INPUT_MIXER_2, 0x0003); + DEBUG_LOG(""); - /*Analogue Output Configuration */ - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, 0x0100); - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, 0x0100); - wm8994_write(codec, WM8994_CHARGE_PUMP_1, 0x9F25); - wm8994_write(codec, WM8994_ANALOGUE_HP_1, 0x00EE); + audio_ctrl_mic_bias_gpio(wm8994->pdata, 1); - /*Digital Path Enables and Unmutes */ - wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, 0x3003); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, 0x3303); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, 0x0000); - wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, 0x0000); - wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x0000); - wm8994_write(codec, WM8994_DAC1_LEFT_MIXER_ROUTING, 0x0005); - wm8994_write(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING, 0x0005); - wm8994_write(codec, WM8994_DAC2_LEFT_VOLUME, 0x01C0); - wm8994_write(codec, WM8994_DAC2_RIGHT_VOLUME, 0x01C0); + wm8994_set_voicecall_common_setting(codec); + /* Digital Path Enables and Unmutes */ if (wm8994->hw_version == 3) { /* H/W Rev D */ wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, - WM8994_ADC2_TO_DAC2L | WM8994_ADC1_TO_DAC2L); - wm8994_write(codec, WM8994_DAC2_MIXER_VOLUMES, 0x018C); + WM8994_ADC2_TO_DAC2L); + wm8994_write(codec, WM8994_DAC2_MIXER_VOLUMES, 0x0180); wm8994_write(codec, WM8994_SIDETONE, 0x01C0); - } else { /* H/W Rev B */ + } else { /* H/W Rev B */ wm8994_write(codec, WM8994_DAC2_MIXER_VOLUMES, 0x000C); wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, - WM8994_ADC1_TO_DAC2L); + WM8994_ADC1_TO_DAC2L); wm8994_write(codec, WM8994_SIDETONE, 0x01C1); } - /* Tx -> AIF2 Path */ - wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, - WM8994_ADC1_TO_DAC2R); - - wm8994_set_voicecall_common_setting(codec); - - /* Unmute */ - if (!wm8994->testmode_config_flag) { - val = wm8994_read(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME); - val &= ~(WM8994_IN1R_MUTE_MASK | WM8994_IN1R_VOL_MASK); - val |= (WM8994_IN1R_VU | TUNING_CALL_EAR_INPUTMIX_VOL); - wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, val); - - /* unmute right pga, set volume */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_4); - val &= ~(WM8994_IN1R_TO_MIXINR_MASK | - WM8994_IN1R_MIXINR_VOL_MASK | - WM8994_MIXOUTR_MIXINR_VOL_MASK); - val |= (WM8994_IN1R_TO_MIXINR); /* 0db */ - wm8994_write(codec, WM8994_INPUT_MIXER_4, val); - - /* Volume Control - Output */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_5); - val &= ~(WM8994_DACL_MIXOUTL_VOL_MASK); - val |= TUNING_EAR_OUTMIX5_VOL << WM8994_DACL_MIXOUTL_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_5, val); - - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_6); - val &= ~(WM8994_DACR_MIXOUTR_VOL_MASK); - val |= TUNING_EAR_OUTMIX6_VOL << WM8994_DACR_MIXOUTR_VOL_SHIFT; - wm8994_write(codec, WM8994_OUTPUT_MIXER_6, val); - - val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | WM8994_HPOUT1L_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | - TUNING_CALL_OUTPUTL_VOL); - wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); - - val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | WM8994_HPOUT1R_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | - TUNING_CALL_OUTPUTR_VOL); - wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); - - val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | - TUNING_CALL_OPGAL_VOL); - wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); - - val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | - TUNING_CALL_OPGAR_VOL); - wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); - - /* Unmute DAC1 left */ - val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); - val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); - val |= TUNING_DAC1L_VOL; - wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); - - /* Unmute and volume ctrl RightDAC */ - val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); - val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); - val |= TUNING_DAC1R_VOL; - wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - } - - /*DCS*/ - wm8994_write(codec, WM8994_DC_SERVO_4, 0x9C9C); - wm8994_write(codec, WM8994_DC_SERVO_2, 0x054E); - wm8994_write(codec, WM8994_DC_SERVO_1, 0x300f); - wm8994_write(codec, WM8994_DC_SERVO_ANA_1, 0x0080); - wm8994_write(codec, WM8994_DC_SERVO_ANA_2, 0x0080); -} - -void wm8994_set_voicecall_speaker(struct snd_soc_codec *codec) -{ - struct wm8994_priv *wm8994 = codec->drvdata; - - int val; - - DEBUG_LOG(""); - - audio_ctrl_mic_bias_gpio(1); - - wm8994_write(codec, 0x39, 0x006C); - /*Analogue Configuration */ - wm8994_write(codec, 0x01, 0x0003); - /*Analogue Input Configuration */ - wm8994_write(codec, 0x02, 0x6240); + /* Analogue Input Configuration */ + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_2); + val &= ~(WM8994_TSHUT_ENA_MASK | WM8994_TSHUT_OPDIS_MASK | + WM8994_MIXINR_ENA_MASK | WM8994_IN1R_ENA_MASK); + val |= (WM8994_TSHUT_ENA | WM8994_TSHUT_OPDIS | + WM8994_MIXINR_ENA | WM8994_IN1R_ENA); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, 0x6110); - /*Analogue Output Configuration */ - wm8994_write(codec, 0x03, 0x0300); + val = wm8994_read(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME); + val &= ~(WM8994_IN1R_MUTE_MASK | WM8994_IN1R_VOL_MASK); + val |= (WM8994_IN1R_VU | TUNING_CALL_EAR_INPUTMIX_VOL); + wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, val); - wm8994_write(codec, WM8994_INPUT_MIXER_2, - WM8994_IN1LP_TO_IN1L | WM8994_IN1LN_TO_IN1L); + val = wm8994_read(codec, WM8994_INPUT_MIXER_4); + val &= ~(WM8994_IN1R_TO_MIXINR_MASK | + WM8994_IN1R_MIXINR_VOL_MASK | + WM8994_MIXOUTR_MIXINR_VOL_MASK); + val |= (WM8994_IN1R_TO_MIXINR); + wm8994_write(codec, WM8994_INPUT_MIXER_4, val); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, - WM8994_AIF2ADCL_ENA | WM8994_ADCL_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, - WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | - WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | - WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, 0x0000); - - if (!wm8994->testmode_config_flag) { - /* Volume Control - Input */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_3); - val &= ~(WM8994_IN1L_TO_MIXINL_MASK | - WM8994_IN1L_MIXINL_VOL_MASK | - WM8994_MIXOUTL_MIXINL_VOL_MASK); - val |= (WM8994_IN1L_TO_MIXINL); - wm8994_write(codec, WM8994_INPUT_MIXER_3, val); + val = wm8994_read(codec, WM8994_INPUT_MIXER_2); + val &= ~(WM8994_IN1RP_TO_IN1R_MASK | WM8994_IN1RN_TO_IN1R_MASK); + val |= (WM8994_IN1RP_TO_IN1R | WM8994_IN1RN_TO_IN1R); + wm8994_write(codec, WM8994_INPUT_MIXER_2, 0x0003); - val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); - val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); - val |= (WM8994_IN1L_VU | TUNING_CALL_SPK_INPUTMIX_VOL); - wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, val); - - /* Volume Control - Output */ - /* Unmute the SPKMIXVOLUME */ - val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); - val &= ~(WM8994_SPKMIXL_VOL_MASK); - val |= TUNING_SPKMIXL_ATTEN; - wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); - val &= ~(WM8994_SPKMIXR_VOL_MASK); - val |= TUNING_SPKMIXR_ATTEN; - wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); - val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | WM8994_SPKOUTL_VOL_MASK); - val |= (WM8994_SPKOUT_VU | WM8994_SPKOUTL_MUTE_N | - TUNING_CALL_SPKL_VOL); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); + /* Unmute*/ + val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | + TUNING_CALL_OPGAL_VOL); + wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); - val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | WM8994_SPKOUTR_VOL_MASK); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); + val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); + val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); + val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | + TUNING_CALL_OPGAR_VOL); + wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); - val = wm8994_read(codec, WM8994_CLASSD); - val &= ~(WM8994_SPKOUTL_BOOST_MASK); - val |= TUNING_CALL_CLASSD_VOL << WM8994_SPKOUTL_BOOST_SHIFT; - wm8994_write(codec, WM8994_CLASSD, val); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, 0x2001); - /* Unmute DAC1 left */ - val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); - val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); - val |= TUNING_DAC1L_VOL; - wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); + val = wm8994_read(codec, 0x102); + val &= ~(0x0003); + val = 0x0003; + wm8994_write(codec, 0x102, val); - /* Unmute and volume ctrl RightDAC */ - val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); - val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); - val |= TUNING_DAC1R_VOL; - wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - } + val = wm8994_read(codec, 0x56); + val &= ~(0x0003); + val = 0x0003; + wm8994_write(codec, 0x56, val); - val = wm8994_read(codec, WM8994_SPKOUT_MIXERS); - val &= ~(WM8994_SPKMIXL_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTR_MASK); - val |= WM8994_SPKMIXL_TO_SPKOUTL; - wm8994_write(codec, WM8994_SPKOUT_MIXERS, val); + val = wm8994_read(codec, 0x102); + val &= ~(0x0000); + val = 0x0000; + wm8994_write(codec, 0x102, val); - wm8994_write(codec, 0x36, 0x0003); - /* Digital Path Enables and Unmutes */ - wm8994_write(codec, 0x520, 0x0000); - wm8994_write(codec, 0x601, 0x0005); - wm8994_write(codec, 0x602, 0x0005); - wm8994_write(codec, 0x603, 0x000C); - wm8994_write(codec, 0x612, 0x01C0); - wm8994_write(codec, 0x613, 0x01C0); - wm8994_write(codec, 0x620, 0x0000); - wm8994_write(codec, 0x621, 0x01C0); + val = wm8994_read(codec, WM8994_CLASS_W_1); + val &= ~(0x0005); + val |= 0x0005; + wm8994_write(codec, WM8994_CLASS_W_1, val); - /* Tx -> AIF2 Path */ - wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, - WM8994_ADC1_TO_DAC2L); - wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, - WM8994_ADC1_TO_DAC2R); + val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); + val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | WM8994_HPOUT1L_VOL_MASK); + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | + TUNING_CALL_OUTPUTL_VOL); + wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); - wm8994_set_voicecall_common_setting(codec); + val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); + val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | WM8994_HPOUT1R_VOL_MASK); + val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | + TUNING_CALL_OUTPUTR_VOL); + wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, - WM8994_SPKOUTL_ENA | WM8994_VMID_SEL_NORMAL | - WM8994_BIAS_ENA); -} + val = wm8994_read(codec, WM8994_DC_SERVO_2); + val &= ~(0x03E0); + val = 0x03E0; + wm8994_write(codec, WM8994_DC_SERVO_2, val); -void wm8994_set_voicecall_bluetooth(struct snd_soc_codec *codec) -{ - DEBUG_LOG(""); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, 0x0303); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, 0x0007); - msleep(50); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, 0x0003); - - /*Digital Path Enables and Unmutes */ - wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, 0x00); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, 0x00); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, 0x3000); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_5, - WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | - WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA | - WM8994_DAC2L_ENA | WM8994_DAC2R_ENA); - /* - * for BT DTMF Play - * Rx Path: AIF2ADCDAT2 select - * CP(CALL) Path:GPIO5/DACDAT2 select - * AP(DTMF) Path: DACDAT1 select - * Tx Path: GPIO8/DACDAT3 select - */ - wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, - 0x0003 << WM8994_AIF2_ADCDAT_SRC_SHIFT); + wm8994_write(codec, WM8994_ANALOGUE_HP_1, 0x0022); + wm8994_write(codec, WM8994_CHARGE_PUMP_1, 0x9F25); - wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x00); + msleep(5); - wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, - WM8994_AIF2DACL_TO_DAC2L | WM8994_AIF1DAC1L_TO_DAC2L); - wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, - WM8994_AIF2DACR_TO_DAC2R | WM8994_AIF1DAC1R_TO_DAC2R); + /* Analogue Output Configuration */ + wm8994_write(codec, WM8994_OUTPUT_MIXER_1, 0x0001); + wm8994_write(codec, WM8994_OUTPUT_MIXER_2, 0x0001); - wm8994_write(codec, WM8994_DAC2_LEFT_VOLUME, 0x1C0); - wm8994_write(codec, WM8994_DAC2_RIGHT_VOLUME, 0x1C0); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, 0x0030); - /*Clocking */ - wm8994_write(codec, WM8994_CLOCKING_1, - WM8994_DSP_FS1CLK_ENA | WM8994_DSP_FS2CLK_ENA | - WM8994_DSP_FSINTCLK_ENA); - wm8994_write(codec, WM8994_AIF2_RATE, - 0x0003 << WM8994_AIF2CLK_RATE_SHIFT); + wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); - /*AIF1Interface */ - wm8994_write(codec, WM8994_AIF1_CONTROL_2, 0x0000); - wm8994_write(codec, WM8994_AIF1_MASTER_SLAVE, WM8994_AIF1_MSTR | - WM8994_AIF1_CLK_FRC | WM8994_AIF1_LRCLK_FRC); + wm8994_write(codec, WM8994_DC_SERVO_1, 0x303); - /*AIF2 Interface */ - wm8994_write(codec, WM8994_AIF2_CONTROL_2, 0x0000); - wm8994_write(codec, WM8994_AIF2_MASTER_SLAVE, WM8994_AIF2_MSTR | - WM8994_AIF2_CLK_FRC | WM8994_AIF2_LRCLK_FRC); - wm8994_write(codec, WM8994_AIF2_CONTROL_1, - WM8994_AIF2ADCR_SRC | WM8994_AIF2_BCLK_INV | - WM8994_AIF2_LRCLK_INV | 0x1 << WM8994_AIF2_FMT_SHIFT); + msleep(160); - wm8994_write(codec, WM8994_OVERSAMPLING, 0X0000); + testreturn1 = wm8994_read(codec, WM8994_DC_SERVO_4); - /*FLL2 Setting */ - wm8994_write(codec, WM8994_FLL2_CONTROL_2, 0x2F00); - wm8994_write(codec, WM8994_FLL2_CONTROL_3, 0x3126); - wm8994_write(codec, WM8994_FLL2_CONTROL_4, 0x0100); - wm8994_write(codec, WM8994_FLL2_CONTROL_5, 0x0C88); - wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); - wm8994_write(codec, WM8994_FLL2_CONTROL_1, - WM8994_FLL2_FRACN_ENA | WM8994_FLL2_ENA); + testlow = (signed char)(testreturn1 & 0xff); + testhigh = (signed char)((testreturn1>>8) & 0xff); - /*GPIO Configuration */ - wm8994_write(codec, WM8994_GPIO_1, 0xA101); - wm8994_write(codec, WM8994_GPIO_3, WM8994_GP3_DIR | WM8994_GP3_DB); - wm8994_write(codec, WM8994_GPIO_4, WM8994_GP4_DIR | WM8994_GP4_DB); - wm8994_write(codec, WM8994_GPIO_5, WM8994_GP5_DIR | WM8994_GP5_DB); - wm8994_write(codec, WM8994_GPIO_6, - WM8994_GP6_DIR | WM8994_GP6_PD | WM8994_GP6_DB | 0x1 << - WM8994_GP6_FN_SHIFT); - wm8994_write(codec, WM8994_GPIO_7, WM8994_GP7_DB); - wm8994_write(codec, WM8994_GPIO_8, WM8994_GP8_DIR | WM8994_GP8_DB); - wm8994_write(codec, WM8994_GPIO_9, WM8994_GP9_DB); - wm8994_write(codec, WM8994_GPIO_10, WM8994_GP10_DB); - wm8994_write(codec, WM8994_GPIO_11, WM8994_GP11_DB); -} + testlow1 = ((signed short)testlow - 5) & 0x00ff; + testhigh1 = (((signed short)(testhigh - 5)<<8) & 0xff00); + testreturn2 = testlow1|testhigh1; + wm8994_write(codec, WM8994_DC_SERVO_4, testreturn2); -void wm8994_set_fmradio_common(struct snd_soc_codec *codec) -{ - struct wm8994_priv *wm8994 = codec->drvdata; + val = wm8994_read(codec, WM8994_DC_SERVO_1); + val &= ~(0x000F); + val = 0x000F; + wm8994_write(codec, WM8994_DC_SERVO_1, val); - u16 val; + msleep(15); - val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_3_4_VOLUME); - val &= ~(WM8994_IN2L_VU_MASK); - val |= (WM8994_IN2L_VU | WM8994_IN2L_VOL_16_5dB); - wm8994_write(codec, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, 0x0116); + wm8994_write(codec, WM8994_ANALOGUE_HP_1, 0x00EE); - val = wm8994_read(codec, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME); - val &= ~(WM8994_IN2R_VU_MASK); - val |= (WM8994_IN2R_VU_MASK | WM8994_IN2R_VOL_16_5dB); - wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, 0x0116); + /* Unmute DAC1 left */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); + val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); + val |= TUNING_DAC1L_VOL; + wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); - val = (WM8994_IN2LN_TO_IN2L | WM8994_IN2RN_TO_IN2R); - wm8994_write(codec, WM8994_INPUT_MIXER_2, val); + /* Unmute and volume ctrl RightDAC */ + val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); + val |= TUNING_DAC1R_VOL; + wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - if (!wm8994->testmode_config_flag) { - /* IN2L to MIXINL */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_3); - val &= ~(WM8994_IN2L_TO_MIXINL_MASK); - val |= WM8994_IN2L_TO_MIXINL; - wm8994_write(codec, WM8994_INPUT_MIXER_3, val); + wm8994_write(codec, WM8994_DAC2_LEFT_VOLUME, 0x01C0); - /* IN2R to MIXINR */ - val = wm8994_read(codec, WM8994_INPUT_MIXER_4); - val &= ~(WM8994_IN2R_TO_MIXINR_MASK); - val |= WM8994_IN2R_TO_MIXINR; - wm8994_write(codec, WM8994_INPUT_MIXER_4, val); - } + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, 0x0000); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x0000); } -void wm8994_set_fmradio_headset(struct snd_soc_codec *codec) +void wm8994_set_voicecall_speaker(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = codec->drvdata; - u16 val; - - u16 nReadServo4Val = NULL; - u16 ncompensationResult = NULL; - u16 nServo4Low = NULL; - u16 nServo4High = NULL; - u8 nCompensationResultLow = 0; - u8 nCompensationResultHigh = 0; - - DEBUG_LOG("Routing ear path : FM Radio -> EAR Out"); - - wm8994->fmradio_path = FMR_HP; - - /* Disable reg sync to MCLK */ - val = wm8994_read(codec, WM8994_AIF1_CLOCKING_1); - val &= ~(WM8994_AIF1CLK_ENA_MASK); - val |= WM8994_AIF1CLK_ENA; - wm8994_write(codec, WM8994_AIF1_CLOCKING_1, val); - - val = wm8994_read(codec, WM8994_CONTROL_INTERFACE); - val &= ~(WM8994_AUTO_INC_MASK); - val |= WM8994_AUTO_INC; - wm8994_write(codec, WM8994_CONTROL_INTERFACE, val); - - /* Analogue Path Config */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_2); - val &= ~(WM8994_MIXINL_ENA_MASK | WM8994_MIXINR_ENA_MASK | - WM8994_IN2L_ENA_MASK | WM8994_IN2R_ENA_MASK); - val |= (WM8994_MIXINL_ENA | WM8994_MIXINR_ENA | - WM8994_IN2L_ENA | WM8994_IN2R_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, val); - - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_NORMAL); - val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, 0x0003); - - val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); - val = 0x0000; - wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); - - val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); - val = 0x0000; - wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); + int val; - wm8994_set_fmradio_common(codec); + DEBUG_LOG(""); - /* Output mixer setting */ - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_1); - val &= ~(WM8994_DAC1L_TO_HPOUT1L_MASK | WM8994_MIXINL_TO_MIXOUTL_MASK); - val |= (WM8994_MIXINL_TO_MIXOUTL); - wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val); + audio_ctrl_mic_bias_gpio(wm8994->pdata, 1); - val = wm8994_read(codec, WM8994_OUTPUT_MIXER_2); - val &= ~(WM8994_DAC1R_TO_HPOUT1R_MASK | WM8994_MIXINR_TO_MIXOUTR_MASK); - val |= (WM8994_MIXINR_TO_MIXOUTR); - wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val); + wm8994_set_voicecall_common_setting(codec); - /** Headset */ - wm8994_write(codec, 0x102, 0x0003); - wm8994_write(codec, 0x56, 0x0003); - wm8994_write(codec, 0x102, 0x0000); - wm8994_write(codec, 0x5D, 0x0002); + wm8994_write(codec, 0x601, 0x0005); + wm8994_write(codec, 0x602, 0x0005); + wm8994_write(codec, 0x603, 0x000C); + /* Tx -> AIF2 Path */ + wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, + WM8994_ADC1_TO_DAC2L); - /* DC Servo Series Count */ - val = 0x03E0; - wm8994_write(codec, WM8994_DC_SERVO_2, val); + /* Analogue Input Configuration*/ + wm8994_write(codec, 0x02, 0x6240); + wm8994_write(codec, WM8994_INPUT_MIXER_2, WM8994_IN1LP_TO_IN1L | + WM8994_IN1LN_TO_IN1L); + + val = wm8994_read(codec, WM8994_INPUT_MIXER_3); + val &= ~(WM8994_IN1L_TO_MIXINL_MASK | + WM8994_IN1L_MIXINL_VOL_MASK | + WM8994_MIXOUTL_MIXINL_VOL_MASK); + val |= (WM8994_IN1L_TO_MIXINL | TUNING_CALL_SPK_MIXER_VOL); + wm8994_write(codec, WM8994_INPUT_MIXER_3, val); + + val = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); + val &= ~(WM8994_IN1L_MUTE_MASK | WM8994_IN1L_VOL_MASK); + val |= (WM8994_IN1L_VU | TUNING_CALL_SPK_INPUTMIX_VOL); + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, val); + + /* Analogue Output Configuration*/ + wm8994_write(codec, 0x03, 0x0300); - /* HP first and second stage */ - /* Enable vmid,bias, hp left and right */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | - WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK); - val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | - WM8994_HPOUT1R_ENA | WM8994_HPOUT1L_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, + WM8994_AIF2ADCL_ENA | WM8994_ADCL_ENA); - val = (WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY); - wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); + wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); - /* Enable Charge Pump */ - val = wm8994_read(codec, WM8994_CHARGE_PUMP_1); - val &= ~WM8994_CP_ENA_MASK; - val |= WM8994_CP_ENA | WM8994_CP_ENA_DEFAULT; - wm8994_write(codec, WM8994_CHARGE_PUMP_1, 0x9F25); + val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); + val &= ~(WM8994_SPKMIXL_VOL_MASK); + val |= TUNING_SPKMIXL_ATTEN; + wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); - msleep(5); + val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); + val &= ~(WM8994_SPKMIXR_VOL_MASK); + val |= TUNING_SPKMIXR_ATTEN; + wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); - /* DC Servo */ - val = (WM8994_DCS_TRIG_SERIES_1 | WM8994_DCS_TRIG_SERIES_0 | - WM8994_DCS_ENA_CHAN_1 | WM8994_DCS_ENA_CHAN_0); - wm8994_write(codec, WM8994_DC_SERVO_1, 0x0303); + val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); + val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | WM8994_SPKOUTL_VOL_MASK); + val |= (WM8994_SPKOUT_VU | WM8994_SPKOUTL_MUTE_N | + TUNING_CALL_SPKL_VOL); + wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); - msleep(160); + val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); + val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | WM8994_SPKOUTR_VOL_MASK); + wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); - nReadServo4Val = wm8994_read(codec, WM8994_DC_SERVO_4); - nServo4Low = (u8) (nReadServo4Val & 0xff); - nServo4High = (u8) ((nReadServo4Val >> 8) & 0xff); + val = wm8994_read(codec, WM8994_CLASSD); + val &= ~(WM8994_SPKOUTL_BOOST_MASK); + val |= TUNING_CALL_CLASSD_VOL << WM8994_SPKOUTL_BOOST_SHIFT; + wm8994_write(codec, WM8994_CLASSD, val); - nCompensationResultLow = ((u16) nServo4Low - 4) & 0x00ff; - nCompensationResultHigh = (((u16) nServo4High - 4) << 8) & 0xff00; - ncompensationResult = nCompensationResultLow | nCompensationResultHigh; - wm8994_write(codec, WM8994_DC_SERVO_4, ncompensationResult); + val = wm8994_read(codec, WM8994_SPKOUT_MIXERS); + val &= ~(WM8994_SPKMIXL_TO_SPKOUTL_MASK | + WM8994_SPKMIXR_TO_SPKOUTL_MASK | + WM8994_SPKMIXR_TO_SPKOUTR_MASK); + val |= WM8994_SPKMIXL_TO_SPKOUTL; + wm8994_write(codec, WM8994_SPKOUT_MIXERS, val); - val = (WM8994_DCS_TRIG_DAC_WR_1 | WM8994_DCS_TRIG_DAC_WR_0 | - WM8994_DCS_ENA_CHAN_1 | WM8994_DCS_ENA_CHAN_0); - wm8994_write(codec, WM8994_DC_SERVO_1, val); + wm8994_write(codec, 0x36, 0x0003); + /* Digital Path Enables and Unmutes*/ - msleep(20); + wm8994_write(codec, WM8994_SIDETONE, 0x01C0); - /* Headphone Output */ - /* Intermediate HP settings */ - val = wm8994_read(codec, WM8994_ANALOGUE_HP_1); - val &= ~(WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1R_OUTP_MASK | - WM8994_HPOUT1R_RMV_SHORT_MASK | WM8994_HPOUT1L_DLY_MASK | - WM8994_HPOUT1L_OUTP_MASK | WM8994_HPOUT1L_RMV_SHORT_MASK); - val |= (WM8994_HPOUT1L_RMV_SHORT | WM8994_HPOUT1L_OUTP | - WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_RMV_SHORT | - WM8994_HPOUT1R_OUTP | WM8994_HPOUT1R_DLY); - wm8994_write(codec, WM8994_ANALOGUE_HP_1, val); - - /* Enable MIXOUT */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); - val &= ~(WM8994_MIXOUTLVOL_ENA_MASK | WM8994_MIXOUTRVOL_ENA_MASK | - WM8994_MIXOUTL_ENA_MASK | WM8994_MIXOUTR_ENA_MASK); - val |= (WM8994_MIXOUTLVOL_ENA | WM8994_MIXOUTRVOL_ENA | - WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val); - /* Unmutes */ - /* Output setting */ - if (!wm8994->testmode_config_flag) { - val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTL_MUTE_N | - TUNING_FMRADIO_OPGAL_VOL); - wm8994_write(codec, WM8994_LEFT_OPGA_VOLUME, val); + wm8994_write(codec, WM8994_ANALOGUE_HP_1, 0x0000); + wm8994_write(codec, WM8994_DC_SERVO_1, 0x0000); - val = wm8994_read(codec, WM8994_RIGHT_OPGA_VOLUME); - val &= ~(WM8994_MIXOUTR_MUTE_N_MASK | WM8994_MIXOUTR_VOL_MASK); - val |= (WM8994_MIXOUT_VU | WM8994_MIXOUTR_MUTE_N | - TUNING_FMRADIO_OPGAR_VOL); - wm8994_write(codec, WM8994_RIGHT_OPGA_VOLUME, val); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_SPKOUTL_ENA | WM8994_VMID_SEL_NORMAL | WM8994_BIAS_ENA); - val = wm8994_read(codec, WM8994_LEFT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1L_MUTE_N_MASK | WM8994_HPOUT1L_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | - TUNING_FMRADIO_OUTPUTL_VOL); - wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); + /* Unmute DAC1 left */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); + val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); + val |= TUNING_DAC1L_VOL; + wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); - val = wm8994_read(codec, WM8994_RIGHT_OUTPUT_VOLUME); - val &= ~(WM8994_HPOUT1R_MUTE_N_MASK | WM8994_HPOUT1R_VOL_MASK); - val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | - TUNING_FMRADIO_OUTPUTR_VOL); - wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); - } + /* Unmute and volume ctrl RightDAC */ + val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); + val |= TUNING_DAC1R_VOL; + wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); + wm8994_write(codec, WM8994_DAC2_LEFT_VOLUME, 0x01C0); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, WM8994_AIF1DAC1_UNMUTE); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, WM8994_AIF1DAC2_UNMUTE); } -void wm8994_set_fmradio_speaker(struct snd_soc_codec *codec) +void wm8994_set_voicecall_bluetooth(struct snd_soc_codec *codec) { - struct wm8994_priv *wm8994 = codec->drvdata; + int val; - u16 val; + DEBUG_LOG(""); - DEBUG_LOG("Routing spk path : FM Radio -> SPK Out"); + wm8994_set_voicecall_common_setting(codec); - wm8994->fmradio_path = FMR_SPK; + /* GPIO Configuration */ + wm8994_write(codec, WM8994_GPIO_8, WM8994_GP8_DIR | WM8994_GP8_DB); + wm8994_write(codec, WM8994_GPIO_9, WM8994_GP9_DB); + wm8994_write(codec, WM8994_GPIO_10, WM8994_GP10_DB); + wm8994_write(codec, WM8994_GPIO_11, WM8994_GP11_DB); - /* Disable end point for preventing pop up noise. */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_SPKOUTL_ENA_MASK); + /* Digital Path Enables and Unmutes */ + val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); + val &= ~(WM8994_SPKOUTL_ENA_MASK | WM8994_HPOUT2_ENA_MASK | + WM8994_HPOUT1L_ENA_MASK | WM8994_HPOUT1R_ENA_MASK); wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); - val = (WM8994_TSHUT_ENA | WM8994_TSHUT_OPDIS | WM8994_OPCLK_ENA | - WM8994_MIXINL_ENA | WM8994_MIXINR_ENA | WM8994_IN2L_ENA | - WM8994_IN2R_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_2, val); - - wm8994_set_fmradio_common(codec); - - if (!wm8994->testmode_config_flag) { - /* Unmute the SPKMIXVOLUME */ - val = wm8994_read(codec, WM8994_SPKMIXL_ATTENUATION); - val &= ~(WM8994_SPKMIXL_VOL_MASK); - val |= TUNING_SPKMIXL_ATTEN; - wm8994_write(codec, WM8994_SPKMIXL_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPKMIXR_ATTENUATION); - val &= ~(WM8994_SPKMIXR_VOL_MASK); - wm8994_write(codec, WM8994_SPKMIXR_ATTENUATION, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_LEFT); - val &= ~(WM8994_SPKOUTL_MUTE_N_MASK | WM8994_SPKOUTL_VOL_MASK); - val |= (WM8994_SPKOUT_VU | WM8994_SPKOUTL_MUTE_N | - TUNING_FMRADIO_SPKL_VOL); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_LEFT, val); - - val = wm8994_read(codec, WM8994_SPEAKER_VOLUME_RIGHT); - val &= ~(WM8994_SPKOUTR_MUTE_N_MASK | WM8994_SPKOUTR_VOL_MASK); - wm8994_write(codec, WM8994_SPEAKER_VOLUME_RIGHT, val); - - val = wm8994_read(codec, WM8994_CLASSD); - val &= ~(WM8994_SPKOUTL_BOOST_MASK); - val |= TUNING_FMRADIO_CLASSD_VOL << WM8994_SPKOUTL_BOOST_SHIFT; - wm8994_write(codec, WM8994_CLASSD, val); - - } - - /*Output MIxer-Output PGA */ - val = wm8994_read(codec, WM8994_SPKOUT_MIXERS); - val &= ~(WM8994_SPKMIXL_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTL_MASK | - WM8994_SPKMIXR_TO_SPKOUTR_MASK); - val |= (WM8994_SPKMIXL_TO_SPKOUTL); - wm8994_write(codec, WM8994_SPKOUT_MIXERS, val); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_4, + WM8994_AIF2ADCL_ENA | WM8994_ADCL_ENA); - /* Output mixer setting */ - val = wm8994_read(codec, WM8994_SPEAKER_MIXER); - val &= ~(WM8994_MIXINL_TO_SPKMIXL_MASK | WM8994_MIXINR_TO_SPKMIXR_MASK); - val |= (WM8994_MIXINL_TO_SPKMIXL); - wm8994_write(codec, WM8994_SPEAKER_MIXER, val); + /* If Input MIC is enabled, bluetooth Rx is muted. */ + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, + WM8994_IN1L_MUTE); + wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_1_2_VOLUME, + WM8994_IN1R_MUTE); + wm8994_write(codec, WM8994_INPUT_MIXER_2, 0x00); + wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x00); + wm8994_write(codec, WM8994_INPUT_MIXER_4, 0x00); - /* Enable SPK Volume. */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_3); - val &= ~(WM8994_SPKRVOL_ENA_MASK | WM8994_SPKLVOL_ENA_MASK); - val |= (WM8994_SPKLVOL_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val); + /* + * for BT DTMF Play + * Rx Path: AIF2ADCDAT2 select + * CP(CALL) Path:GPIO5/DACDAT2 select + * AP(DTMF) Path: DACDAT1 select + * Tx Path: GPIO8/DACDAT3 select + */ - /* Enbale bias,vmid and Left speaker */ - val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); - val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | - WM8994_SPKOUTL_ENA_MASK); - val |= (WM8994_BIAS_ENA | WM8994_VMID_SEL_NORMAL | WM8994_SPKOUTL_ENA); - wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, val); -} + wm8994_write(codec, WM8994_POWER_MANAGEMENT_6, 0x000C); -void wm8994_set_fmradio_headset_mix(struct snd_soc_codec *codec) -{ - struct wm8994_priv *wm8994 = codec->drvdata; + /* AIF1 & AIF2 Output is connected to DAC1 */ + wm8994_write(codec, WM8994_DAC2_LEFT_MIXER_ROUTING, + WM8994_AIF2DACL_TO_DAC2L | WM8994_AIF1DAC1L_TO_DAC2L); + wm8994_write(codec, WM8994_DAC2_RIGHT_MIXER_ROUTING, + WM8994_AIF2DACR_TO_DAC2R | WM8994_AIF1DAC1R_TO_DAC2R); - DEBUG_LOG(""); + wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019); - wm8994->fmradio_path = FMR_HP_MIX; + wm8994_write(codec, WM8994_DAC2_MIXER_VOLUMES, 0x000C); - wm8994_set_playback_headset(codec); - wm8994_set_fmradio_headset(codec); -} + wm8994_write(codec, WM8994_DAC2_LEFT_VOLUME, 0x01C0); + wm8994_write(codec, WM8994_DAC2_RIGHT_VOLUME, 0x01C0); -void wm8994_set_fmradio_speaker_mix(struct snd_soc_codec *codec) -{ - struct wm8994_priv *wm8994 = codec->drvdata; + wm8994_write(codec, WM8994_OVERSAMPLING, 0X0000); - DEBUG_LOG(""); + /* Unmute DAC1 left */ + val = wm8994_read(codec, WM8994_DAC1_LEFT_VOLUME); + val &= ~(WM8994_DAC1L_MUTE_MASK | WM8994_DAC1L_VOL_MASK); + val |= TUNING_DAC1L_VOL; + wm8994_write(codec, WM8994_DAC1_LEFT_VOLUME, val); - wm8994->fmradio_path = FMR_SPK_MIX; + /* Unmute and volume ctrl RightDAC */ + val = wm8994_read(codec, WM8994_DAC1_RIGHT_VOLUME); + val &= ~(WM8994_DAC1R_MUTE_MASK | WM8994_DAC1R_VOL_MASK); + val |= TUNING_DAC1R_VOL; + wm8994_write(codec, WM8994_DAC1_RIGHT_VOLUME, val); - wm8994_set_fmradio_speaker(codec); - wm8994_set_playback_headset(codec); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, 0x0000); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x0000); } -void wm8994_set_fmradio_speaker_headset_mix(struct snd_soc_codec *codec) -{ - struct wm8994_priv *wm8994 = codec->drvdata; - - DEBUG_LOG(""); - - wm8994->fmradio_path = FMR_SPK_HP_MIX; - - wm8994_set_playback_speaker_headset(codec); - wm8994_set_fmradio_headset(codec); -} diff --git a/sound/soc/codecs/wm8994_samsung.c b/sound/soc/codecs/wm8994_samsung.c new file mode 100755 index 0000000..d899ab8 --- /dev/null +++ b/sound/soc/codecs/wm8994_samsung.c @@ -0,0 +1,1528 @@ +/* + * wm8994_samsung.c -- WM8994 ALSA Soc Audio driver + * + * Copyright 2010 Wolfson Microelectronics PLC. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Notes: + * The WM8994 is a multichannel codec with S/PDIF support, featuring six + * DAC channels and two ADC channels. + * + * Currently only the primary audio interface is supported - S/PDIF and + * the secondary audio interfaces are not. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/tlv.h> +#include <sound/initval.h> +#include <asm/div64.h> +#include <linux/io.h> +#include <plat/map-base.h> +#include <linux/gpio.h> +#include <plat/gpio-cfg.h> +#include <mach/regs-clock.h> +#include "wm8994_samsung.h" + +#define WM8994_VERSION "0.1" +#define SUBJECT "wm8994_samsung.c" + +#if defined(CONFIG_VIDEO_TV20) && defined(CONFIG_SND_S5P_WM8994_MASTER) +#define HDMI_USE_AUDIO +#endif + +/* + *Definitions of clock related. +*/ + +static struct { + int ratio; + int clk_sys_rate; +} clk_sys_rates[] = { + { 64, 0 }, + { 128, 1 }, + { 192, 2 }, + { 256, 3 }, + { 384, 4 }, + { 512, 5 }, + { 768, 6 }, + { 1024, 7 }, + { 1408, 8 }, + { 1536, 9 }, +}; + +static struct { + int rate; + int sample_rate; +} sample_rates[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 3 }, + { 22050, 4 }, + { 24000, 5 }, + { 32000, 6 }, + { 44100, 7 }, + { 48000, 8 }, + { 88200, 9 }, + { 96000, 10 }, +}; + +static struct { + int div; + int bclk_div; +} bclk_divs[] = { + { 1, 0 }, + { 2, 1 }, + { 4, 2 }, + { 6, 3 }, + { 8, 4 }, + { 12, 5 }, + { 16, 6 }, + { 24, 7 }, + { 32, 8 }, + { 48, 9 }, +}; + +struct snd_soc_dai wm8994_dai; +EXPORT_SYMBOL_GPL(wm8994_dai); + +struct snd_soc_codec_device soc_codec_dev_pcm_wm8994; +EXPORT_SYMBOL_GPL(soc_codec_dev_pcm_wm8994); + +struct snd_soc_codec_device soc_codec_dev_wm8994; +EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994); + +static struct wm8994_platform_data *pdata; + +static void wm8994_set_off(struct snd_soc_codec *codec); + +/* + * Definitions of sound path + */ +select_route universal_wm8994_playback_paths[] = { + wm8994_set_off, wm8994_set_playback_receiver, + wm8994_set_playback_speaker, wm8994_set_playback_headset, + wm8994_set_off, wm8994_set_playback_speaker_headset +}; + +select_route universal_wm8994_voicecall_paths[] = { + wm8994_set_off, wm8994_set_voicecall_receiver, + wm8994_set_voicecall_speaker, wm8994_set_voicecall_headset, + wm8994_set_voicecall_bluetooth +}; + +select_mic_route universal_wm8994_mic_paths[] = { + wm8994_record_main_mic, wm8994_record_headset_mic, +}; + +select_clock_control universal_clock_controls = wm8994_configure_clock; + +/* + * Implementation of I2C functions + */ +static unsigned int wm8994_read_hw(struct snd_soc_codec *codec, u16 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *i2c = codec->control_data; + + data = ((reg & 0xff00) >> 8) | ((reg & 0xff) << 8); + + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = 2; + xfer[0].buf = (void *)&data; + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret != 2) { + dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[4]; + int ret; + + /* data is + * D15..D9 WM8993 register offset + * D8...D0 register data + */ + data[0] = (reg & 0xff00) >> 8; + data[1] = reg & 0x00ff; + data[2] = value >> 8; + data[3] = value & 0x00ff; + ret = codec->hw_write(codec->control_data, data, 4); + + if (ret == 4) + return 0; + else { + pr_err("i2c write problem occured\n"); + return ret; + } +} + +inline unsigned int wm8994_read(struct snd_soc_codec *codec, unsigned int reg) +{ + return wm8994_read_hw(codec, reg); +} + +static int wm8994_ldo_control(struct wm8994_platform_data *pdata, int en) +{ + + if (!pdata) { + pr_err("failed to control wm8994 ldo\n"); + return -EINVAL; + } + + gpio_set_value(pdata->ldo, en); + + if (en) + msleep(10); + else + msleep(125); + + return 0; + +} + +/* + * Functions related volume. + */ +static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); + +static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + u16 val; + + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + + DEBUG_LOG(""); + + ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); + if (ret < 0) + return ret; + + val = wm8994_read(codec, reg); + + return wm8994_write(codec, reg, val | 0x0100); +} + +static int wm899x_inpga_put_volsw_vu(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + int ret; + u16 val; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (ret < 0) + return ret; + + val = wm8994_read(codec, reg); + + return wm8994_write(codec, reg, val | 0x0100); + +} + +/* + * Implementation of sound path + */ +#define MAX_PLAYBACK_PATHS 8 +#define MAX_VOICECALL_PATH 4 +static const char *playback_path[] = { + "OFF", "RCV", "SPK", "HP", "BT", "SPK_HP", + "RING_SPK", "RING_HP", "RING_SPK_HP" +}; +static const char *voicecall_path[] = { "OFF", "RCV", "SPK", "HP", "BT" }; +static const char *mic_path[] = { "Main Mic", "Hands Free Mic" }; +static const char *mic_state[] = { "MIC_NO_USE", "MIC_USE" }; + +static int wm8994_get_mic_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + + ucontrol->value.integer.value[0] = wm8994->rec_path; + + return 0; +} + +static int wm8994_set_mic_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + + DEBUG_LOG(""); + + if (ucontrol->value.integer.value[0] == 0) + wm8994->rec_path = MAIN; + else if (ucontrol->value.integer.value[0] == 1) + wm8994->rec_path = SUB; + else if (ucontrol->value.integer.value[0] == 2) { + wm8994->rec_path = BT_REC; + wm8994->universal_mic_path[wm8994->rec_path] (codec); + return 0; + } else + return -EINVAL; + + wm8994->universal_mic_path[wm8994->rec_path] (codec); + + return 0; +} + +static int wm8994_get_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + + ucontrol->value.integer.value[0] = wm8994->cur_path; + + return 0; +} + +static int wm8994_set_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value; + + int path_num = ucontrol->value.integer.value[0]; + + if (strcmp(mc->texts[path_num], playback_path[path_num])) { + DEBUG_LOG_ERR("Unknown path %s\n", mc->texts[path_num]); + return -ENODEV; + } + + if (path_num > MAX_PLAYBACK_PATHS) { + DEBUG_LOG_ERR("Unknown Path\n"); + return -ENODEV; + } + + switch (path_num) { + case OFF: + DEBUG_LOG("Switching off output path\n"); + break; + case RCV: + case SPK: + case HP: + case SPK_HP: + case BT: + DEBUG_LOG("routing to %s\n", mc->texts[path_num]); + wm8994->ringtone_active = DEACTIVE; + break; + case RING_SPK: + case RING_HP: + DEBUG_LOG("routing to %s\n", mc->texts[path_num]); + wm8994->ringtone_active = ACTIVE; + path_num -= 4; + break; + case RING_SPK_HP: + DEBUG_LOG("routing to %s\n", mc->texts[path_num]); + wm8994->ringtone_active = ACTIVE; + path_num -= 3; + break; + default: + DEBUG_LOG_ERR("audio path[%d] does not exists!!\n", path_num); + return -ENODEV; + break; + } + + wm8994->cur_path = path_num; + wm8994->call_state = DISCONNECT; + wm8994->universal_playback_path[wm8994->cur_path] (codec); + + return 0; +} + +static int wm8994_get_voice_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + + ucontrol->value.integer.value[0] = wm8994->cur_path; + + return 0; +} + +static int wm8994_set_voice_path(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + struct soc_enum *mc = (struct soc_enum *)kcontrol->private_value; + + int path_num = ucontrol->value.integer.value[0]; + + if (strcmp(mc->texts[path_num], voicecall_path[path_num])) { + DEBUG_LOG_ERR("Unknown path %s\n", mc->texts[path_num]); + return -ENODEV; + } + + switch (path_num) { + case OFF: + DEBUG_LOG("Switching off output path\n"); + break; + case RCV: + case SPK: + case HP: + case BT: + DEBUG_LOG("routing voice path to %s\n", mc->texts[path_num]); + break; + default: + DEBUG_LOG_ERR("path[%d] does not exists!\n", path_num); + return -ENODEV; + break; + } + + if (wm8994->cur_path != path_num || wm8994->call_state == DISCONNECT) { + wm8994->cur_path = path_num; + wm8994->call_state = CONNECT; + wm8994->universal_voicecall_path[wm8994->cur_path] (codec); + } else { + int val; + val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); + val &= ~(WM8994_AIF1DAC1_MUTE_MASK); + val |= (WM8994_AIF1DAC1_UNMUTE); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); + } + + return 0; +} + +static int wm8994_get_mic_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + + DEBUG_LOG("mic_state = [%d]", wm8994->mic_state); + + return wm8994->mic_state; +} + +static int wm8994_set_mic_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct wm8994_priv *wm8994 = codec->drvdata; + + int control_flag = ucontrol->value.integer.value[0]; + + DEBUG_LOG("Changed mic state [%d] => [%d]", + wm8994->mic_state, control_flag); + + wm8994->mic_state = control_flag; + + return 0; +} + +static void wm8994_set_off(struct snd_soc_codec *codec) +{ + struct wm8994_priv *wm8994 = codec->drvdata; + + DEBUG_LOG(""); + + wm8994_ldo_control(wm8994->pdata, 0); + + wm8994->universal_clock_control(codec, CODEC_OFF); +} + +#define SOC_WM899X_OUTPGA_DOUBLE_R_TLV(xname, reg_left, reg_right,\ + xshift, xmax, xinvert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_2r, \ + .get = snd_soc_get_volsw_2r, .put = wm899x_outpga_put_volsw_vu, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = reg_left, .rreg = reg_right, .shift = xshift, \ + .max = xmax, .invert = xinvert} } + +#define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ + tlv_array) {\ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, \ + .get = snd_soc_get_volsw, .put = wm899x_inpga_put_volsw_vu, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } + +static const DECLARE_TLV_DB_SCALE(digital_tlv, -7162, 37, 1); +static const DECLARE_TLV_DB_LINEAR(digital_tlv_spkr, -5700, 600); +static const DECLARE_TLV_DB_LINEAR(digital_tlv_rcv, -5700, 600); +static const DECLARE_TLV_DB_LINEAR(digital_tlv_headphone, -5700, 600); +static const DECLARE_TLV_DB_LINEAR(digital_tlv_mic, -7162, 7162); + +static const struct soc_enum path_control_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(playback_path), playback_path), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(voicecall_path), voicecall_path), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mic_path), mic_path), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(mic_state), mic_state), +}; + +static const struct snd_kcontrol_new wm8994_snd_controls[] = { + SOC_WM899X_OUTPGA_DOUBLE_R_TLV("Playback Volume", + WM8994_LEFT_OPGA_VOLUME, + WM8994_RIGHT_OPGA_VOLUME, 0, 0x3F, 0, + digital_tlv_rcv), + SOC_WM899X_OUTPGA_DOUBLE_R_TLV("Playback Spkr Volume", + WM8994_SPEAKER_VOLUME_LEFT, + WM8994_SPEAKER_VOLUME_RIGHT, 1, 0x3F, 0, + digital_tlv_spkr), + SOC_WM899X_OUTPGA_DOUBLE_R_TLV("Playback Headset Volume", + WM8994_LEFT_OUTPUT_VOLUME, + WM8994_RIGHT_OUTPUT_VOLUME, 1, 0x3F, 0, + digital_tlv_headphone), + SOC_WM899X_OUTPGA_SINGLE_R_TLV("Capture Volume", + WM8994_AIF1_ADC1_LEFT_VOLUME, + 0, 0xEF, 0, digital_tlv_mic), + /* Path Control */ + SOC_ENUM_EXT("Playback Path", path_control_enum[0], + wm8994_get_path, wm8994_set_path), + + SOC_ENUM_EXT("Voice Call Path", path_control_enum[1], + wm8994_get_voice_path, wm8994_set_voice_path), + + SOC_ENUM_EXT("MIC Path", path_control_enum[2], + wm8994_get_mic_path, wm8994_set_mic_path), + +#if defined USE_INFINIEON_EC_FOR_VT + SOC_ENUM_EXT("Clock Control", clock_control_enum[0], + s3c_pcmdev_get_clock, s3c_pcmdev_set_clock), +#endif + SOC_ENUM_EXT("Mic Status", path_control_enum[3], + wm8994_get_mic_status, wm8994_set_mic_status), + +}; + +/* Add non-DAPM controls */ +static int wm8994_add_controls(struct snd_soc_codec *codec) +{ + int err, i; + + for (i = 0; i < ARRAY_SIZE(wm8994_snd_controls); i++) { + err = snd_ctl_add(codec->card, + snd_soc_cnew(&wm8994_snd_controls[i], + codec, NULL)); + if (err < 0) + return err; + } + return 0; +} +static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { +}; + +static const struct snd_soc_dapm_route audio_map[] = { +}; + +static int wm8994_add_widgets(struct snd_soc_codec *codec) +{ + snd_soc_dapm_new_controls(codec, wm8994_dapm_widgets, + ARRAY_SIZE(wm8994_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_new_widgets(codec); + return 0; +} + +static int configure_clock(struct snd_soc_codec *codec) +{ + struct wm8994_priv *wm8994 = codec->drvdata; + unsigned int reg; + + DEBUG_LOG(""); + + reg = wm8994_read(codec, WM8994_AIF1_CLOCKING_1); + reg &= ~WM8994_AIF1CLK_ENA; + reg &= ~WM8994_AIF1CLK_SRC_MASK; + wm8994_write(codec, WM8994_AIF1_CLOCKING_1, reg); + + switch (wm8994->sysclk_source) { + case WM8994_SYSCLK_MCLK: + dev_dbg(codec->dev, "Using %dHz MCLK\n", wm8994->mclk_rate); + + reg = wm8994_read(codec, WM8994_AIF1_CLOCKING_1); + reg &= ~WM8994_AIF1CLK_ENA; + wm8994_write(codec, WM8994_AIF1_CLOCKING_1, reg); + + reg = wm8994_read(codec, WM8994_AIF1_CLOCKING_1); + reg &= 0x07; + + if (wm8994->mclk_rate > 13500000) { + reg |= WM8994_AIF1CLK_DIV; + wm8994->sysclk_rate = wm8994->mclk_rate / 2; + } else { + reg &= ~WM8994_AIF1CLK_DIV; + wm8994->sysclk_rate = wm8994->mclk_rate; + } + reg |= WM8994_AIF1CLK_ENA; + wm8994_write(codec, WM8994_AIF1_CLOCKING_1, reg); + + /* Enable clocks to the Audio core and sysclk of wm8994 */ + reg = wm8994_read(codec, WM8994_CLOCKING_1); + reg &= ~(WM8994_SYSCLK_SRC_MASK | WM8994_DSP_FSINTCLK_ENA_MASK + | WM8994_DSP_FS1CLK_ENA_MASK); + reg |= (WM8994_DSP_FS1CLK_ENA | WM8994_DSP_FSINTCLK_ENA); + wm8994_write(codec, WM8994_CLOCKING_1, reg); + break; + + case WM8994_SYSCLK_FLL: + switch (wm8994->fs) { + case 8000: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x2F00); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0x3126); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x0100); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 11025: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x1F00); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0x86C2); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x00e0); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 12000: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x1F00); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0x3126); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x0100); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 16000: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x1900); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0xE23E); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x0100); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 22050: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x0F00); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0x86C2); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x00E0); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 24000: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x0F00); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0x3126); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x0100); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 32000: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x0C00); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0xE23E); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x0100); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 44100: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x0700); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0x86C2); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x00E0); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + case 48000: + wm8994_write(codec, WM8994_FLL1_CONTROL_2, 0x0700); + wm8994_write(codec, WM8994_FLL1_CONTROL_3, 0x3126); + wm8994_write(codec, WM8994_FLL1_CONTROL_5, 0x0C88); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, 0x0100); + wm8994_write(codec, WM8994_FLL1_CONTROL_1, + WM8994_FLL1_FRACN_ENA | WM8994_FLL1_ENA); + break; + + default: + DEBUG_LOG_ERR("Unsupported Frequency\n"); + break; + } + + reg = wm8994_read(codec, WM8994_AIF1_CLOCKING_1); + reg |= WM8994_AIF1CLK_ENA; + reg |= WM8994_AIF1CLK_SRC_FLL1; + wm8994_write(codec, WM8994_AIF1_CLOCKING_1, reg); + + /* Enable clocks to the Audio core and sysclk of wm8994*/ + reg = wm8994_read(codec, WM8994_CLOCKING_1); + reg &= ~(WM8994_SYSCLK_SRC_MASK | WM8994_DSP_FSINTCLK_ENA_MASK | + WM8994_DSP_FS1CLK_ENA_MASK); + reg |= (WM8994_DSP_FS1CLK_ENA | WM8994_DSP_FSINTCLK_ENA); + wm8994_write(codec, WM8994_CLOCKING_1, reg); + break; + + default: + dev_err(codec->dev, "System clock not configured\n"); + return -EINVAL; + } + + dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm8994->sysclk_rate); + + return 0; +} + +static int wm8994_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + DEBUG_LOG(""); + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + /* VMID=2*40k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK, 0x2); + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, + WM8994_TSHUT_ENA, WM8994_TSHUT_ENA); + break; + + case SND_SOC_BIAS_STANDBY: + if (codec->bias_level == SND_SOC_BIAS_OFF) { + /* Bring up VMID with fast soft start */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + WM8994_VMID_RAMP_MASK | + WM8994_BIAS_SRC, + WM8994_STARTUP_BIAS_ENA | + WM8994_VMID_BUF_ENA | + WM8994_VMID_RAMP_MASK | + WM8994_BIAS_SRC); + /* VMID=2*40k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK | + WM8994_BIAS_ENA, + WM8994_BIAS_ENA | 0x2); + + /* Switch to normal bias */ + snd_soc_update_bits(codec, WM8994_ANTIPOP_2, + WM8994_BIAS_SRC | + WM8994_STARTUP_BIAS_ENA, 0); + } + + /* VMID=2*240k */ + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK, 0x4); + + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, + WM8994_TSHUT_ENA, 0); + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, WM8994_ANTIPOP_1, + WM8994_LINEOUT_VMID_BUF_ENA, 0); + + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA, 0); + break; + } + + codec->bias_level = level; + + return 0; +} + +static int wm8994_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8994_priv *wm8994 = codec->drvdata; + + DEBUG_LOG("clk_id =%d ", clk_id); + + switch (clk_id) { + case WM8994_SYSCLK_MCLK: + wm8994->mclk_rate = freq; + wm8994->sysclk_source = clk_id; + break; + case WM8994_SYSCLK_FLL: + wm8994->sysclk_rate = freq; + wm8994->sysclk_source = clk_id; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8994_priv *wm8994 = codec->drvdata; + + unsigned int aif1 = wm8994_read(codec, WM8994_AIF1_CONTROL_1); + unsigned int aif2 = wm8994_read(codec, WM8994_AIF1_MASTER_SLAVE); + + DEBUG_LOG(""); + + aif1 &= ~(WM8994_AIF1_LRCLK_INV | WM8994_AIF1_BCLK_INV | + WM8994_AIF1_WL_MASK | WM8994_AIF1_FMT_MASK); + + aif2 &= ~(WM8994_AIF1_LRCLK_FRC_MASK | + WM8994_AIF1_CLK_FRC | WM8994_AIF1_MSTR); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + wm8994->master = 0; + break; + case SND_SOC_DAIFMT_CBS_CFM: + aif2 |= (WM8994_AIF1_MSTR | WM8994_AIF1_LRCLK_FRC); + wm8994->master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFS: + aif2 |= (WM8994_AIF1_MSTR | WM8994_AIF1_CLK_FRC); + wm8994->master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFM: + aif2 |= (WM8994_AIF1_MSTR | WM8994_AIF1_CLK_FRC | + WM8994_AIF1_LRCLK_FRC); + wm8994->master = 1; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + aif1 |= WM8994_AIF1_LRCLK_INV; + case SND_SOC_DAIFMT_DSP_A: + aif1 |= 0x18; + break; + case SND_SOC_DAIFMT_I2S: + aif1 |= 0x10; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + aif1 |= 0x8; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8994_AIF1_BCLK_INV; + break; + default: + return -EINVAL; + } + break; + + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_LEFT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + aif1 |= WM8994_AIF1_BCLK_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + aif1 |= WM8994_AIF1_LRCLK_INV; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + aif1 |= 0x4000; + wm8994_write(codec, WM8994_AIF1_CONTROL_1, aif1); + wm8994_write(codec, WM8994_AIF1_MASTER_SLAVE, aif2); + wm8994_write(codec, WM8994_AIF1_CONTROL_2, 0x4000); + + return 0; +} + +static int wm8994_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8994_priv *wm8994 = codec->drvdata; + int ret, i, best, best_val, cur_val; + unsigned int clocking1, clocking3, aif1, aif4, aif5; + + DEBUG_LOG(""); + + clocking1 = wm8994_read(codec, WM8994_AIF1_BCLK); + clocking1 &= ~WM8994_AIF1_BCLK_DIV_MASK; + + clocking3 = wm8994_read(codec, WM8994_AIF1_RATE); + clocking3 &= ~(WM8994_AIF1_SR_MASK | WM8994_AIF1CLK_RATE_MASK); + + aif1 = wm8994_read(codec, WM8994_AIF1_CONTROL_1); + aif1 &= ~WM8994_AIF1_WL_MASK; + aif4 = wm8994_read(codec, WM8994_AIF1ADC_LRCLK); + aif4 &= ~WM8994_AIF1ADC_LRCLK_DIR; + aif5 = wm8994_read(codec, WM8994_AIF1DAC_LRCLK); + aif5 &= ~WM8994_AIF1DAC_LRCLK_DIR_MASK; + + wm8994->fs = params_rate(params); + wm8994->bclk = 2 * wm8994->fs; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + wm8994->bclk *= 16; + break; + + case SNDRV_PCM_FORMAT_S20_3LE: + wm8994->bclk *= 20; + aif1 |= (0x01 << WM8994_AIF1_WL_SHIFT); + break; + + case SNDRV_PCM_FORMAT_S24_LE: + wm8994->bclk *= 24; + aif1 |= (0x10 << WM8994_AIF1_WL_SHIFT); + break; + + case SNDRV_PCM_FORMAT_S32_LE: + wm8994->bclk *= 32; + aif1 |= (0x11 << WM8994_AIF1_WL_SHIFT); + break; + + default: + return -EINVAL; + } + + ret = configure_clock(codec); + if (ret != 0) + return ret; + + dev_dbg(codec->dev, "Target BCLK is %dHz\n", wm8994->bclk); + + /* Select nearest CLK_SYS_RATE */ + if (wm8994->fs == 8000) + best = 3; + else { + best = 0; + best_val = abs((wm8994->sysclk_rate / clk_sys_rates[0].ratio) + - wm8994->fs); + + for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { + cur_val = abs((wm8994->sysclk_rate / + clk_sys_rates[i].ratio) - wm8994->fs); + + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", + clk_sys_rates[best].ratio); + } + + clocking3 |= (clk_sys_rates[best].clk_sys_rate + << WM8994_AIF1CLK_RATE_SHIFT); + + /* Sampling rate */ + best = 0; + best_val = abs(wm8994->fs - sample_rates[0].rate); + for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { + cur_val = abs(wm8994->fs - sample_rates[i].rate); + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + dev_dbg(codec->dev, "Selected SAMPLE_RATE of %dHz\n", + sample_rates[best].rate); + + clocking3 |= (sample_rates[best].sample_rate << WM8994_AIF1_SR_SHIFT); + + /* BCLK_DIV */ + best = 0; + best_val = INT_MAX; + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + cur_val = ((wm8994->sysclk_rate) / bclk_divs[i].div) + - wm8994->bclk; + if (cur_val < 0) + break; + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + wm8994->bclk = (wm8994->sysclk_rate) / bclk_divs[best].div; + + dev_dbg(codec->dev, "Selected BCLK_DIV of %d for %dHz BCLK\n", + bclk_divs[best].div, wm8994->bclk); + + clocking1 |= bclk_divs[best].bclk_div << WM8994_AIF1_BCLK_DIV_SHIFT; + + /* LRCLK is a simple fraction of BCLK */ + dev_dbg(codec->dev, "LRCLK_RATE is %d\n", wm8994->bclk / wm8994->fs); + + aif4 |= wm8994->bclk / wm8994->fs; + aif5 |= wm8994->bclk / wm8994->fs; + +#ifdef HDMI_USE_AUDIO + /* set bclk to 32fs for 44.1kHz 16 bit playback.*/ + if (wm8994->fs == 44100) + wm8994_write(codec, WM8994_AIF1_BCLK, 0x70); +#endif + + wm8994_write(codec, WM8994_AIF1_RATE, clocking3); + wm8994_write(codec, WM8994_AIF1_CONTROL_1, aif1); + + return 0; +} + +static int wm8994_digital_mute(struct snd_soc_dai *codec_dai, int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + int mute_reg; + int reg; + + switch (codec_dai->id) { + case 1: + mute_reg = WM8994_AIF1_DAC1_FILTERS_1; + break; + case 2: + mute_reg = WM8994_AIF2_DAC_FILTERS_1; + break; + default: + return -EINVAL; + } + + if (mute) + reg = WM8994_AIF1DAC1_MUTE; + else + reg = 0; + + snd_soc_update_bits(codec, mute_reg, WM8994_AIF1DAC1_MUTE, reg); + + return 0; +} + +static int wm8994_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8994_priv *wm8994 = codec->drvdata; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + wm8994->play_en_dis = 1; + else + wm8994->rec_en_dis = 1; + + if (wm8994->power_state == CODEC_OFF) { + wm8994->power_state = CODEC_ON; + DEBUG_LOG("Turn on codec!! Power state =[%d]", + wm8994->power_state); + + /* For initialize codec */ + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, + 0x3 << WM8994_VMID_SEL_SHIFT | WM8994_BIAS_ENA); + msleep(30); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_NORMAL | WM8994_BIAS_ENA); + wm8994_write(codec, WM8994_OVERSAMPLING, 0x0000); + } else + DEBUG_LOG("Already turned on codec!!"); + + return 0; +} + +static void wm8994_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct wm8994_priv *wm8994 = codec->drvdata; + + DEBUG_LOG("%s.., wm8994->call_state = %d, current path = %d", + __func__, wm8994->call_state, wm8994->cur_path); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + wm8994->play_en_dis = 0; + DEBUG_LOG("..inside..%s..for PLAYBACK_STREAM!!", __func__); + if (wm8994->cur_path != OFF) + wm8994->cur_path = OFF; + } else { + wm8994->rec_en_dis = 0; + DEBUG_LOG("..inside..%s..for CAPTURE_STREAM!!", __func__); + if (wm8994->mic_state == MIC_NO_USE && \ + wm8994->rec_path != MIC_OFF) + wm8994->rec_path = MIC_OFF; + } + + if (wm8994->call_state == DISCONNECT) { + if (!wm8994->play_en_dis && !wm8994->rec_en_dis) { + DEBUG_LOG("Turn off Codec!!"); + gpio_set_value(wm8994->pdata->micbias, 0); + wm8994->power_state = CODEC_OFF; + wm8994_write(codec, WM8994_SOFTWARE_RESET, 0x0000); + return; + } + } + + DEBUG_LOG("Preserve codec state for call[%d].", + wm8994->call_state); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + wm8994->universal_mic_path[MIC_OFF] (codec); + } else { + if (wm8994->call_state == CONNECT) { + int val; + val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_1); + val &= ~(WM8994_AIF1DAC1_MUTE_MASK); + val |= (WM8994_AIF1DAC1_MUTE); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val); + } + } + + DEBUG_LOG("exiting ...%s...", __func__); + +} + +static struct snd_soc_device *wm8994_socdev; +static struct snd_soc_codec *wm8994_codec; + +#define WM8994_RATES SNDRV_PCM_RATE_8000_96000 +#define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static struct snd_soc_dai_ops wm8994_ops = { + .startup = wm8994_startup, + .shutdown = wm8994_shutdown, + .set_sysclk = wm8994_set_sysclk, + .set_fmt = wm8994_set_dai_fmt, + .hw_params = wm8994_hw_params, + .digital_mute = NULL, +}; + +struct snd_soc_dai wm8994_dai = { + + .name = "WM8994 PAIFRX", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 6, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = WM8994_RATES, + .formats = WM8994_FORMATS, + }, + + .ops = &wm8994_ops, +}; + +/* + * initialise the WM8994 driver + * register the mixer and dsp interfaces with the kernel + */ +static int wm8994_init(struct wm8994_priv *wm8994_private) +{ + struct snd_soc_codec *codec = &wm8994_private->codec; + struct wm8994_priv *wm8994; + int ret = 0; + DEBUG_LOG(""); + codec->drvdata = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); + if (codec->drvdata == NULL) + return -ENOMEM; + + wm8994 = codec->drvdata; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + codec->name = "WM8994"; + codec->owner = THIS_MODULE; + codec->read = wm8994_read; + codec->write = wm8994_write; + codec->set_bias_level = NULL; + codec->dai = &wm8994_dai; + codec->num_dai = 1; + wm8994->universal_playback_path = universal_wm8994_playback_paths; + wm8994->universal_voicecall_path = universal_wm8994_voicecall_paths; + wm8994->universal_mic_path = universal_wm8994_mic_paths; + wm8994->universal_clock_control = universal_clock_controls; + wm8994->cur_path = OFF; + wm8994->rec_path = MIC_OFF; + wm8994->call_state = DISCONNECT; + wm8994->power_state = CODEC_OFF; + wm8994->mic_state = MIC_NO_USE; + wm8994->play_en_dis = 0; + wm8994->rec_en_dis = 0; + wm8994->pdata = pdata; + + wm8994->universal_clock_control(codec, CODEC_ON); + + wm8994->codec_clk = clk_get(NULL, "usb_osc"); + + if (IS_ERR(wm8994->codec_clk)) { + pr_err("failed to get MCLK clock from AP\n"); + goto card_err; + } + + wm8994_write(codec, WM8994_SOFTWARE_RESET, 0x0000); + + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, + 0x3 << WM8994_VMID_SEL_SHIFT | WM8994_BIAS_ENA); + msleep(10); + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_NORMAL | WM8994_BIAS_ENA); + + wm8994->hw_version = wm8994_read(codec, 0x100); + + wm8994_socdev->card->codec = codec; + wm8994_codec = codec; + + ret = snd_soc_new_pcms(wm8994_socdev, SNDRV_DEFAULT_IDX1, + SNDRV_DEFAULT_STR1); + if (ret < 0) { + DEBUG_LOG_ERR("failed to create pcms\n"); + goto pcm_err; + } + + wm8994_add_controls(codec); + wm8994_add_widgets(codec); + + return ret; + +card_err: + snd_soc_free_pcms(wm8994_socdev); + snd_soc_dapm_free(wm8994_socdev); +pcm_err: + + return ret; +} + +/* If the i2c layer weren't so broken, we could pass this kind of data + around */ + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + + +static void *control_data1; + +static int wm8994_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_codec *codec; + struct wm8994_priv *wm8994_priv; + int ret; + + DEBUG_LOG(""); + + wm8994_priv = kzalloc(sizeof(struct wm8994_priv), GFP_KERNEL); + if (wm8994_priv == NULL) + return -ENOMEM; + + codec = &wm8994_priv->codec; +#ifdef PM_DEBUG + pm_codec = codec; +#endif + + pdata = i2c->dev.platform_data; + + if (!pdata) + dev_err(&i2c->dev, "failed to initialize WM8994\n"); + + /* CODEC LDO SETTING */ + if (gpio_is_valid(pdata->ldo)) { + ret = gpio_request(pdata->ldo, "WM8994 LDO"); + if (ret) { + pr_err("Failed to request CODEC_LDO_EN!\n"); + goto err_ldo; + } + gpio_direction_output(pdata->ldo, 0); + } + + s3c_gpio_setpull(pdata->ldo, S3C_GPIO_PULL_NONE); + + /* For preserving output of codec related pins */ + s3c_gpio_slp_cfgpin(pdata->ldo, S3C_GPIO_SLP_PREV); + s3c_gpio_slp_setpull_updown(pdata->ldo, S3C_GPIO_PULL_NONE); + + /* EAR_SEL SETTING(only crespo HW) */ + if (gpio_is_valid(pdata->ear_sel)) { + ret = gpio_request(pdata->ear_sel, "EAR SEL"); + if (ret) { + pr_err("Failed to request EAR_SEL!\n"); + goto err_earsel; + } + gpio_direction_output(pdata->ear_sel, 0); + } + s3c_gpio_setpull(pdata->ear_sel, S3C_GPIO_PULL_NONE); + + s3c_gpio_slp_cfgpin(pdata->ear_sel, S3C_GPIO_SLP_PREV); + s3c_gpio_slp_setpull_updown(pdata->ear_sel, S3C_GPIO_PULL_NONE); + + if (gpio_is_valid(pdata->micbias)) { + ret = gpio_request(pdata->micbias, "MICBIAS_EN"); + if (ret) { + pr_err("Failed to request MICBIAS_EN!\n"); + goto err_micbias; + } + gpio_direction_output(pdata->micbias, 0); + } + s3c_gpio_slp_cfgpin(pdata->micbias, S3C_GPIO_SLP_PREV); + + wm8994_ldo_control(pdata, 1); + msleep(10); + + codec->hw_write = (hw_write_t) i2c_master_send; + i2c_set_clientdata(i2c, wm8994_priv); + codec->control_data = i2c; + codec->dev = &i2c->dev; + control_data1 = i2c; + + ret = wm8994_init(wm8994_priv); + if (ret < 0) + dev_err(&i2c->dev, "failed to initialize WM8994\n"); + + return ret; + +err_ldo: + gpio_free(pdata->ldo); + return ret; +err_micbias: + gpio_free(pdata->micbias); + return ret; +err_earsel: + gpio_free(pdata->ear_sel); + return ret; +} + +static int wm8994_i2c_remove(struct i2c_client *client) +{ + struct wm8994_priv *wm8994_priv = i2c_get_clientdata(client); + + gpio_free(pdata->ldo); + gpio_free(pdata->micbias); + gpio_free(pdata->ear_sel); + + kfree(pdata); + kfree(wm8994_priv); + return 0; +} + +static const struct i2c_device_id wm8994_i2c_id[] = { + {"wm8994", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); + +static struct i2c_driver wm8994_i2c_driver = { + .driver = { + .name = "WM8994 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8994_i2c_probe, + .remove = wm8994_i2c_remove, + .id_table = wm8994_i2c_id, +}; + +static int wm8994_add_i2c_device(struct platform_device *pdev, + const struct wm8994_setup_data *setup) +{ + int ret; + + ret = i2c_add_driver(&wm8994_i2c_driver); + if (ret != 0) { + dev_err(&pdev->dev, "can't add i2c driver\n"); + return ret; + } + + return 0; + +err_driver: + i2c_del_driver(&wm8994_i2c_driver); + return -ENODEV; +} +#endif + +static int wm8994_probe(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct wm8994_setup_data *setup; + + int ret = 0; + + pr_info("WM8994 Audio Codec %s\n", WM8994_VERSION); + + setup = socdev->codec_data; + wm8994_socdev = socdev; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + if (setup->i2c_address) + ret = wm8994_add_i2c_device(pdev, setup); +#else + /* Add other interfaces here */ +#endif + return ret; +} + +/* power down chip */ +static int wm8994_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = wm8994_codec; + + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_unregister_device(codec->control_data); + i2c_del_driver(&wm8994_i2c_driver); +#endif + + kfree(codec->drvdata); + + return 0; +} + +#ifdef CONFIG_PM +static int wm8994_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct snd_soc_codec *codec = wm8994_codec; + struct wm8994_priv *wm8994 = codec->drvdata; + + DEBUG_LOG("%s..", __func__); + + if (wm8994->call_state == DISCONNECT && wm8994->cur_path == OFF) { + wm8994->power_state = OFF; + wm8994_write(codec, WM8994_SOFTWARE_RESET, 0x0000); + wm8994_ldo_control(wm8994->pdata, 0); + wm8994->universal_clock_control(codec, CODEC_OFF); + } + + return 0; +} + +static int wm8994_resume(struct platform_device *pdev) +{ + struct snd_soc_codec *codec = wm8994_codec; + struct wm8994_priv *wm8994 = codec->drvdata; + + DEBUG_LOG("%s..", __func__); + DEBUG_LOG_ERR("------WM8994 Revision = [%d]-------", + wm8994->hw_version); + + if (wm8994->call_state == DISCONNECT && wm8994->cur_path == OFF) { + /* Turn on sequence by recommend Wolfson.*/ + wm8994_ldo_control(wm8994->pdata, 1); + wm8994->universal_clock_control(codec, CODEC_ON); + wm8994->power_state = CODEC_ON; + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, + 0x3 << WM8994_VMID_SEL_SHIFT | WM8994_BIAS_ENA); + msleep(50); /* Wait VMID up */ + wm8994_write(codec, WM8994_POWER_MANAGEMENT_1, + WM8994_VMID_SEL_NORMAL | WM8994_BIAS_ENA); + + wm8994_write(codec, WM8994_OVERSAMPLING, 0x0000); + } + return 0; +} +#endif + +struct snd_soc_codec_device soc_codec_dev_wm8994 = { + .probe = wm8994_probe, + .remove = wm8994_remove, +#ifdef CONFIG_PM + .suspend = wm8994_suspend, + .resume = wm8994_resume, +#endif +}; + +static int __init wm8994_modinit(void) +{ + int ret; + ret = snd_soc_register_dai(&wm8994_dai); + if (ret) + pr_err("..dai registration failed..\n"); + + return ret; +} + +module_init(wm8994_modinit); + +static void __exit wm8994_exit(void) +{ + snd_soc_unregister_dai(&wm8994_dai); +} + +module_exit(wm8994_exit); + +MODULE_DESCRIPTION("ASoC WM8994 driver"); +MODULE_AUTHOR("Shaju Abraham shaju.abraham@samsung.com"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wm8994_samsung.h b/sound/soc/codecs/wm8994_samsung.h new file mode 100755 index 0000000..5c285de --- /dev/null +++ b/sound/soc/codecs/wm8994_samsung.h @@ -0,0 +1,119 @@ +/* + * wm8994_samsung.h -- WM8994 Soc Audio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _WM8994_SAMSUNG_H +#define _WM8994_SAMSUNG_H + +#include <sound/soc.h> +#include <linux/mfd/wm8994/wm8994_pdata.h> + +extern struct snd_soc_codec_device soc_codec_dev_wm8994; + +/* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */ +#define WM8994_SYSCLK_MCLK1 1 +#define WM8994_SYSCLK_MCLK2 2 +#define WM8994_SYSCLK_FLL1 3 +#define WM8994_SYSCLK_FLL2 4 + +#define WM8994_FLL1 1 +#define WM8994_FLL2 2 + +/* Added belows codes by Samsung Electronics.*/ + +#include "wm8994_def.h" + +extern struct snd_soc_dai wm8994_dai; + +#define WM8994_SYSCLK_MCLK 1 +#define WM8994_SYSCLK_FLL 2 + +#define AUDIO_COMMON_DEBUG 0 + +/* + * Definitions of enum type + */ +enum audio_path { + OFF, RCV, SPK, HP, BT, SPK_HP, + RING_SPK, RING_HP, RING_SPK_HP +}; +enum mic_path { MAIN, SUB, BT_REC, MIC_OFF}; +enum call_state { DISCONNECT, CONNECT}; +enum power_state { CODEC_OFF, CODEC_ON }; +enum mic_state { MIC_NO_USE, MIC_USE}; +enum ringtone_state { DEACTIVE, ACTIVE}; +enum recognition {REC_OFF, REC_ON}; + +typedef void (*select_route)(struct snd_soc_codec *); +typedef void (*select_mic_route)(struct snd_soc_codec *); +typedef int (*select_clock_control)(struct snd_soc_codec *, int); + + +struct wm8994_setup_data { + int i2c_bus; + unsigned short i2c_address; +}; + +struct wm8994_priv { + struct snd_soc_codec codec; + int master; + int sysclk_source; + unsigned int mclk_rate; + unsigned int sysclk_rate; + unsigned int fs; + unsigned int bclk; + unsigned int hw_version; + enum audio_path cur_path; + enum mic_path rec_path; + enum call_state call_state; + enum power_state power_state; + enum mic_state mic_state; + enum recognition recognition_active; + enum ringtone_state ringtone_active; + select_route *universal_playback_path; + select_route *universal_voicecall_path; + select_mic_route *universal_mic_path; + select_clock_control universal_clock_control; + bool play_en_dis; + bool rec_en_dis; + struct wm8994_platform_data *pdata; + struct clk *codec_clk; +}; + +#if AUDIO_COMMON_DEBUG +#define DEBUG_LOG(format, ...)\ + printk(KERN_INFO "[ "SUBJECT " (%s,%d) ] " format "\n", \ + __func__, __LINE__, ## __VA_ARGS__); +#else +#define DEBUG_LOG(format, ...) +#endif + +#define DEBUG_LOG_ERR(format, ...)\ + printk(KERN_ERR "[ "SUBJECT " (%s,%d) ] " format "\n", \ + __func__, __LINE__, ## __VA_ARGS__); + +/* Definitions of function prototype. */ +inline unsigned int wm8994_read(struct snd_soc_codec *codec, unsigned int reg); +int wm8994_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value); +int wm8994_configure_clock(struct snd_soc_codec *codec, int en); +void wm8994_disable_playback_path(struct snd_soc_codec *codec, + enum audio_path path); +void wm8994_disable_rec_path(struct snd_soc_codec *codec); +void wm8994_record_main_mic(struct snd_soc_codec *codec); +void wm8994_record_headset_mic(struct snd_soc_codec *codec); +void wm8994_record_bluetooth(struct snd_soc_codec *codec); +void wm8994_set_playback_receiver(struct snd_soc_codec *codec); +void wm8994_set_playback_headset(struct snd_soc_codec *codec); +void wm8994_set_playback_speaker(struct snd_soc_codec *codec); +void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec); +void wm8994_set_voicecall_common_setting(struct snd_soc_codec *codec); +void wm8994_set_voicecall_receiver(struct snd_soc_codec *codec); +void wm8994_set_voicecall_headset(struct snd_soc_codec *codec); +void wm8994_set_voicecall_speaker(struct snd_soc_codec *codec); +void wm8994_set_voicecall_bluetooth(struct snd_soc_codec *codec); +#endif diff --git a/sound/soc/samsung/herring-wm8994.c b/sound/soc/samsung/herring-wm8994.c index ca33b46..d19e2ef 100644 --- a/sound/soc/samsung/herring-wm8994.c +++ b/sound/soc/samsung/herring-wm8994.c @@ -18,7 +18,7 @@ #include <sound/soc-dapm.h> #include <mach/regs-clock.h> #include <plat/regs-iis.h> -#include "../codecs/wm8994.h" +#include "../codecs/wm8994_samsung.h" #include "s3c-dma.h" #include "s5pc1xx-i2s.h" #include "s3c-i2s-v2.h" |