From df44533e336c5fde76a0912ad1c68d5f08f38e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Sat, 23 Oct 2010 03:34:20 +0200 Subject: [PATCH] Voodoo sound: introducing usage of the ReTune hardware parametric EQ This first extension allow usage of the parametric hardware EQ in order to reduce harshness found in high frequencies. With the current setup, high frequencies around 20kHz create an associated white noise and tend to make highs fatiguing and unclean. I don't know if it's a limit of the oversampling abilities of the codec, but the method employed here is surprisingly effective. The only drawback is that alter (reduce) the high frequency response for very high frequencies. It can slightly affect the brightness and it's probably not recommended to use it if your headphone already lack brightness. However it's tuned to mostly removes noise artifacts and frequencies which are not reproduced accurately in the default codec config. This anti-alias filter can be tweaked live through sysfs as simple user. filename: /sys/devices/virtual/voodoo_sound/parametric_equalizer/anti_alias_filter 0: anti-alias filter disabled 1: anti-alias filter enabled, simple mode. 1 high-shelf 2: anti-alias filter enabled, advanced mode. 1 parametric EQ band + 1 high-shelf For novice listeners, this filter's effect can be difficult to identify. Testing with udial.wav make a very clear demonstration of its efficiency ;) --- Kernel/sound/soc/codecs/wm8994_aries.c | 89 ++++++++++++++++++++++++-- Kernel/sound/soc/s3c24xx/Kconfig | 8 +++ 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/Kernel/sound/soc/codecs/wm8994_aries.c b/Kernel/sound/soc/codecs/wm8994_aries.c index c90924c8f..4967fc3ef 100755 --- a/Kernel/sound/soc/codecs/wm8994_aries.c +++ b/Kernel/sound/soc/codecs/wm8994_aries.c @@ -172,9 +172,12 @@ extern short int get_headset_status(void); // For ear-jack control(MIC-Bias) extern void set_recording_status(int value); // For preventing MIC Bias off on using MIC. -#ifdef CONFIG_SND_VOODOO_SOUND_HEADPHONE_AMP_GAIN -// Voodoo sound +#ifdef CONFIG_SND_VOODOO_SOUND_RETUNE_EQ +// by default the anti-alias filter is disabled +unsigned short voodoo_anti_alias_filter = 0; +#endif +#ifdef CONFIG_SND_VOODOO_SOUND_HEADPHONE_AMP_GAIN // Creating variables which we will use to save the headphone amplifier // gain chose by the user through sysfs interface // min: 0x0, max 3B ( 3C -> 3F = saturation & distortion ) @@ -190,9 +193,16 @@ struct device *voodoo_sound_dev; // Voodoo sound: headphone amplifier gain -static void voodoo_update_headphone_volumes() +void voodoo_update_headphone_volumes(void) { unsigned short val; + + // hard limit to 61 because 62 and 63 introduce distortion + if (voodoo_headphone_left_volume > 62) + voodoo_headphone_left_volume = 62; + if (voodoo_headphone_right_volume > 62) + voodoo_headphone_right_volume = 62; + // we don't need the Volume Update flag when sending the first volume //printk("Voodoo sound: setting headphone volume: left %u\n", voodoo_headphone_left_volume); val = (WM8994_HPOUT1L_MUTE_N | voodoo_headphone_left_volume); @@ -247,7 +257,6 @@ static ssize_t gain_store(struct device *dev, static DEVICE_ATTR(gain_lr,0666, gain_lr_show, gain_lr_store); // create the sysfs device to allow read and write static DEVICE_ATTR(gain,0666, gain_show, gain_store); - #endif @@ -271,7 +280,7 @@ static ssize_t wm8994_write_store(struct device *dev, { short unsigned int register_address = 0x0; short unsigned int val = 0x0; - if (sscanf(buf, "%hx %hx", ®ister_address, &val) != 1) + if (sscanf(buf, "%hx %hx", ®ister_address, &val) == 2) wm8994_write(voodoo_codec, register_address, val); return size; @@ -281,6 +290,61 @@ static DEVICE_ATTR(wm8994_write,0600, wm8994_write_show, wm8994_write_store); #endif +#ifdef CONFIG_SND_VOODOO_SOUND_RETUNE_EQ +// Voodoo sound: use the hardware parametric equalizer + +void voodoo_update_anti_alias_filter(void) +{ + + // Use the parametric EQ to create an anti-alias filter + // printk("Voodoo sound: applying anti-alias filter\n"); + + if (voodoo_anti_alias_filter == 1) + { + // anti-alias 1 (only high-shelf) + wm8994_write(voodoo_codec, 0x480, 0x6319); + wm8994_write(voodoo_codec, 0x481, 0x6000); + wm8994_write(voodoo_codec, 0x491, 0xF692); + wm8994_write(voodoo_codec, 0x492, 0x0400); + wm8994_write(voodoo_codec, 0x493, 0x1A48); + } + if (voodoo_anti_alias_filter == 2) + { + // anti alias 2 (1 parametric band + high-shelf) + wm8994_write(voodoo_codec, 0x480, 0x6319); + wm8994_write(voodoo_codec, 0x481, 0x0000); + wm8994_write(voodoo_codec, 0x48D, 0xE386); + wm8994_write(voodoo_codec, 0x48E, 0xF1B2); + wm8994_write(voodoo_codec, 0x48F, 0x040A); + wm8994_write(voodoo_codec, 0x490, 0x06B7); + wm8994_write(voodoo_codec, 0x491, 0xF474); + wm8994_write(voodoo_codec, 0x492, 0x0400); + wm8994_write(voodoo_codec, 0x493, 0x11D0); + } +} + +static ssize_t anti_alias_filter_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%hu\n",voodoo_anti_alias_filter); + return 0; +} + +static ssize_t anti_alias_filter_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + sscanf(buf, "%hu", &voodoo_anti_alias_filter); + if (voodoo_anti_alias_filter > 2) + voodoo_anti_alias_filter = 0; + + voodoo_update_anti_alias_filter(); + return size; +} + +static DEVICE_ATTR(anti_alias_filter,0666, anti_alias_filter_show, anti_alias_filter_store); +#endif + + // Voodoo sound initialization #ifdef CONFIG_SND_VOODOO_SOUND @@ -304,6 +368,15 @@ int voodoo_sound_init(struct snd_soc_codec *codec) pr_err("Failed to create device file(%s)!\n", dev_attr_gain.attr.name); #endif +#ifdef CONFIG_SND_VOODOO_SOUND_RETUNE_EQ + printk("Voodoo sound: ReTune parametric EQ activated\n"); + voodoo_sound_dev = device_create(voodoo_sound_class, NULL, 0, NULL, "parametric_equalizer"); + if (IS_ERR(voodoo_sound_dev)) + pr_err("Failed to create device(voodoo_sound_dev)!\n"); + if (device_create_file(voodoo_sound_dev, &dev_attr_anti_alias_filter) < 0) + pr_err("Failed to create device file(%s)!\n", dev_attr_anti_alias_filter.attr.name); +#endif + #ifdef CONFIG_SND_VOODOO_SOUND_WM8994_WRITE printk("Voodoo sound: wm8994 direct write to codec interface activated\n"); voodoo_sound_dev = device_create(voodoo_sound_class, NULL, 0, NULL, "wm8994_codec"); @@ -1557,7 +1630,11 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec) val |= (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | TUNING_MP3_OUTPUTR_VOL); #endif wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); - + + +#ifdef CONFIG_SND_VOODOO_SOUND_RETUNE_EQ + voodoo_update_anti_alias_filter(); +#endif val = wm8994_read(codec, WM8994_LEFT_OPGA_VOLUME); val &= ~(WM8994_MIXOUTL_MUTE_N_MASK | WM8994_MIXOUTL_VOL_MASK); diff --git a/Kernel/sound/soc/s3c24xx/Kconfig b/Kernel/sound/soc/s3c24xx/Kconfig index 1f68b5abb..27b910201 100644 --- a/Kernel/sound/soc/s3c24xx/Kconfig +++ b/Kernel/sound/soc/s3c24xx/Kconfig @@ -111,6 +111,14 @@ config SND_VOODOO_SOUND_HEADPHONE_AMP_GAIN Say Y if you want to activate control of the headphone gain through the sysfs interface +config SND_VOODOO_SOUND_RETUNE_EQ + bool "ReTune parametric hardware equalizer" + depends on SND_VOODOO_SOUND + default y + help + Say Y if you want to activate Wolfson ReTune paremetric hardware + equalizer controls + config SND_VOODOO_SOUND_WM8994_READ bool "Expose the wm8994_read function" depends on SND_VOODOO_SOUND