diff options
Diffstat (limited to 'arch/arm/mach-exynos/board-grande-sound.c')
-rw-r--r-- | arch/arm/mach-exynos/board-grande-sound.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/board-grande-sound.c b/arch/arm/mach-exynos/board-grande-sound.c new file mode 100644 index 0000000..e07444a --- /dev/null +++ b/arch/arm/mach-exynos/board-grande-sound.c @@ -0,0 +1,371 @@ +/* + * midas-sound.c - Sound Management of MIDAS Project + * + * Copyright (C) 2012 Samsung Electrnoics + * JS Park <aitdark.park@samsung.com> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/i2c.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/i2c-gpio.h> +#include <mach/irqs.h> +#include <mach/pmu.h> +#include <plat/iic.h> + +#include <plat/gpio-cfg.h> +#ifdef CONFIG_ARCH_EXYNOS5 +#include <mach/gpio-p10.h> +#else +#include <mach/gpio-midas.h> +#endif + +#ifdef CONFIG_SND_SOC_WM8994 +#include <linux/mfd/wm8994/pdata.h> +#include <linux/mfd/wm8994/gpio.h> +#endif + +#ifdef CONFIG_FM34_WE395 +#include <linux/i2c/fm34_we395.h> +#endif + +#ifdef CONFIG_AUDIENCE_ES305 +#include <linux/i2c/es305.h> +#endif + +static bool midas_snd_mclk_enabled; + +#ifdef CONFIG_ARCH_EXYNOS5 +#define I2C_NUM_2MIC 4 +#define I2C_NUM_CODEC 7 +#define SET_PLATDATA_2MIC(i2c_pd) s3c_i2c4_set_platdata(i2c_pd) +#define SET_PLATDATA_CODEC(i2c_pd) s3c_i2c7_set_platdata(i2c_pd) +#else /* for CONFIG_ARCH_EXYNOS4 */ +#define I2C_NUM_2MIC 6 +#define I2C_NUM_CODEC 4 +#define SET_PLATDATA_2MIC(i2c_pd) s3c_i2c6_set_platdata(i2c_pd) +#define SET_PLATDATA_CODEC(i2c_pd) s3c_i2c4_set_platdata(i2c_pd) +#endif + +static DEFINE_SPINLOCK(midas_snd_spinlock); + +void midas_snd_set_mclk(bool on, bool forced) +{ + static int use_cnt; + + spin_lock(&midas_snd_spinlock); + + midas_snd_mclk_enabled = on; + + if (midas_snd_mclk_enabled) { + if (use_cnt++ == 0 || forced) { + printk(KERN_INFO "Sound: enabled mclk\n"); +#ifdef CONFIG_ARCH_EXYNOS5 + exynos5_pmu_xclkout_set(midas_snd_mclk_enabled, + XCLKOUT_XXTI); +#else /* for CONFIG_ARCH_EXYNOS4 */ + exynos4_pmu_xclkout_set(midas_snd_mclk_enabled, + XCLKOUT_XUSBXTI); +#endif + mdelay(10); + } + } else { + if ((--use_cnt <= 0) || forced) { + printk(KERN_INFO "Sound: disabled mclk\n"); +#ifdef CONFIG_ARCH_EXYNOS5 + exynos5_pmu_xclkout_set(midas_snd_mclk_enabled, + XCLKOUT_XXTI); +#else /* for CONFIG_ARCH_EXYNOS4 */ + exynos4_pmu_xclkout_set(midas_snd_mclk_enabled, + XCLKOUT_XUSBXTI); +#endif + use_cnt = 0; + } + } + + spin_unlock(&midas_snd_spinlock); + + printk(KERN_INFO "Sound: state: %d, use_cnt: %d\n", + midas_snd_mclk_enabled, use_cnt); +} + +bool midas_snd_get_mclk(void) +{ + return midas_snd_mclk_enabled; +} + +#ifdef CONFIG_SND_SOC_WM8994 +/* vbatt_devices */ +static struct regulator_consumer_supply vbatt_supplies[] = { + REGULATOR_SUPPLY("LDO1VDD", NULL), + REGULATOR_SUPPLY("SPKVDD1", NULL), + REGULATOR_SUPPLY("SPKVDD2", NULL), +}; + +static struct regulator_init_data vbatt_initdata = { + .constraints = { + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vbatt_supplies), + .consumer_supplies = vbatt_supplies, +}; + +static struct fixed_voltage_config vbatt_config = { + .init_data = &vbatt_initdata, + .microvolts = 5000000, + .supply_name = "VBATT", + .gpio = -EINVAL, +}; + +struct platform_device vbatt_device = { + .name = "reg-fixed-voltage", + .id = -1, + .dev = { + .platform_data = &vbatt_config, + }, +}; + +/* wm1811 ldo1 */ +static struct regulator_consumer_supply wm1811_ldo1_supplies[] = { + REGULATOR_SUPPLY("AVDD1", NULL), +}; + +static struct regulator_init_data wm1811_ldo1_initdata = { + .constraints = { + .name = "WM1811 LDO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(wm1811_ldo1_supplies), + .consumer_supplies = wm1811_ldo1_supplies, +}; + +/* wm1811 ldo2 */ +static struct regulator_consumer_supply wm1811_ldo2_supplies[] = { + REGULATOR_SUPPLY("DCVDD", NULL), +}; + +static struct regulator_init_data wm1811_ldo2_initdata = { + .constraints = { + .name = "WM1811 LDO2", + .always_on = true, /* Actually status changed by LDO1 */ + }, + .num_consumer_supplies = ARRAY_SIZE(wm1811_ldo2_supplies), + .consumer_supplies = wm1811_ldo2_supplies, +}; + +static struct wm8994_drc_cfg drc_value[] = { + { + .name = "voice call DRC", + .regs[0] = 0x009B, + .regs[1] = 0x0844, + .regs[2] = 0x00E8, + .regs[3] = 0x0210, + .regs[4] = 0x0000, + }, +#if defined(CONFIG_MACH_C1_KOR_LGT) + { + .name = "voice call DRC", + .regs[0] = 0x008c, + .regs[1] = 0x0253, + .regs[2] = 0x0028, + .regs[3] = 0x028c, + .regs[4] = 0x0000, + }, +#endif +#if defined(CONFIG_MACH_P4NOTE) +{ + .name = "cam rec DRC", + .regs[0] = 0x019B, + .regs[1] = 0x0844, + .regs[2] = 0x0408, + .regs[3] = 0x0108, + .regs[4] = 0x0120, + }, +#endif +}; + +static struct wm8994_pdata wm1811_pdata = { + .gpio_defaults = { + [0] = WM8994_GP_FN_IRQ, /* GPIO1 IRQ output, CMOS mode */ + [7] = WM8994_GPN_DIR | WM8994_GP_FN_PIN_SPECIFIC, /* DACDAT3 */ + [8] = WM8994_CONFIGURE_GPIO | + WM8994_GP_FN_PIN_SPECIFIC, /* ADCDAT3 */ + [9] = WM8994_CONFIGURE_GPIO |\ + WM8994_GP_FN_PIN_SPECIFIC, /* LRCLK3 */ + [10] = WM8994_CONFIGURE_GPIO |\ + WM8994_GP_FN_PIN_SPECIFIC, /* BCLK3 */ + }, + + .irq_base = IRQ_BOARD_CODEC_START, + + /* The enable is shared but assign it to LDO1 for software */ + .ldo = { + { + .enable = GPIO_WM8994_LDO, + .init_data = &wm1811_ldo1_initdata, + }, + { + .init_data = &wm1811_ldo2_initdata, + }, + }, + /* Apply DRC Value */ + .drc_cfgs = drc_value, + .num_drc_cfgs = ARRAY_SIZE(drc_value), + + /* Support external capacitors*/ + .jd_ext_cap = 1, + + /* Regulated mode at highest output voltage */ +#ifdef CONFIG_TARGET_LOCALE_KOR + .micbias = {0x22, 0x22}, +#else + .micbias = {0x2f, 0x2f}, +#endif + + .micd_lvl_sel = 0xFF, + + .ldo_ena_always_driven = true, + .ldo_ena_delay = 30000, +#ifdef CONFIG_TARGET_LOCALE_KOR + .lineout2_diff = 0, +#endif +#ifdef CONFIG_MACH_C1 + .lineout1fb = 0, +#else + .lineout1fb = 1, +#endif +#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_C1_KOR_SKT) || \ + defined(CONFIG_MACH_C1_KOR_KT) || defined(CONFIG_MACH_C1_KOR_LGT) || \ + defined(CONFIG_MACH_P4NOTE) || defined(CONFIG_MACH_GC1) \ + || defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON) + .lineout2fb = 0, +#else + .lineout2fb = 1, +#endif +}; + +static struct i2c_board_info i2c_wm1811[] __initdata = { + { + I2C_BOARD_INFO("wm1811", (0x34 >> 1)), /* Audio CODEC */ + .platform_data = &wm1811_pdata, + .irq = IRQ_EINT(30), + }, +}; + +#endif + +#ifdef CONFIG_FM34_WE395 +static struct fm34_platform_data fm34_we395_pdata = { + .gpio_pwdn = GPIO_FM34_PWDN, + .gpio_rst = GPIO_FM34_RESET, + .gpio_bp = GPIO_FM34_BYPASS, + .set_mclk = midas_snd_set_mclk, +}; +#ifdef CONFIG_MACH_C1_KOR_LGT +static struct fm34_platform_data fm34_we395_pdata_rev05 = { + .gpio_pwdn = GPIO_FM34_PWDN, + .gpio_rst = GPIO_FM34_RESET_05, + .gpio_bp = GPIO_FM34_BYPASS_05, + .set_mclk = midas_snd_set_mclk, +}; +#endif +static struct i2c_board_info i2c_2mic[] __initdata = { + { + I2C_BOARD_INFO("fm34_we395", (0xC0 >> 1)), /* 2MIC */ + .platform_data = &fm34_we395_pdata, + }, +}; + +#if defined(CONFIG_MACH_C1_KOR_LGT) +static struct i2c_gpio_platform_data gpio_i2c_fm34 = { + .sda_pin = GPIO_FM34_SDA, + .scl_pin = GPIO_FM34_SCL, +}; + +struct platform_device s3c_device_fm34 = { + .name = "i2c-gpio", + .id = I2C_NUM_2MIC, + .dev.platform_data = &gpio_i2c_fm34, +}; +#endif +#endif + +#ifdef CONFIG_AUDIENCE_ES305 +static struct es305_platform_data es305_pdata = { + .gpio_wakeup = GPIO_ES305_WAKEUP, + .gpio_reset = GPIO_ES305_RESET, + .set_mclk = midas_snd_set_mclk, +}; + +static struct i2c_board_info i2c_2mic[] __initdata = { + { + I2C_BOARD_INFO("audience_es305", 0x3E), /* 2MIC */ + .platform_data = &es305_pdata, + }, +}; +#endif + +static struct platform_device *midas_sound_devices[] __initdata = { +#if defined(CONFIG_MACH_C1_KOR_LGT) +#ifdef CONFIG_FM34_WE395 + &s3c_device_fm34, +#endif +#endif +}; + +void __init midas_sound_init(void) +{ + printk(KERN_INFO "Sound: start %s\n", __func__); + + platform_add_devices(midas_sound_devices, + ARRAY_SIZE(midas_sound_devices)); + +#ifdef CONFIG_ARCH_EXYNOS5 +#ifndef CONFIG_MACH_P10_LTE_00_BD + i2c_wm1811[0].irq = IRQ_EINT(29); +#endif + SET_PLATDATA_CODEC(NULL); + i2c_register_board_info(I2C_NUM_CODEC, i2c_wm1811, + ARRAY_SIZE(i2c_wm1811)); +#else /* for CONFIG_ARCH_EXYNOS4 */ + i2c_wm1811[0].irq = 0; + SET_PLATDATA_CODEC(NULL); + i2c_register_board_info(I2C_NUM_CODEC, i2c_wm1811, + ARRAY_SIZE(i2c_wm1811)); +#endif/* CONFIG_ARCH_EXYNOS5 */ + +#ifdef CONFIG_FM34_WE395 + midas_snd_set_mclk(true, false); + SET_PLATDATA_2MIC(NULL); + +#if defined(CONFIG_MACH_C1_KOR_LGT) + if (system_rev > 5) + i2c_2mic[0].platform_data = &fm34_we395_pdata_rev05; +#endif + + i2c_register_board_info(I2C_NUM_2MIC, i2c_2mic, ARRAY_SIZE(i2c_2mic)); +#endif + + +#ifdef CONFIG_AUDIENCE_ES305 + midas_snd_set_mclk(true, false); + SET_PLATDATA_2MIC(NULL); + i2c_register_board_info(I2C_NUM_2MIC, i2c_2mic, ARRAY_SIZE(i2c_2mic)); +#endif +} |