diff options
author | supercurio <supercurio@gmail.com> | 2011-11-23 22:26:41 +0100 |
---|---|---|
committer | KalimochoAz <calimochoazucarado@gmail.com> | 2011-12-19 12:15:15 +0100 |
commit | dbaf5858c22315a61fc4cd9c02fe5c1a55295231 (patch) | |
tree | 90035c46549c0f4be2de65c642f79b723f80ee00 /sound | |
parent | b29527f97c21f5e3d1085d6758855059ed915491 (diff) | |
download | kernel_samsung_crespo-dbaf5858c22315a61fc4cd9c02fe5c1a55295231.zip kernel_samsung_crespo-dbaf5858c22315a61fc4cd9c02fe5c1a55295231.tar.gz kernel_samsung_crespo-dbaf5858c22315a61fc4cd9c02fe5c1a55295231.tar.bz2 |
Voodoo sound: update to driver v5
- New speaker tuning mode for music using different
hardware EQ settings than stock ones
- Microphone presets now supported on Nexus S.
- Microphone presets balanced and loud reworked
with lower background noise and higher dynamic range
for balanced: -2dB noise, +6dB dynamic range.
- New DAC direct option: reduces distortion and improves
SNR by a small margin (bypass usless analog channel mixer)
- Anti-jitter mode on by default.
- Same exact source is now used on each device supported
(still: only useful code is compiled in via ifdefs)
- ability to fully disable/re-enable the driver and
its sysfs interface: 0 or 1 in
/sys/class/misc/voodoo_sound_control/enable
- refactored source code
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/Kconfig.voodoo | 18 | ||||
-rwxr-xr-x | sound/soc/codecs/wm8994_herring.c | 6 | ||||
-rwxr-xr-x | sound/soc/codecs/wm8994_samsung.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994_voodoo.c | 599 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994_voodoo.h | 30 |
5 files changed, 463 insertions, 192 deletions
diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo index 7f07e6d..af418fb 100644 --- a/sound/soc/codecs/Kconfig.voodoo +++ b/sound/soc/codecs/Kconfig.voodoo @@ -1,6 +1,6 @@ menuconfig SND_VOODOO bool "Voodoo sound driver" - depends on SND_S3C24XX_SOC + depends on SND_UNIVERSAL_WM8994 || SND_S3C24XX_SOC default y help With this option enabled, the kernel compile an additionnal driver @@ -17,15 +17,29 @@ config SND_VOODOO_HP_LEVEL_CONTROL config SND_VOODOO_HP_LEVEL int "default level at boot 0-62" depends on SND_VOODOO_HP_LEVEL_CONTROL - default 54 + default 54 if MACH_HERRING=y || M110S=y + default 47 range 0 62 help Default headphone amplifier level. Take care not setting it to high, it would introduce hiss for people not using the control app +config SND_VOODOO_RECORD_PRESETS + bool "Microphone recording presets" + depends on SND_VOODOO + default y + help + Recording presets with Dynamic Range Compression auto-gain + on microphone: + - Original + - High sensitivity + - Balanced (recommanded, default) + - Loud environment - concert + config SND_VOODOO_FM bool "FM radio: restore a normal frequency response" depends on SND_VOODOO && SND_ARIES_SOC_WM8994 + default n if S5PC110_T959_BOARD=y || S5PC110_KEPLER_BOARD=y || S5PV210_VICTORY=y || M110S=y default y help Adds a control to enable or disable the high-pass filter on FM radio diff --git a/sound/soc/codecs/wm8994_herring.c b/sound/soc/codecs/wm8994_herring.c index c5bbdf2..28e2320 100755 --- a/sound/soc/codecs/wm8994_herring.c +++ b/sound/soc/codecs/wm8994_herring.c @@ -21,7 +21,9 @@ #include <mach/regs-clock.h> #include "wm8994_samsung.h" #include "../../../arch/arm/mach-s5pv210/herring.h" +#ifdef CONFIG_SND_VOODOO #include "wm8994_voodoo.h" +#endif /* * Debug Feature @@ -2168,6 +2170,10 @@ void wm8994_set_playback_speaker(struct snd_soc_codec *codec) val |= WM8994_AIF1DAC1L_TO_DAC1L; wm8994_write(codec, WM8994_DAC1_LEFT_MIXER_ROUTING, val); +#ifdef CONFIG_SND_VOODOO + voodoo_hook_playback_speaker(); +#endif + /* Enbale bias,vmid and Left speaker */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | diff --git a/sound/soc/codecs/wm8994_samsung.c b/sound/soc/codecs/wm8994_samsung.c index ea4736a..4b646e0 100755 --- a/sound/soc/codecs/wm8994_samsung.c +++ b/sound/soc/codecs/wm8994_samsung.c @@ -41,7 +41,9 @@ #include <mach/regs-clock.h> #include "wm8994_samsung.h" #include "../../../arch/arm/mach-s5pv210/herring.h" +#ifdef CONFIG_SND_VOODOO #include "wm8994_voodoo.h" +#endif #define WM8994_VERSION "0.1" #define SUBJECT "wm8994_samsung.c" diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 7065df1..8d0f117 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -1,7 +1,7 @@ /* * voodoo_sound.c -- WM8994 ALSA Soc Audio driver related * - * Copyright (C) 2010 François SIMOND / twitter & XDA-developers @supercurio + * Copyright (C) 2010/11 François SIMOND / twitter & XDA-developers @supercurio * * 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 @@ -11,20 +11,17 @@ */ #include <sound/soc.h> -#include <sound/soc-dapm.h> #include <linux/delay.h> -#include <asm/io.h> -#include <asm/gpio.h> -#include <plat/gpio-cfg.h> -#include <plat/map-base.h> -#include <mach/regs-clock.h> -#include <mach/gpio.h> #include <linux/miscdevice.h> -#include "wm8994_samsung.h" #include "wm8994_voodoo.h" +#ifdef NEXUS_S +#include "wm8994_samsung.h" +#else +#include "wm8994.h" +#endif #define SUBJECT "wm8994_voodoo.c" -#define VOODOO_SOUND_VERSION 4 +#define VOODOO_SOUND_VERSION 5 bool bypass_write_hook = false; @@ -41,17 +38,53 @@ bool fm_radio_headset_normalize_gain = true; #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS unsigned short recording_preset = 1; +unsigned short original_record_gain; +unsigned short original_record_gain_input_mixer; #endif +#ifdef NEXUS_S +bool speaker_tuning = false; +#endif + +// global active or kill switch +bool enable = false; + bool dac_osr128 = true; bool adc_osr128 = false; -bool fll_tuning = false; +bool fll_tuning = true; +bool dac_direct = true; bool mono_downmix = false; // keep here a pointer to the codec structure struct snd_soc_codec *codec_; +#define DECLARE_BOOL_SHOW(name) \ +static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return sprintf(buf,"%u\n",(name ? 1 : 0)); \ +} + +#define DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(name, updater, with_mute) \ +static ssize_t name##_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) \ +{ \ + unsigned short state; \ + if (sscanf(buf, "%hu", &state) == 1) \ + { \ + name = state == 0 ? false : true; \ + updater(with_mute); \ + } \ + return size; \ +} + + +#ifdef NEXUS_S +#define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->drvdata; +#else +#define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->private_data; +#endif + + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL void update_hpvol() { @@ -83,6 +116,11 @@ void update_fm_radio_headset_restore_freqs(bool with_mute) { unsigned short val; + // apply only when FM radio is active + DECLARE_WM8994(codec_) + if (wm8994->fmradio_path == FMR_OFF) + return; + if (with_mute) { wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x236); @@ -123,8 +161,13 @@ void update_fm_radio_headset_restore_freqs(bool with_mute) } } -void update_fm_radio_headset_normalize_gain() +void update_fm_radio_headset_normalize_gain(bool with_mute) { + // apply only when FM radio is active + DECLARE_WM8994(codec_) + if (wm8994->fmradio_path == FMR_OFF) + return; + if (fm_radio_headset_normalize_gain) { // Bumped volume, change with Zero Cross @@ -152,64 +195,202 @@ void update_fm_radio_headset_normalize_gain() #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS -void update_recording_preset() +void update_recording_preset(bool with_mute) { - switch (recording_preset) + if (is_path(MAIN_MICROPHONE)) { - case 0: - { - // Original: - // IN1L_VOL1=11000 (+19.5 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0118); - // DRC disabled - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x0080); - break; - } - case 2: - { - // High sensitivy: Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); - // DRC Input: -6dB, Ouptut -3.75dB - // Above knee 1/8, Below knee 1/2 - // Max gain 24 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0426); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0105); - break; - } - case 3: - { - // Concert: Original - 36 dB IN1L_VOL1=00000 (-16.5 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); - // DRC Input: -4.5dB, Ouptut -6.75dB - // Above knee 1/4, Below knee 1/2 - // Max gain 18 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0845); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0011); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); - break; - } - default: + switch (recording_preset) { - // make sure recording_preset is the default: 4 - recording_preset = 1; - // Balanced: Original - 16.5 dB, IN1L_VOL1=01101 (+3 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x054D); - // DRC Input: -13.5dB, Ouptut -9dB - // Above knee 1/8, Below knee 1/2 - // Max gain 12 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0844); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x024C); - break; + case 0: + { +#ifdef NEXUS_S + printk("Voodoo sound: Nexus S original microphone gain & input mixer: 0x%X, 0x%X\n", + original_record_gain, original_record_gain_input_mixer); +#endif + // Original: + // On Galaxy S: IN1L_VOL1=11000 (+19.5 dB) + // On Nexus S: variable value + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, WM8994_IN1L_VU | original_record_gain ); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, original_record_gain_input_mixer); + // DRC disabled + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x0080); + break; + } + case 2: + { + // High sensitivy: Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x30); + // DRC Input: -6dB, Ouptut -3.75dB + // Above knee 1/8, Below knee 1/2 + // Max gain 24 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0426); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0105); + break; + } + case 3: + { + // Concert new: IN1L_VOL1=10110 (+4.5 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x010F); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -4.5dB, Ouptut -6.75dB + // Above knee 1/4, Below knee 1/2 + // Max gain 24 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0846); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0011); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); + break; + } + case 4: + { + // ULTRA LOUD: Original - 36 dB - 30 dB IN1L_VOL1=00000 (-16.5 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -7.5dB, Ouptut -6dB + // Above knee 1/8, Below knee 1/4 + // Max gain 36 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0847); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x001A); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); + break; + } + default: + { + // make sure recording_preset is the default + recording_preset = 1; + // New Balanced: Original - 16.5 dB + // IN1L_VOL1=01101 (+27 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x055D); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -18.5dB, Ouptut -9dB + // Above knee 1/8, Below knee 1/2 + // Max gain 18 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0845); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x030C); + break; + } } } } #endif +bool is_path(int unified_path) +{ + DECLARE_WM8994(codec_) + + switch(unified_path) + { + // speaker + case SPEAKER: +#ifdef GALAXY_TAB + if (wm8994->cur_path != SPK && wm8994->cur_path != RING_SPK && + wm8994->fmradio_path != FMR_SPK && wm8994->fmradio_path != FMR_SPK_MIX) +#else + if (wm8994->cur_path != SPK && wm8994->cur_path != RING_SPK) +#endif + return true; + + // headphones + // FIXME: be sure dac_direct doesn't break phone calls on TAB + // with these spath detection settings (HP4P) + case HEADPHONES: +#ifdef NEXUS_S + if (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC) +#else +#ifdef GALAXY_TAB + if (wm8994->cur_path == HP3P || wm8994->cur_path == HP4P || wm8994->fmradio_path == FMR_HP) +#else +#ifdef M110S + if (wm8994->cur_path == HP) +#else + if (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP) +#endif +#endif +#endif + return true; + + + // headphones + // FIXME: be sure dac_direct doesn't break phone calls on TAB + // with these spath detection settings (HP4P) + case MAIN_MICROPHONE: + if (wm8994->rec_path == MAIN) + return true; + + } + return false; +} + +#ifdef NEXUS_S +void update_speaker_tuning(bool with_mute) +{ + if (speaker_tuning) + { + // DRC settings + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0010); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00EB); + + // hardware EQ + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x041D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x4C00); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FE3); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x0403); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x0074); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F03); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0F9); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x03DA); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1ED2); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF11A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x045D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_A, 0x0E76); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_B, 0xFCE4); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_PG, 0x330D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_A, 0xFC8F); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_B, 0x0400); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_PG, 0x323C); + + // Speaker Boost tuning + wm8994_write(codec_, WM8994_CLASSD, 0x0170); + } + else + { + // DRC settings + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0028); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0186); + + // hardware EQ + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x6280); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FC3); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x03FD); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x00F4); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F30); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0CD); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x032C); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1C52); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF379); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x0DC1); + wm8994_write(codec_, WM8994_CLASSD, 0x0170); + + // Speaker Boost tuning + wm8994_write(codec_, WM8994_CLASSD, 0x0168); + } +} +#endif unsigned short osr128_get_value(unsigned short val) { @@ -225,7 +406,7 @@ unsigned short osr128_get_value(unsigned short val) return val; } -void update_osr128() +void update_osr128(bool with_mute) { unsigned short val; val = osr128_get_value(wm8994_read(codec_, WM8994_OVERSAMPLING)); @@ -242,7 +423,7 @@ unsigned short fll_tuning_get_value(unsigned short val) return val; } -void update_fll_tuning() +void update_fll_tuning(bool with_mute) { unsigned short val; val = fll_tuning_get_value(wm8994_read(codec_, WM8994_FLL1_CONTROL_4)); @@ -254,15 +435,19 @@ void update_fll_tuning() unsigned short mono_downmix_get_value(unsigned short val) { - if (mono_downmix) - val |= WM8994_AIF1DAC1_MONO; - else - val &= ~WM8994_AIF1DAC1_MONO; + // depends on the output path in order to preserve mono downmixing + // on speaker + if (is_path(SPEAKER)) + { + if (mono_downmix) + val |= WM8994_AIF1DAC1_MONO; + else + val &= ~WM8994_AIF1DAC1_MONO; + } return val; } - -void update_mono_downmix() +void update_mono_downmix(bool with_mute) { unsigned short val1, val2, val3; val1 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF1_DAC1_FILTERS_1)); @@ -276,6 +461,32 @@ void update_mono_downmix() bypass_write_hook = false; } +unsigned short dac_direct_get_value(unsigned short val) +{ + if (is_path(HEADPHONES)) + { + if (dac_direct) + val = (val == WM8994_DAC1L_TO_MIXOUTL) ? WM8994_DAC1L_TO_HPOUT1L : val; + else + val = (val == WM8994_DAC1L_TO_HPOUT1L) ? WM8994_DAC1L_TO_MIXOUTL : val; + } + + return val; +} + +void update_dac_direct(bool with_mute) +{ + unsigned short val1, val2; + val1 = dac_direct_get_value(wm8994_read(codec_, WM8994_OUTPUT_MIXER_1)); + val2 = dac_direct_get_value(wm8994_read(codec_, WM8994_OUTPUT_MIXER_2)); + + bypass_write_hook = true; + wm8994_write(codec_, WM8994_OUTPUT_MIXER_1, val1); + wm8994_write(codec_, WM8994_OUTPUT_MIXER_2, val2); + bypass_write_hook = false; +} + + /* * * Declaring the controling misc devices @@ -301,55 +512,20 @@ static ssize_t headphone_amplifier_level_store(struct device *dev, struct device } #endif +#ifdef NEXUS_S +DECLARE_BOOL_SHOW(speaker_tuning) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(speaker_tuning, update_speaker_tuning, false) +#endif #ifdef CONFIG_SND_VOODOO_FM -static ssize_t fm_radio_headset_restore_bass_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fm_radio_headset_restore_bass ? 1 : 0)); -} - -static ssize_t fm_radio_headset_restore_bass_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fm_radio_headset_restore_bass = state == 0 ? false : true; - update_fm_radio_headset_restore_freqs(true); - } - return size; -} +DECLARE_BOOL_SHOW(fm_radio_headset_restore_bass) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_bass, update_fm_radio_headset_restore_freqs, true) -static ssize_t fm_radio_headset_restore_highs_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fm_radio_headset_restore_highs ? 1 : 0)); -} +DECLARE_BOOL_SHOW(fm_radio_headset_restore_highs) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_highs, update_fm_radio_headset_restore_freqs, true) -static ssize_t fm_radio_headset_restore_highs_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fm_radio_headset_restore_highs = state == 0 ? false : true; - update_fm_radio_headset_restore_freqs(true); - } - return size; -} - -static ssize_t fm_radio_headset_normalize_gain_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fm_radio_headset_restore_highs ? 1 : 0)); -} - -static ssize_t fm_radio_headset_normalize_gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fm_radio_headset_normalize_gain = state == 0 ? false : true; - update_fm_radio_headset_normalize_gain(); - } - return size; -} +DECLARE_BOOL_SHOW(fm_radio_headset_normalize_gain) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_normalize_gain, update_fm_radio_headset_normalize_gain, false) #endif @@ -365,76 +541,27 @@ static ssize_t recording_preset_store(struct device *dev, struct device_attribut if (sscanf(buf, "%hu", &preset_number) == 1) { recording_preset = preset_number; - update_recording_preset(); + update_recording_preset(false); } return size; } #endif -static ssize_t dac_osr128_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(dac_osr128 ? 1 : 0)); -} - -static ssize_t dac_osr128_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - dac_osr128 = state == 0 ? false : true; - update_osr128(); - } - return size; -} - -static ssize_t adc_osr128_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(adc_osr128 ? 1 : 0)); -} - -static ssize_t adc_osr128_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - adc_osr128 = state == 0 ? false : true; - update_osr128(); - } - return size; -} +DECLARE_BOOL_SHOW(dac_osr128) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_osr128, update_osr128, false) -static ssize_t fll_tuning_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fll_tuning ? 1 : 0)); -} +DECLARE_BOOL_SHOW(adc_osr128) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(adc_osr128, update_osr128, false) -static ssize_t fll_tuning_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fll_tuning = state == 0 ? false : true; - update_fll_tuning(); - } - return size; -} +DECLARE_BOOL_SHOW(fll_tuning) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fll_tuning, update_fll_tuning, false) -static ssize_t mono_downmix_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(mono_downmix ? 1 : 0)); -} +DECLARE_BOOL_SHOW(mono_downmix) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(mono_downmix, update_mono_downmix, false) -static ssize_t mono_downmix_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - mono_downmix = state == 0 ? false : true; - update_mono_downmix(); - } - return size; -} +DECLARE_BOOL_SHOW(dac_direct) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_direct, update_dac_direct, false) #ifdef CONFIG_SND_VOODOO_DEBUG @@ -515,9 +642,31 @@ static ssize_t voodoo_sound_version(struct device *dev, struct device_attribute return sprintf(buf, "%u\n", VOODOO_SOUND_VERSION); } + +DECLARE_BOOL_SHOW(enable) +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + bool bool_state; + if (sscanf(buf, "%hu", &state) == 1) + { + bool_state = state == 0 ? false : true; + if (state != enable) + { + enable = bool_state; + update_enable(); + } + } + return size; +} + + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL static DEVICE_ATTR(headphone_amplifier_level, S_IRUGO | S_IWUGO , headphone_amplifier_level_show, headphone_amplifier_level_store); #endif +#ifdef NEXUS_S +static DEVICE_ATTR(speaker_tuning, S_IRUGO | S_IWUGO , speaker_tuning_show, speaker_tuning_store); +#endif #ifdef CONFIG_SND_VOODOO_FM static DEVICE_ATTR(fm_radio_headset_restore_bass, S_IRUGO | S_IWUGO , fm_radio_headset_restore_bass_show, fm_radio_headset_restore_bass_store); static DEVICE_ATTR(fm_radio_headset_restore_highs, S_IRUGO | S_IWUGO , fm_radio_headset_restore_highs_show, fm_radio_headset_restore_highs_store); @@ -529,6 +678,7 @@ static DEVICE_ATTR(recording_preset, S_IRUGO | S_IWUGO , recording_preset_show, static DEVICE_ATTR(dac_osr128, S_IRUGO | S_IWUGO , dac_osr128_show, dac_osr128_store); static DEVICE_ATTR(adc_osr128, S_IRUGO | S_IWUGO , adc_osr128_show, adc_osr128_store); static DEVICE_ATTR(fll_tuning, S_IRUGO | S_IWUGO , fll_tuning_show, fll_tuning_store); +static DEVICE_ATTR(dac_direct, S_IRUGO | S_IWUGO , dac_direct_show, dac_direct_store); static DEVICE_ATTR(mono_downmix, S_IRUGO | S_IWUGO , mono_downmix_show, mono_downmix_store); #ifdef CONFIG_SND_VOODOO_DEBUG static DEVICE_ATTR(wm8994_register_dump, S_IRUGO , show_wm8994_register_dump, NULL); @@ -536,10 +686,15 @@ static DEVICE_ATTR(wm8994_write, S_IWUSR , NULL, store_wm8994_write); #endif static DEVICE_ATTR(version, S_IRUGO , voodoo_sound_version, NULL); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUGO , enable_show, enable_store); + static struct attribute *voodoo_sound_attributes[] = { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL &dev_attr_headphone_amplifier_level.attr, #endif +#ifdef NEXUS_S + &dev_attr_speaker_tuning.attr, +#endif #ifdef CONFIG_SND_VOODOO_FM &dev_attr_fm_radio_headset_restore_bass.attr, &dev_attr_fm_radio_headset_restore_highs.attr, @@ -551,6 +706,7 @@ static struct attribute *voodoo_sound_attributes[] = { &dev_attr_dac_osr128.attr, &dev_attr_adc_osr128.attr, &dev_attr_fll_tuning.attr, + &dev_attr_dac_direct.attr, &dev_attr_mono_downmix.attr, #ifdef CONFIG_SND_VOODOO_DEBUG &dev_attr_wm8994_register_dump.attr, @@ -560,15 +716,53 @@ static struct attribute *voodoo_sound_attributes[] = { NULL }; +static struct attribute *voodoo_sound_control_attributes[] = { + &dev_attr_enable.attr, + NULL +}; + static struct attribute_group voodoo_sound_group = { .attrs = voodoo_sound_attributes, }; +static struct attribute_group voodoo_sound_control_group = { + .attrs = voodoo_sound_control_attributes, +}; + static struct miscdevice voodoo_sound_device = { .minor = MISC_DYNAMIC_MINOR, .name = "voodoo_sound", }; +static struct miscdevice voodoo_sound_control_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "voodoo_sound_control", +}; + + +void voodoo_hook_wm8994_pcm_remove() { + printk("Voodoo sound: removing driver v%d\n", VOODOO_SOUND_VERSION); + sysfs_remove_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group); + misc_deregister(&voodoo_sound_device); +} + + +void update_enable() +{ + if (enable) + { + printk("Voodoo sound: initializing driver v%d\n", VOODOO_SOUND_VERSION); + misc_register(&voodoo_sound_device); + if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group) < 0) + { + printk("%s sysfs_create_group fail\n", __FUNCTION__); + pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_device.name); + } + } + else + voodoo_hook_wm8994_pcm_remove(); +} + /* * @@ -579,11 +773,15 @@ static struct miscdevice voodoo_sound_device = { #ifdef CONFIG_SND_VOODOO_FM void voodoo_hook_fmradio_headset() { + // global kill switch + if (! enable) + return; + if (! fm_radio_headset_restore_bass && ! fm_radio_headset_restore_highs && !fm_radio_headset_normalize_gain) return; update_fm_radio_headset_restore_freqs(false); - update_fm_radio_headset_normalize_gain(); + update_fm_radio_headset_normalize_gain(false); } #endif @@ -591,24 +789,48 @@ void voodoo_hook_fmradio_headset() #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS void voodoo_hook_record_main_mic() { - update_recording_preset(); + // global kill switch + if (! enable) + return; + + if (recording_preset == 0) + return; + + original_record_gain = wm8994_read(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); + original_record_gain_input_mixer = wm8994_read(codec_, WM8994_INPUT_MIXER_3); + update_recording_preset(false); } #endif -void voodoo_hook_playback_headset() + +void voodoo_hook_playback_speaker() { + // global kill switch + if (! enable) + return; +#ifdef NEXUS_S + if (! speaker_tuning) + return; + + update_speaker_tuning(false); +#endif } unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - struct wm8994_priv *wm8994 = codec->drvdata; + // global kill switch + if (! enable) + return value; + // modify some registers before those being written to the codec + // be sure our pointer to codec is up to date + codec_ = codec; if (! bypass_write_hook) { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL - if (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC) + if (is_path(HEADPHONES)) { if (reg == WM8994_LEFT_OUTPUT_VOLUME) value = (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | hplvol); @@ -622,13 +844,20 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int value = fll_tuning_get_value(value); if (reg == WM8994_AIF1_DAC1_FILTERS_1 || reg == WM8994_AIF1_DAC2_FILTERS_1 || reg == WM8994_AIF2_DAC_FILTERS_1) value = mono_downmix_get_value(value); + if (reg == WM8994_OUTPUT_MIXER_1 || reg == WM8994_OUTPUT_MIXER_2) + value = dac_direct_get_value(value); } #ifdef CONFIG_SND_VOODOO_DEBUG_LOG // log every write to dmesg printk("Voodoo sound: wm8994_write register= [%X] value= [%X]\n", reg, value); +#ifdef NEXUS_S printk("Voodoo sound: cur_path=%i, rec_path=%i, power_state=%i\n", wm8994->cur_path, wm8994->rec_path, wm8994->power_state); +#else + printk("Voodoo sound: cur_path=%i, rec_path=%i, fmradio_path=%i, fmr_mix_path=%i, power_state=%i, recognition_active=%i, ringtone_active=%i\n", + wm8994->cur_path, wm8994->rec_path, wm8994->fmradio_path, wm8994->fmr_mix_path, wm8994->power_state, wm8994->recognition_active, wm8994->ringtone_active); +#endif #endif return value; } @@ -636,12 +865,14 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec) { - printk("Voodoo sound: driver v%d\n", VOODOO_SOUND_VERSION); - misc_register(&voodoo_sound_device); - if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group) < 0) + enable = true; + update_enable(); + + misc_register(&voodoo_sound_control_device); + if (sysfs_create_group(&voodoo_sound_control_device.this_device->kobj, &voodoo_sound_control_group) < 0) { printk("%s sysfs_create_group fail\n", __FUNCTION__); - pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_device.name); + pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_control_device.name); } // make a copy of the codec pointer diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h index 0b8e63e..e7a31b0 100644 --- a/sound/soc/codecs/wm8994_voodoo.h +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -6,17 +6,35 @@ * published by the Free Software Foundation. */ +bool is_path(int unified_path); void voodoo_hook_fmradio_headset(void); unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec); +void voodoo_hook_wm8994_pcm_remove(void); void voodoo_hook_record_main_mic(void); -void voodoo_hook_playback_headset(void); +void voodoo_hook_playback_speaker(void); void update_hpvol(void); void update_fm_radio_headset_restore_freqs(bool with_mute); -void update_fm_radio_headset_normalize_gain(void); -void update_recording_preset(void); +void update_fm_radio_headset_normalize_gain(bool with_mute); +void update_recording_preset(bool with_mute); void update_full_bitwidth(bool with_mute); -void update_osr128(void); -void update_fll_tuning(void); +void update_osr128(bool with_mute); +void update_fll_tuning(bool with_mute); +void update_mono_downmix(bool with_mute); +void update_dac_direct(bool with_mute); +void update_enable(void); unsigned short tune_fll_value(unsigned short val); -void update_mono_downmix(void); + +#ifdef CONFIG_MACH_HERRING +#define NEXUS_S +#endif + +#ifdef CONFIG_FB_S3C_AMS701KA +#define GALAXY_TAB +#endif + +#ifdef CONFIG_M110S +#define M110S +#endif + +enum unified_path { HEADPHONES, SPEAKER, MAIN_MICROPHONE }; |