aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorsupercurio <supercurio@gmail.com>2011-11-23 22:26:41 +0100
committerKalimochoAz <calimochoazucarado@gmail.com>2011-12-19 12:15:15 +0100
commitdbaf5858c22315a61fc4cd9c02fe5c1a55295231 (patch)
tree90035c46549c0f4be2de65c642f79b723f80ee00 /sound
parentb29527f97c21f5e3d1085d6758855059ed915491 (diff)
downloadkernel_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.voodoo18
-rwxr-xr-xsound/soc/codecs/wm8994_herring.c6
-rwxr-xr-xsound/soc/codecs/wm8994_samsung.c2
-rw-r--r--sound/soc/codecs/wm8994_voodoo.c599
-rw-r--r--sound/soc/codecs/wm8994_voodoo.h30
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 };