summaryrefslogtreecommitdiff
path: root/drivers/staging
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/alc5625/Kconfig13
-rw-r--r--drivers/staging/alc5625/Makefile3
-rw-r--r--drivers/staging/alc5625/alc5625.c2276
-rw-r--r--drivers/staging/alc5625/alc5625.h865
-rw-r--r--drivers/staging/alc5625/origen_alc5625.c236
-rw-r--r--drivers/staging/bcm/nvm.c2
8 files changed, 3397 insertions, 1 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index e3402d5644d..6c05d217e41 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -136,4 +136,6 @@ source "drivers/staging/csr/Kconfig"
source "drivers/staging/omap-thermal/Kconfig"
+source "drivers/staging/alc5625/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 664eae1a4aa..ed1a42e2c3b 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -60,3 +60,4 @@ obj-$(CONFIG_USB_G_CCG) += ccg/
obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
obj-$(CONFIG_CSR_WIFI) += csr/
obj-$(CONFIG_OMAP_BANDGAP) += omap-thermal/
+obj-$(CONFIG_SND_SOC_ORIGEN_ALC5625) += alc5625/
diff --git a/drivers/staging/alc5625/Kconfig b/drivers/staging/alc5625/Kconfig
new file mode 100644
index 00000000000..b35a4695497
--- /dev/null
+++ b/drivers/staging/alc5625/Kconfig
@@ -0,0 +1,13 @@
+# Staging the origen board audio codec
+config SND_SOC_ALC5625
+ tristate
+
+config SND_SOC_ORIGEN_ALC5625
+ tristate "SoC I2S Audio support for ALC5625 on ORIGEN board"
+ depends on SND_SOC_SAMSUNG && MACH_ORIGEN
+ select SND_SOC_ALC5625
+ select SND_SAMSUNG_I2S
+ select fool
+ help
+ Say Y if you want to add support for SoC audio
+ on origen board using ALC5625 codec
diff --git a/drivers/staging/alc5625/Makefile b/drivers/staging/alc5625/Makefile
new file mode 100644
index 00000000000..ae4d85e7738
--- /dev/null
+++ b/drivers/staging/alc5625/Makefile
@@ -0,0 +1,3 @@
+# Staging the origen board audio codec
+obj-$(CONFIG_SND_SOC_ALC5625) += alc5625.o
+obj-$(CONFIG_SND_SOC_ORIGEN_ALC5625) += origen_alc5625.o
diff --git a/drivers/staging/alc5625/alc5625.c b/drivers/staging/alc5625/alc5625.c
new file mode 100644
index 00000000000..98a874fb573
--- /dev/null
+++ b/drivers/staging/alc5625/alc5625.c
@@ -0,0 +1,2276 @@
+/*
+ * alc5625.c -- ALC5625 ALSA SoC Audio driver
+ *
+ * Copyright (C) 2011 Insignal Co., Ltd.
+ *
+ * Author: Pan<pan@insginal.co.kr>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include "alc5625.h"
+
+struct alc5625_priv {
+ unsigned int stereo_sysclk;
+ unsigned int voice_sysclk;
+ enum snd_soc_control_type control_type;
+ void *control_data;
+ struct snd_soc_codec *codec;
+ struct regmap *regmap;
+};
+
+struct alc5625_init_reg {
+ u8 reg_index;
+ u16 reg_value;
+};
+
+static struct alc5625_init_reg alc5625_init_list[] = {
+
+ {ALC5625_HP_OUT_VOL, 0x9090}, /* default is -12db */
+ {ALC5625_SPK_OUT_VOL, 0x8080}, /* default is 0db */
+ {ALC5625_DAC_AND_MIC_CTRL, 0xee03}, /* DAC to hpmixer */
+ {ALC5625_OUTPUT_MIXER_CTRL, 0x0748}, /* all output from hpmixer */
+ {ALC5625_MIC_CTRL, 0x0500}, /* mic boost 20db */
+ {ALC5625_ADC_REC_MIXER, 0x3f3f}, /* record source from mic1 */
+ {ALC5625_GEN_CTRL_REG1, 0x0c0a}, /* speaker vdd ratio is 1 */
+
+ /* gain 15db of ADC by default */
+ {ALC5625_ADC_REC_GAIN, 0xd5d5},
+
+ /* Audio Record settings */
+ {ALC5625_LINE_IN_VOL, 0xff1f},
+ {ALC5625_PD_CTRL_STAT, 0x00c0},
+ {ALC5625_PWR_MANAG_ADD3, 0x80c2},
+};
+
+#define ALC5625_INIT_REG_NUM ARRAY_SIZE(alc5625_init_list)
+
+/*
+ * bit[0] for linein playback switch
+ * bit[1] phone
+ * bit[2] mic1
+ * bit[3] mic2
+ * bit[4] vopcm
+ *
+ */
+#define HPL_MIXER 0x80
+#define HPR_MIXER 0x82
+static unsigned int reg80, reg82;
+
+/*
+ * bit[0][1][2] use for aec control
+ * bit[3] for none
+ * bit[4] for SPKL pga
+ * bit[5] for SPKR pga
+ * bit[6] for hpl pga
+ * bit[7] for hpr pga
+ * bit[8] for dump dsp
+ */
+#define virtual_reg_FOR_MISC_FUNC 0x84
+static unsigned int reg84;
+
+static const u16 alc5625_reg[] = {
+ 0x59b4, 0x8080, 0x9090, 0x8080, /* reg00-reg06 */
+ 0xc800, 0xff1f, 0x1010, 0x0808, /* reg08-reg0e */
+ 0xe0ef, 0xd5d5, 0x3f3f, 0x0000, /* reg10-reg16 */
+ 0xe010, 0x0000, 0x0748, 0x2007, /* reg18-reg1e */
+ 0x0000, 0x0500, 0x00c0, 0x00c0, /* reg20-reg26 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* reg28-reg2e */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* reg30-reg36 */
+ 0x0000, 0x0000, 0x0000, 0x80c2, /* reg38-reg3e */
+ 0x0c0a, 0x0000, 0x0000, 0x0000, /* reg40-reg46 */
+ 0x0029, 0x0000, 0xbe3e, 0x3e3e, /* reg48-reg4e */
+ 0x0000, 0x0000, 0x803a, 0x0000, /* reg50-reg56 */
+ 0x0000, 0x0009, 0x0000, 0x3000, /* reg58-reg5e */
+ 0x3075, 0x1010, 0x3110, 0x0000, /* reg60-reg66 */
+ 0x0553, 0x0000, 0x0000, 0x0000, /* reg68-reg6e */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* reg70-reg76 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* reg78-reg7e */
+};
+
+struct voice_dsp_reg vodsp_aec_init_value[] = {
+ {0x232c, 0x0025},
+ {0x230b, 0x0001},
+ {0x2308, 0x007f},
+ {0x23f8, 0x4003},
+ {0x2301, 0x0002},
+ {0x2328, 0x0001},
+ {0x2304, 0x00fa},
+ {0x2305, 0x0500},
+ {0x2306, 0x4000},
+ {0x230d, 0x0900},
+ {0x230e, 0x0280},
+ {0x2312, 0x00b1},
+ {0x2314, 0xc000},
+ {0x2316, 0x0041},
+ {0x2317, 0x2200},
+ {0x2318, 0x0c00},
+ {0x231d, 0x0050},
+ {0x231f, 0x4000},
+ {0x2330, 0x0008},
+ {0x2335, 0x000a},
+ {0x2336, 0x0004},
+ {0x2337, 0x5000},
+ {0x233a, 0x0300},
+ {0x233b, 0x0030},
+ {0x2341, 0x0008},
+ {0x2343, 0x0800},
+ {0x2352, 0x7fff},
+ {0x237f, 0x0400},
+ {0x23a7, 0x2800},
+ {0x22ce, 0x0400},
+ {0x22d3, 0x1500},
+ {0x22d4, 0x2800},
+ {0x22d5, 0x3000},
+ {0x2399, 0x2800},
+ {0x230c, 0x0000}, /* to enable VODSP AEC function */
+};
+
+#define SET_VODSP_REG_INIT_NUM ARRAY_SIZE(vodsp_aec_init_value)
+
+static inline unsigned int alc5625_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+
+ if (reg > 0x7e)
+ return 0;
+ return cache[reg / 2];
+}
+
+static unsigned int alc5625_read_hw_reg(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ unsigned int value = 0x0;
+
+ if (regmap_read(codec->control_data, reg, &value) < 0) {
+ printk(KERN_DEBUG "%s failed\n", __func__);
+ return -EIO;
+ }
+ return value;
+}
+
+
+static unsigned int alc5625_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+ if ((reg == 0x80) || (reg == 0x82) || (reg == 0x84))
+ return (reg == 0x80) ? reg80 :
+ ((reg == 0x82) ? reg82 : reg84);
+
+ return alc5625_read_hw_reg(codec, reg);
+}
+
+static inline void alc5625_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg,
+ unsigned int value)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg > 0x7E)
+ return;
+ cache[reg / 2] = value;
+}
+
+static int alc5625_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ unsigned int *regvalue = NULL;
+
+ if ((reg == 0x80) || (reg == 0x82) || (reg == 0x84)) {
+ regvalue = ((reg == 0x80) ? &reg80 :
+ ((reg == 0x82) ? &reg82 : &reg84));
+ *regvalue = value;
+ return 0;
+ }
+ alc5625_write_reg_cache(codec, reg, value);
+
+ if (!regmap_write(codec->control_data, reg, value)) {
+ return 0;
+ } else {
+ printk(KERN_ERR "alc5625_write fail\n");
+ return -EIO;
+ }
+}
+
+#define alc5625_write_mask(c, reg, value, mask) snd_soc_update_bits(c,\
+ reg, mask, value)
+
+#define alc5625_reset(c) alc5625_write(c, ALC5625_RESET, 0)
+
+/* read/write dsp reg */
+static int alc5625_wait_vodsp_i2c_done(struct snd_soc_codec *codec)
+{
+ unsigned int checkcount = 0;
+ unsigned int vodsp_data;
+
+ vodsp_data = alc5625_read(codec, ALC5625_VODSP_REG_CMD);
+ while (vodsp_data & VODSP_BUSY) {
+ if (checkcount > 10)
+ return -EBUSY;
+ vodsp_data = alc5625_read(codec, ALC5625_VODSP_REG_CMD);
+ checkcount++;
+ }
+ return 0;
+}
+
+static int alc5625_write_vodsp_reg(struct snd_soc_codec *codec,
+ unsigned int vodspreg, unsigned int value)
+{
+ if (alc5625_wait_vodsp_i2c_done(codec))
+ return -EBUSY;
+
+ alc5625_write(codec, ALC5625_VODSP_REG_ADDR, vodspreg);
+ alc5625_write(codec, ALC5625_VODSP_REG_DATA, value);
+ alc5625_write(codec, ALC5625_VODSP_REG_CMD,
+ VODSP_WRITE_ENABLE | VODSP_CMD_MW);
+ mdelay(10);
+ return 0;
+
+}
+
+static unsigned int alc5625_read_vodsp_reg(struct snd_soc_codec *codec,
+ unsigned int vodspreg)
+{
+ unsigned int ndata_h, ndata_l;
+ unsigned int value;
+
+ if (alc5625_wait_vodsp_i2c_done(codec))
+ return -EBUSY;
+
+ alc5625_write(codec, ALC5625_VODSP_REG_ADDR, vodspreg);
+ alc5625_write(codec, ALC5625_VODSP_REG_CMD,
+ VODSP_READ_ENABLE | VODSP_CMD_MR);
+
+ if (alc5625_wait_vodsp_i2c_done(codec))
+ return -EBUSY;
+
+ alc5625_write(codec, ALC5625_VODSP_REG_ADDR, 0x26);
+ alc5625_write(codec, ALC5625_VODSP_REG_CMD,
+ VODSP_READ_ENABLE | VODSP_CMD_RR);
+
+ if (alc5625_wait_vodsp_i2c_done(codec))
+ return -EBUSY;
+
+ ndata_h = alc5625_read(codec, ALC5625_VODSP_REG_DATA);
+ alc5625_write(codec, ALC5625_VODSP_REG_ADDR, 0x25);
+ alc5625_write(codec, ALC5625_VODSP_REG_CMD,
+ VODSP_READ_ENABLE | VODSP_CMD_RR);
+
+ if (alc5625_wait_vodsp_i2c_done(codec))
+ return -EBUSY;
+
+ ndata_l = alc5625_read(codec, ALC5625_VODSP_REG_DATA);
+ value = ((ndata_h & 0xff) << 8) | (ndata_l & 0xff);
+
+ return value;
+}
+
+static int alc5625_reg_init(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for (i = 0; i < ALC5625_INIT_REG_NUM; i++)
+ alc5625_write(codec, alc5625_init_list[i].reg_index,
+ alc5625_init_list[i].reg_value);
+
+ return 0;
+}
+
+static const char *const alc5625_aec_path_sel[] = {
+ "aec func disable", "aec func for pcm in/out",
+ "aec func for iis in/out", "aec func for analog in/out"
+}; /* 0 */
+static const char *const alc5625_spk_out_sel[] = {
+ "Class AB", "Class D"
+}; /* 1 */
+static const char *const alc5625_spk_l_source_sel[] = {
+ "LPRN", "LPRP", "LPLN", "MM"
+}; /* 2 */
+static const char *const alc5625_spkmux_source_sel[] = {
+ "VMID", "HP Mixer", "SPK Mixer", "Mono Mixer"
+}; /* 3 */
+static const char *const alc5625_hplmux_source_sel[] = {
+ "VMID", "HPL Mixer"
+}; /* 4 */
+static const char *const alc5625_hprmux_source_sel[] = {
+ "VMID", "HPR Mixer"
+}; /* 5 */
+static const char *const alc5625_auxmux_source_sel[] = {
+ "VMID", "HP Mixer", "SPK Mixer", "Mono Mixer"
+}; /* 6 */
+static const char *const alc5625_spkamp_ratio_sel[] = {
+ "2.25 Vdd", "2.00 Vdd", "1.75 Vdd",
+ "1.50 Vdd", "1.25 Vdd", "1.00 Vdd"
+}; /* 7 */
+static const char *const alc5625_mic1_boost_sel[] = {
+ "Bypass", "+20db", "+30db", "+40db"
+}; /* 8 */
+static const char *const alc5625_mic2_boost_sel[] = {
+ "Bypass", "+20db", "+30db", "+40db"
+}; /* 9 */
+static const char *const alc5625_dmic_boost_sel[] = {
+ "Bypass", "+6db", "+12db", "+18db",
+ "+24db", "+30db", "+36db", "+42db"
+}; /* 10 */
+static const char *const alc5625_adcr_func_sel[] = {
+ "Stereo ADC", "Voice ADC",
+ "VoDSP Interface", "PDM Slave Interface"
+}; /* 11 */
+
+static const struct soc_enum alc5625_enum[] = {
+ SOC_ENUM_SINGLE(virtual_reg_FOR_MISC_FUNC, 0, 4,
+ alc5625_aec_path_sel), /* 0 */
+ SOC_ENUM_SINGLE(ALC5625_OUTPUT_MIXER_CTRL, 13, 2,
+ alc5625_spk_out_sel), /* 1 */
+ SOC_ENUM_SINGLE(ALC5625_OUTPUT_MIXER_CTRL, 14, 4,
+ alc5625_spk_l_source_sel), /* 2 */
+ SOC_ENUM_SINGLE(ALC5625_OUTPUT_MIXER_CTRL, 10, 4,
+ alc5625_spkmux_source_sel), /* 3 */
+ SOC_ENUM_SINGLE(ALC5625_OUTPUT_MIXER_CTRL, 9, 2,
+ alc5625_hplmux_source_sel), /* 4 */
+ SOC_ENUM_SINGLE(ALC5625_OUTPUT_MIXER_CTRL, 8, 2,
+ alc5625_hprmux_source_sel), /* 5 */
+ SOC_ENUM_SINGLE(ALC5625_OUTPUT_MIXER_CTRL, 6, 4,
+ alc5625_auxmux_source_sel), /* 6 */
+ SOC_ENUM_SINGLE(ALC5625_GEN_CTRL_REG1, 1, 6,
+ alc5625_spkamp_ratio_sel), /* 7 */
+ SOC_ENUM_SINGLE(ALC5625_MIC_CTRL, 10, 4,
+ alc5625_mic1_boost_sel), /* 8 */
+ SOC_ENUM_SINGLE(ALC5625_MIC_CTRL, 8, 4,
+ alc5625_mic2_boost_sel), /* 9 */
+ SOC_ENUM_SINGLE(ALC5625_DMIC_CTRL, 0, 8,
+ alc5625_dmic_boost_sel), /* 10 */
+ SOC_ENUM_SINGLE(ALC5625_DAC_ADC_VODAC_FUN_SEL, 4, 4,
+ alc5625_adcr_func_sel), /* 11 */
+};
+
+/* function: Enable the Voice PCM interface Path */
+static int config_pcm_voice_path(struct snd_soc_codec *codec,
+ unsigned int enable_voice_path,
+ unsigned int mode)
+{
+ if (enable_voice_path) {
+ /* Power on DAC reference */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ PWR_DAC_REF | PWR_VOICE_DF2SE,
+ PWR_DAC_REF | PWR_VOICE_DF2SE);
+ /* Power on Voice DAC/ADC */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD2,
+ PWR_VOICE_CLOCK,
+ PWR_VOICE_CLOCK);
+ /* routing voice to HPMixer */
+ alc5625_write_mask(codec, ALC5625_VOICE_DAC_OUT_VOL, 0,
+ M_V_DAC_TO_HP_MIXER);
+
+ switch (mode) {
+ case PCM_SLAVE_MODE_B:
+ /*
+ * 8kHz sampling rate,16 bits PCM mode and Slave mode,
+ * PCM mode is B,MCLK=24.576MHz from Oscillator.
+ * CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08C00000,
+ * PSKEY_FORMAT=0x0060
+ *
+ * Set LRCK voice select divide 32
+ * set voice blck select divide 6 and 8
+ * voice filter clock divide 3 and 16
+ * the register 0x64 value's should is 0x5524
+ */
+ alc5625_write(codec, ALC5625_VOICE_DAC_PCMCLK_CTRL1,
+ 0x5524);
+
+ break;
+
+ case PCM_SLAVE_MODE_A:
+ /*
+ * 8kHz sampling rate,16 bits PCM and Slave mode,
+ * PCM mode is A,MCLK=24.576MHz from Oscillator.
+ * CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08C00004,
+ * PSKEY_FORMAT=0x0060
+ *
+ * Enable GPIO 1,3,4,5 to voice interface
+ * Set I2S to Slave mode
+ * Voice I2S SYSCLK Source select Main SYSCLK
+ * Set voice i2s VBCLK Polarity to Invert
+ * Set Data length to 16 bit
+ * set Data Fomrat to PCM mode A
+ * the register 0x36 value's should is 0xC082
+ */
+ alc5625_write(codec, ALC5625_EXTEND_SDP_CTRL, 0xC082);
+
+ /*
+ * Set LRCK voice select divide 64
+ * set voice blck select divide 6 and 8
+ * voice filter clock divide 3 and 16
+ * the register 0x64 value's should is 0x5524
+ */
+ alc5625_write(codec, ALC5625_VOICE_DAC_PCMCLK_CTRL1,
+ 0x5524);
+
+ break;
+
+ case PCM_MASTER_MODE_B:
+ /*
+ * 8kHz sampling rate,16 bits PCM and Master mode,
+ * PCM mode is B,Clock from PLL OUT
+ * CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08000002,
+ * PSKEY_FORMAT=0x0060
+ * Enable GPIO 1,3,4,5 to voice interface
+ * Set I2S to master mode
+ * Set voice i2s VBCLK Polarity to Invert
+ * Set Data length to 16 bit
+ * set Data Fomrat to PCM mode B
+ * the register 0x36 value's should is 0x8083
+ */
+ alc5625_write(codec, ALC5625_EXTEND_SDP_CTRL, 0x8083);
+
+ /*
+ * Set LRCK voice select divide 64
+ * set voice blck select divide 6 and 8
+ * voice filter clock divide 3 and 16
+ * the register 0x64 value's should is 0x5524
+ */
+ alc5625_write(codec, ALC5625_VOICE_DAC_PCMCLK_CTRL1,
+ 0x5524);
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+ } else {
+ /* Power down Voice Different to sing-end power */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1, 0,
+ PWR_VOICE_DF2SE);
+ /* Power down Voice DAC/ADC */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD2, 0,
+ PWR_VOICE_CLOCK);
+ /* Disable Voice PCM interface */
+ alc5625_write_mask(codec, ALC5625_EXTEND_SDP_CTRL, 0,
+ EXT_I2S_FUNC_ENABLE);
+ }
+
+ return 0;
+}
+
+static int init_vodsp_aec(struct snd_soc_codec *codec)
+{
+ int i;
+ int ret = 0;
+
+ /* Disable LDO power */
+ alc5625_write_mask(codec, ALC5625_LDO_CTRL, 0, LDO_ENABLE);
+ mdelay(20);
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL,
+ VODSP_NO_PD_MODE_ENA, VODSP_NO_PD_MODE_ENA);
+ /* Enable LDO power and set output voltage to 1.2V */
+ alc5625_write_mask(codec, ALC5625_LDO_CTRL,
+ LDO_ENABLE | LDO_OUT_VOL_CTRL_1_20V,
+ LDO_ENABLE | LDO_OUT_VOL_CTRL_MASK);
+ mdelay(20);
+ /* Enable power of VODSP I2C interface */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ PWR_VODSP_INTERFACE | PWR_I2C_FOR_VODSP,
+ PWR_VODSP_INTERFACE | PWR_I2C_FOR_VODSP);
+ mdelay(1);
+ /* Reset VODSP */
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL,
+ 0, VODSP_NO_RST_MODE_ENA);
+ mdelay(1);
+ /* Set VODSP to non-reset status */
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL,
+ VODSP_NO_RST_MODE_ENA, VODSP_NO_RST_MODE_ENA);
+ mdelay(20);
+
+ /*initize AEC paramter*/
+ for (i = 0; i < SET_VODSP_REG_INIT_NUM; i++) {
+ ret = alc5625_write_vodsp_reg(codec,
+ vodsp_aec_init_value[i].index,
+ vodsp_aec_init_value[i].val);
+ if (ret)
+ return -EIO;
+ }
+
+ schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+
+ return 0;
+}
+
+/*
+ * Enable/Disable the VODSP interface Path
+ *
+ * For system clock only support specific clock, realtek suggests customer to
+ * use 24.576Mhz or 22.5792Mhz clock for MCLK (MCLK=48k*512 or 44.1k*512Mhz)
+ */
+static int set_vodsp_aec_path(struct snd_soc_codec *codec, unsigned int mode)
+{
+ switch (mode) {
+ case PCM_IN_PCM_OUT:
+ /* set PCM format */
+ config_pcm_voice_path(codec, 1, PCM_MASTER_MODE_B);
+ /* set AEC path */
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT,
+ 0x0300, 0x0300);
+ alc5625_write_mask(codec, ALC5625_VODSP_PDM_CTL,
+ VODSP_RXDP_PWR |
+ VODSP_RXDP_S_SEL_VOICE |
+ VOICE_PCM_S_SEL_AEC_TXDP,
+ VODSP_RXDP_PWR |
+ VODSP_RXDP_S_SEL_MASK |
+ VOICE_PCM_S_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_DAC_ADC_VODAC_FUN_SEL,
+ ADCR_FUNC_SEL_PDM |
+ VODAC_SOUR_SEL_VODSP_TXDC,
+ ADCR_FUNC_SEL_MASK |
+ VODAC_SOUR_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL,
+ VODSP_LRCK_SEL_8K,
+ VODSP_LRCK_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT,
+ 0x0000, 0x0300);
+
+ /* Set input&output path and power
+ * Power on related bit
+ *
+ * I2S DAI Enable | spk amp enable |
+ * Dac2Mixer pwr on | MICBIAS1 Enable |
+ * MICBIAS2 Enable | Main Bias Pwr |
+ * DAC ref voltage pwr on
+ */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x0c8f, 0x0c8f);
+
+ /* Pwr on Pll1 | over temperature sensor pwr on |
+ * pwr voice DAC on | Left and Right ADC on |
+ * Spk mixer pwr on | ADC mixer left/right pwr on
+ */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD2,
+ 0xa4cb, 0xa4cb);
+
+ /* power spk left/right vol | pwr vodsp interface |
+ * power on microphone1 boost
+ */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ 0x3302, 0xf302);
+
+ /* Mute DAC to hpmixer */
+ alc5625_write(codec, ALC5625_DAC_AND_MIC_CTRL, 0xee0f);
+
+ /* Set Mic1 to differential mode */
+ alc5625_write(codec, ALC5625_MIC_VOL, 0x8808);
+
+ /* Mic boost 0db */
+ alc5625_write(codec, ALC5625_MIC_CTRL, 0x0000);
+
+ /* ADC_Mixer_R boost 10.5 db */
+ alc5625_write(codec, ALC5625_ADC_REC_GAIN, 0xcbd3);
+
+ /* Mic1->ADCMixer_R */
+ alc5625_write(codec, ALC5625_ADC_REC_MIXER, 0x7f3f);
+
+ /* VoDAC to speakerMixer,0db */
+ alc5625_write(codec, ALC5625_VOICE_DAC_OUT_VOL, 0xa010);
+
+ /* Speaker source from speakermixer */
+ alc5625_write(codec, ALC5625_OUTPUT_MIXER_CTRL, 0x8808);
+
+ /* Unmute speaker */
+ alc5625_write_mask(codec, ALC5625_SPK_OUT_VOL, 0x0000, 0x8080);
+
+ break;
+
+ case ANALOG_IN_ANALOG_OUT:
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT, 0x0300, 0x0300);
+ alc5625_write_mask(codec, ALC5625_VODSP_PDM_CTL,
+ VODSP_RXDP_PWR |
+ VODSP_RXDP_S_SEL_ADCL |
+ VOICE_PCM_S_SEL_AEC_TXDP,
+ VODSP_RXDP_PWR | VODSP_RXDP_S_SEL_MASK |
+ VOICE_PCM_S_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_DAC_ADC_VODAC_FUN_SEL,
+ ADCR_FUNC_SEL_PDM |
+ VODAC_SOUR_SEL_VODSP_TXDC |
+ DAC_FUNC_SEL_VODSP_TXDP|
+ ADCL_FUNC_SEL_VODSP,
+ ADCR_FUNC_SEL_MASK |
+ VODAC_SOUR_SEL_MASK |
+ DAC_FUNC_SEL_MASK |
+ ADCL_FUNC_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL,
+ VODSP_LRCK_SEL_16K,
+ VODSP_LRCK_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT, 0x0000, 0x0300);
+
+ /* Set input&output path and power */
+ /* Power on related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0xcc8f, 0xcc8f);
+
+ /* Power on related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD2,
+ 0xa7cf, 0xa7cf);
+
+ /* Power on related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ 0xf312, 0xf312);
+
+ /* Set Mic1 to differential mode */
+ alc5625_write(codec, ALC5625_MIC_VOL, 0x8808);
+
+ /* Set phone in to differential mode */
+ alc5625_write(codec, ALC5625_PHONEIN_VOL, 0xe800);
+
+ /* Mic boost 0db */
+ alc5625_write(codec, ALC5625_MIC_CTRL, 0x0000);
+
+ /* Mic1->ADCMixer_R,phone in-->ADCMixer_L */
+ alc5625_write(codec, ALC5625_ADC_REC_MIXER, 0x773f);
+
+ /* ADC_Mixer_R boost 10.5 db */
+ alc5625_write(codec, ALC5625_ADC_REC_GAIN, 0xCBD3);
+
+ /* Speaker from spkmixer,monoOut from monoMixer */
+ alc5625_write(codec, ALC5625_OUTPUT_MIXER_CTRL, 0x88c8);
+
+ /* Unmute VoDAC to spkmixer */
+ alc5625_write(codec, ALC5625_VOICE_DAC_OUT_VOL, 0xA010);
+
+ /* Unmute DAC to monoMixer */
+ alc5625_write(codec, ALC5625_DAC_AND_MIC_CTRL, 0xee0e);
+ alc5625_write(codec, ALC5625_STEREO_DAC_CLK_CTRL2, 0x2222);
+ alc5625_write(codec, ALC5625_VOICE_DAC_PCMCLK_CTRL1, 0x3122);
+
+ /* Unmute speaker */
+ alc5625_write_mask(codec, ALC5625_SPK_OUT_VOL, 0x0000, 0x8080);
+
+ /* Unmute auxout */
+ alc5625_write_mask(codec, ALC5625_AUX_OUT_VOL, 0x0000, 0x8080);
+ break;
+
+ case DAC_IN_ADC_OUT:
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT, 0x0300, 0x0300);
+ alc5625_write_mask(codec, ALC5625_DAC_ADC_VODAC_FUN_SEL,
+ ADCR_FUNC_SEL_PDM |
+ DAC_FUNC_SEL_VODSP_TXDC,
+ ADCR_FUNC_SEL_MASK |
+ DAC_FUNC_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_VODSP_PDM_CTL,
+ VODSP_SRC1_PWR |
+ VODSP_SRC2_PWR |
+ VODSP_RXDP_PWR |
+ VODSP_RXDP_S_SEL_SRC1 |
+ REC_S_SEL_SRC2,
+ VODSP_SRC1_PWR |
+ VODSP_SRC2_PWR |
+ VODSP_RXDP_PWR |
+ VODSP_RXDP_S_SEL_MASK |
+ REC_S_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL,
+ VODSP_LRCK_SEL_16K,
+ VODSP_LRCK_SEL_MASK);
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT, 0x0000, 0x0300);
+
+ /* Set input&output path and power */
+ /* Power on related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0xcc0f, 0xcc0f);
+
+ /* Power on related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD2,
+ 0xa7cb, 0xa7cb);
+
+ /* Power on related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ 0x3302, 0x3302);
+
+ /* Set Mic1 to differential mode */
+ alc5625_write(codec, ALC5625_MIC_VOL, 0x8808);
+
+ /*Mic boost 0db */
+ alc5625_write(codec, ALC5625_MIC_CTRL, 0x0000);
+
+ /*Mic1->ADCMixer_R */
+ alc5625_write(codec, ALC5625_ADC_REC_MIXER, 0x7f3f);
+
+ /*ADC_Mixer_R boost 10.5 db */
+ alc5625_write(codec, ALC5625_ADC_REC_GAIN, 0xCBD3);
+
+ /* Speaker out from spkMixer */
+ alc5625_write(codec, ALC5625_OUTPUT_MIXER_CTRL, 0x8808);
+
+ /* Unmute DAC to spkMixer */
+ alc5625_write(codec, ALC5625_DAC_AND_MIC_CTRL, 0xee0d);
+ alc5625_write(codec, ALC5625_STEREO_DAC_CLK_CTRL1, 0x3075);
+ alc5625_write(codec, ALC5625_STEREO_DAC_CLK_CTRL2, 0x1010);
+
+ /* Unmute speaker */
+ alc5625_write_mask(codec, ALC5625_SPK_OUT_VOL, 0x0000, 0x8080);
+
+ break;
+
+ case VODSP_AEC_DISABLE:
+ default:
+ /* Mute speaker out */
+ alc5625_write_mask(codec, ALC5625_SPK_OUT_VOL, 0x8080, 0x8080);
+
+ /* Mute auxout */
+ alc5625_write_mask(codec, ALC5625_AUX_OUT_VOL, 0x8080, 0x8080);
+
+ /* Mic boost 20db by default */
+ alc5625_write(codec, ALC5625_MIC_CTRL, 0x0500);
+
+ /* Record from Mic1 by default */
+ alc5625_write(codec, ALC5625_ADC_REC_MIXER, 0x3f3f);
+
+ /* ADC_Mixer_R boost 15 db by default */
+ alc5625_write(codec, ALC5625_ADC_REC_GAIN, 0xD5D5);
+
+ /* All output from HPmixer by default */
+ alc5625_write(codec, ALC5625_OUTPUT_MIXER_CTRL, 0x0748);
+
+ /* DAC to HPmixer by default */
+ alc5625_write(codec, ALC5625_DAC_AND_MIC_CTRL, 0xee03);
+
+ /* Mute VoDAC to mixer by default */
+ alc5625_write(codec, ALC5625_VOICE_DAC_OUT_VOL, 0xe010);
+
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT, 0x0000, 0x0300);
+
+ /* Set stereo DAC&Voice DAC&Stereo ADC function
+ * select to default
+ */
+ alc5625_write(codec, ALC5625_DAC_ADC_VODAC_FUN_SEL, 0);
+
+ /* Set VODSP&PDM Control to default */
+ alc5625_write(codec, ALC5625_VODSP_PDM_CTL, 0);
+
+ alc5625_write_mask(codec, ALC5625_PD_CTRL_STAT, 0x0000, 0x0300);
+
+ /* Power down related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ 0x0000, 0xf312);
+
+ /* Power down related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x0000, 0xcc8d);
+
+ /* Power down related bit */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD2,
+ 0x0000, 0x07cf);
+ break;
+ }
+ return 0;
+}
+
+static int enable_vodsp_aec(struct snd_soc_codec *codec,
+ unsigned int enable_vodspAEC,
+ unsigned int aec_mode)
+{
+ int ret = 0;
+
+ if (enable_vodspAEC != 0) {
+ /* enable power of VODSP I2C interface & VODSP interface */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ PWR_VODSP_INTERFACE |
+ PWR_I2C_FOR_VODSP,
+ PWR_VODSP_INTERFACE |
+ PWR_I2C_FOR_VODSP);
+ /* enable power of VODSP I2S interface */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ PWR_I2S_INTERFACE,
+ PWR_I2S_INTERFACE);
+ /* select input/output of VODSP AEC */
+ set_vodsp_aec_path(codec, aec_mode);
+ } else {
+ /* disable VODSP AEC path */
+ set_vodsp_aec_path(codec, VODSP_AEC_DISABLE);
+ /* set VODSP AEC to power down mode */
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL, 0,
+ VODSP_NO_PD_MODE_ENA);
+ /* disable power of VODSP I2C interface & VODSP interface */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3, 0,
+ PWR_VODSP_INTERFACE |
+ PWR_I2C_FOR_VODSP);
+ }
+
+ return ret;
+}
+
+static void alc5625_aec_config(struct snd_soc_codec *codec, unsigned int mode)
+{
+ if (mode == VODSP_AEC_DISABLE) {
+ enable_vodsp_aec(codec, 0, mode);
+ /* disable LDO power */
+ alc5625_write_mask(codec, ALC5625_LDO_CTRL, 0, LDO_ENABLE);
+ } else {
+ init_vodsp_aec(codec);
+ enable_vodsp_aec(codec, 1, mode);
+ }
+}
+
+/* function:disable alc5625's function */
+static int alc5625_func_aec_disable(struct snd_soc_codec *codec, int mode)
+{
+ switch (mode) {
+ case ALC5625_AEC_PCM_IN_OUT:
+ case ALC5625_AEC_IIS_IN_OUT:
+ case ALC5625_AEC_ANALOG_IN_OUT:
+ /* disable AEC function and path */
+ alc5625_aec_config(codec, VODSP_AEC_DISABLE);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int alc5625_get_dsp_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ /* cause we choose bit[0][1] to store the mode type */
+ int mode = (alc5625_read(codec, virtual_reg_FOR_MISC_FUNC)) & 0x03;
+
+ ucontrol->value.integer.value[0] = mode;
+ return 0;
+}
+
+static int alc5625_set_dsp_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ u16 virtual_reg = alc5625_read(codec, virtual_reg_FOR_MISC_FUNC);
+ int alc5625_mode = (virtual_reg) & 0x03;
+
+ if (alc5625_mode == ucontrol->value.integer.value[0])
+ return 0;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case ALC5625_AEC_PCM_IN_OUT:
+ /* enable AEC PCM in/out function and path */
+ alc5625_aec_config(codec, PCM_IN_PCM_OUT);
+ break;
+
+ case ALC5625_AEC_IIS_IN_OUT:
+ /* enable AEC IIS in/out function and path */
+ alc5625_aec_config(codec, DAC_IN_ADC_OUT);
+ break;
+
+ case ALC5625_AEC_ANALOG_IN_OUT:
+ /* enable AEC analog in/out function and path */
+ alc5625_aec_config(codec, ANALOG_IN_ANALOG_OUT);
+ break;
+
+ case ALC5625_AEC_DISABLE:
+ /* disable previous select function */
+ alc5625_func_aec_disable(codec, alc5625_mode);
+ break;
+
+ default:
+ break;
+ }
+
+ virtual_reg &= 0xfffc;
+ virtual_reg |= (ucontrol->value.integer.value[0]);
+ alc5625_write(codec, virtual_reg_FOR_MISC_FUNC, virtual_reg);
+
+ return 0;
+}
+
+static int alc5625_dump_dsp_reg(struct snd_soc_codec *codec)
+{
+ int i;
+
+ alc5625_write_mask(codec, ALC5625_VODSP_CTL,
+ VODSP_NO_PD_MODE_ENA,
+ VODSP_NO_PD_MODE_ENA);
+ for (i = 0; i < SET_VODSP_REG_INIT_NUM; i++)
+ alc5625_read_vodsp_reg(codec,
+ vodsp_aec_init_value[i].index);
+
+ return 0;
+}
+
+static int alc5625_dump_dsp_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int mode = alc5625_read(codec, virtual_reg_FOR_MISC_FUNC);
+
+ mode &= ~(0x01 << 8);
+ mode |= (ucontrol->value.integer.value[0] << 8);
+ alc5625_write(codec, virtual_reg_FOR_MISC_FUNC, mode);
+ alc5625_dump_dsp_reg(codec);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new alc5625_snd_ctrls[] = {
+ SOC_ENUM_EXT("alc5625 aec mode sel", alc5625_enum[0],
+ alc5625_get_dsp_mode, alc5625_set_dsp_mode),
+ SOC_ENUM("SPK Amp Type", alc5625_enum[1]),
+ SOC_ENUM("Left SPK Source", alc5625_enum[2]),
+ SOC_ENUM("SPK Amp Ratio", alc5625_enum[7]),
+ SOC_ENUM("Mic1 Boost", alc5625_enum[8]),
+ SOC_ENUM("Mic2 Boost", alc5625_enum[9]),
+ SOC_ENUM("Dmic Boost", alc5625_enum[10]),
+ SOC_ENUM("ADCR Func", alc5625_enum[11]),
+ SOC_DOUBLE("PCM Playback Volume", ALC5625_STEREO_DAC_VOL, 8, 0, 63, 1),
+ SOC_DOUBLE("LineIn Playback Volume", ALC5625_LINE_IN_VOL, 8, 0, 31, 1),
+ SOC_SINGLE("Phone Playback Volume", ALC5625_PHONEIN_VOL, 8, 31, 1),
+ SOC_SINGLE("Mic1 Playback Volume", ALC5625_MIC_VOL, 8, 31, 1),
+ SOC_SINGLE("Mic2 Playback Volume", ALC5625_MIC_VOL, 0, 31, 1),
+ SOC_DOUBLE("PCM Capture Volume", ALC5625_ADC_REC_GAIN, 8, 0, 31, 1),
+ SOC_DOUBLE("SPKOUT Playback Volume", ALC5625_SPK_OUT_VOL, 8, 0, 31, 1),
+ SOC_DOUBLE("SPKOUT Playback Switch", ALC5625_SPK_OUT_VOL, 15, 7, 1, 1),
+ SOC_DOUBLE("HPOUT Playback Volume", ALC5625_HP_OUT_VOL, 8, 0, 31, 1),
+ SOC_DOUBLE("HPOUT Playback Switch", ALC5625_HP_OUT_VOL, 15, 7, 1, 1),
+ SOC_DOUBLE("AUXOUT Playback Volume", ALC5625_AUX_OUT_VOL, 8, 0, 31, 1),
+ SOC_DOUBLE("AUXOUT Playback Switch", ALC5625_AUX_OUT_VOL, 15, 7, 1, 1),
+ SOC_DOUBLE("ADC Record Gain", ALC5625_ADC_REC_GAIN, 8, 0, 31, 0),
+ SOC_SINGLE_EXT("VoDSP Dump", virtual_reg_FOR_MISC_FUNC, 8, 1, 0,
+ snd_soc_get_volsw, alc5625_dump_dsp_put),
+};
+
+static void hp_depop_mode2(struct snd_soc_codec *codec)
+{
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ PWR_SOFTGEN_EN,
+ PWR_SOFTGEN_EN);
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ PWR_HP_R_OUT_VOL | PWR_HP_L_OUT_VOL,
+ PWR_HP_R_OUT_VOL | PWR_HP_L_OUT_VOL);
+ alc5625_write(codec, ALC5625_MISC_CTRL, HP_DEPOP_MODE2_EN);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ PWR_HP_OUT_AMP | PWR_HP_OUT_ENH_AMP,
+ PWR_HP_OUT_AMP | PWR_HP_OUT_ENH_AMP);
+
+}
+
+/* enable depop function for mute/unmute */
+static void hp_mute_unmute_depop(struct snd_soc_codec *codec, int mute)
+{
+ if (mute) {
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ PWR_SOFTGEN_EN,
+ PWR_SOFTGEN_EN);
+ alc5625_write(codec, ALC5625_MISC_CTRL,
+ M_UM_DEPOP_EN | HP_R_M_UM_DEPOP_EN |
+ HP_L_M_UM_DEPOP_EN);
+ /* Mute headphone right/left channel */
+ alc5625_write_mask(codec, ALC5625_HP_OUT_VOL,
+ ALC_L_MUTE|ALC_R_MUTE,
+ ALC_L_MUTE|ALC_R_MUTE);
+ mdelay(50);
+ } else {
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ PWR_SOFTGEN_EN,
+ PWR_SOFTGEN_EN);
+ alc5625_write(codec, ALC5625_MISC_CTRL,
+ M_UM_DEPOP_EN | HP_R_M_UM_DEPOP_EN |
+ HP_L_M_UM_DEPOP_EN);
+ /* unMute headphone right/left channel */
+ alc5625_write_mask(codec, ALC5625_HP_OUT_VOL, 0,
+ ALC_L_MUTE|ALC_R_MUTE);
+ mdelay(50);
+ }
+}
+
+/*
+ * _DAPM_ Controls
+ */
+/* Left ADC Rec mixer */
+static const struct snd_kcontrol_new alc5625_ctrl_adc_l[] = {
+ SOC_DAPM_SINGLE("Mic1 Capture Switch",
+ ALC5625_ADC_REC_MIXER, 14, 1, 1),
+ SOC_DAPM_SINGLE("Mic2 Capture Switch",
+ ALC5625_ADC_REC_MIXER, 13, 1, 1),
+ SOC_DAPM_SINGLE("LineIn Capture Switch",
+ ALC5625_ADC_REC_MIXER, 12, 1, 1),
+ SOC_DAPM_SINGLE("Phone Capture Switch",
+ ALC5625_ADC_REC_MIXER, 11, 1, 1),
+ SOC_DAPM_SINGLE("HP Mixer Capture Switch",
+ ALC5625_ADC_REC_MIXER, 10, 1, 1),
+ SOC_DAPM_SINGLE("SPK Mixer Capture Switch",
+ ALC5625_ADC_REC_MIXER, 9, 1, 1),
+ SOC_DAPM_SINGLE("MoNo Mixer Capture Switch",
+ ALC5625_ADC_REC_MIXER, 8, 1, 1),
+};
+
+/* Left ADC Rec mixer */
+static const struct snd_kcontrol_new alc5625_ctrl_adc_r[] = {
+ SOC_DAPM_SINGLE("Mic1 Capture Switch",
+ ALC5625_ADC_REC_MIXER, 6, 1, 1),
+ SOC_DAPM_SINGLE("Mic2 Capture Switch",
+ ALC5625_ADC_REC_MIXER, 5, 1, 1),
+ SOC_DAPM_SINGLE("LineIn Capture Switch",
+ ALC5625_ADC_REC_MIXER, 4, 1, 1),
+ SOC_DAPM_SINGLE("Phone Capture Switch",
+ ALC5625_ADC_REC_MIXER, 3, 1, 1),
+ SOC_DAPM_SINGLE("HP Mixer Capture Switch",
+ ALC5625_ADC_REC_MIXER, 2, 1, 1),
+ SOC_DAPM_SINGLE("SPK Mixer Capture Switch",
+ ALC5625_ADC_REC_MIXER, 1, 1, 1),
+ SOC_DAPM_SINGLE("MoNo Mixer Capture Switch",
+ ALC5625_ADC_REC_MIXER, 0, 1, 1),
+};
+
+/* Left hpmixer mixer */
+static const struct snd_kcontrol_new alc5625_ctrl_hp_l[] = {
+ SOC_DAPM_SINGLE("ADC Playback Switch",
+ ALC5625_ADC_REC_GAIN, 15, 1, 1),
+ SOC_DAPM_SINGLE("LineIn Playback Switch",
+ HPL_MIXER, 0, 1, 0),
+ SOC_DAPM_SINGLE("Phone Playback Switch",
+ HPL_MIXER, 1, 1, 0),
+ SOC_DAPM_SINGLE("Mic1 Playback Switch",
+ HPL_MIXER, 2, 1, 0),
+ SOC_DAPM_SINGLE("Mic2 Playback Switch",
+ HPL_MIXER, 3, 1, 0),
+ SOC_DAPM_SINGLE("Voice DAC Playback Switch",
+ HPL_MIXER, 4, 1, 0),
+ SOC_DAPM_SINGLE("HIFI DAC Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 3, 1, 1),
+};
+
+/* Right hpmixer mixer */
+static const struct snd_kcontrol_new alc5625_ctrl_hp_r[] = {
+ SOC_DAPM_SINGLE("ADC Playback Switch",
+ ALC5625_ADC_REC_GAIN, 7, 1, 1),
+ SOC_DAPM_SINGLE("LineIn Playback Switch",
+ HPR_MIXER, 0, 1, 0),
+ SOC_DAPM_SINGLE("Phone Playback Switch",
+ HPR_MIXER, 1, 1, 0),
+ SOC_DAPM_SINGLE("Mic1 Playback Switch",
+ HPR_MIXER, 2, 1, 0),
+ SOC_DAPM_SINGLE("Mic2 Playback Switch",
+ HPR_MIXER, 3, 1, 0),
+ SOC_DAPM_SINGLE("Voice DAC Playback Switch",
+ HPR_MIXER, 4, 1, 0),
+ SOC_DAPM_SINGLE("HIFI DAC Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 2, 1, 1),
+};
+
+/* mono mixer */
+static const struct snd_kcontrol_new alc5625_ctrl_mono[] = {
+ SOC_DAPM_SINGLE("ADCL Playback Switch",
+ ALC5625_ADC_REC_GAIN, 14, 1, 1),
+ SOC_DAPM_SINGLE("ADCR Playback Switch",
+ ALC5625_ADC_REC_GAIN, 6, 1, 1),
+ SOC_DAPM_SINGLE("Line Mixer Playback Switch",
+ ALC5625_LINE_IN_VOL, 13, 1, 1),
+ SOC_DAPM_SINGLE("Mic1 Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 13, 1, 1),
+ SOC_DAPM_SINGLE("Mic2 Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 9, 1, 1),
+ SOC_DAPM_SINGLE("DAC Mixer Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 0, 1, 1),
+ SOC_DAPM_SINGLE("Voice DAC Playback Switch",
+ ALC5625_VOICE_DAC_OUT_VOL, 13, 1, 1),
+};
+
+/* speaker mixer */
+static const struct snd_kcontrol_new alc5625_ctrl_spk[] = {
+ SOC_DAPM_SINGLE("Line Mixer Playback Switch",
+ ALC5625_LINE_IN_VOL, 14, 1, 1),
+ SOC_DAPM_SINGLE("Phone Playback Switch",
+ ALC5625_PHONEIN_VOL, 14, 1, 1),
+ SOC_DAPM_SINGLE("Mic1 Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 14, 1, 1),
+ SOC_DAPM_SINGLE("Mic2 Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 10, 1, 1),
+ SOC_DAPM_SINGLE("DAC Mixer Playback Switch",
+ ALC5625_DAC_AND_MIC_CTRL, 1, 1, 1),
+ SOC_DAPM_SINGLE("Voice DAC Playback Switch",
+ ALC5625_VOICE_DAC_OUT_VOL, 14, 1, 1),
+};
+
+static int mixer_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int l, r;
+
+ l = alc5625_read(codec, HPL_MIXER);
+ r = alc5625_read(codec, HPR_MIXER);
+
+ /* Mute/Unmute vol output to hp mixer */
+ if ((l & 0x1) || (r & 0x1))
+ alc5625_write_mask(codec, ALC5625_LINE_IN_VOL,
+ 0x0000, 0x8000);
+ else
+ alc5625_write_mask(codec, ALC5625_LINE_IN_VOL,
+ 0x8000, 0x8000);
+
+ /* Mute/Unmute phone input to hp mixer */
+ if ((l & 0x2) || (r & 0x2))
+ alc5625_write_mask(codec, ALC5625_PHONEIN_VOL,
+ 0x0000, 0x8000);
+ else
+ alc5625_write_mask(codec, ALC5625_PHONEIN_VOL,
+ 0x8000, 0x8000);
+
+ /* Mute/Unmute Mic1 vol output to hp mixer */
+ if ((l & 0x4) || (r & 0x4))
+ alc5625_write_mask(codec, ALC5625_DAC_AND_MIC_CTRL,
+ 0x0000, 0x8000);
+ else
+ alc5625_write_mask(codec, ALC5625_DAC_AND_MIC_CTRL,
+ 0x8000, 0x8000);
+
+ /* Mute/Unmute Mic2 vol output to hp mixer */
+ if ((l & 0x8) || (r & 0x8))
+ alc5625_write_mask(codec, ALC5625_DAC_AND_MIC_CTRL,
+ 0x0000, 0x0800);
+ else
+ alc5625_write_mask(codec, ALC5625_DAC_AND_MIC_CTRL,
+ 0x0800, 0x0800);
+
+ /* Mute/Unmute voice DAC vol to hp mixer */
+ if ((l & 0x10) || (r & 0x10))
+ alc5625_write_mask(codec, ALC5625_VOICE_DAC_OUT_VOL,
+ 0x0000, 0x8000);
+ else
+ alc5625_write_mask(codec, ALC5625_VOICE_DAC_OUT_VOL,
+ 0x8000, 0x8000);
+
+ return 0;
+}
+
+/*
+ * bit[0][1] use for aec control
+ * bit[2][3] for ADCR func
+ * bit[4] for SPKL pga
+ * bit[5] for SPKR pga
+ * bit[6] for hpl pga
+ * bit[7] for hpr pga
+ */
+static int spk_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int reg;
+
+ reg = alc5625_read(codec, virtual_reg_FOR_MISC_FUNC) & (0x3 << 4);
+ if (reg && (reg >> 4) != 0x3)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ 0x3000, 0x3000);
+ alc5625_write_mask(codec, ALC5625_SPK_OUT_VOL,
+ 0x0000, 0x8080);
+ /* power on spk amp */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x0400, 0x0400);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* power off spk amp */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x0000, 0x0400);
+ alc5625_write_mask(codec, ALC5625_SPK_OUT_VOL,
+ 0x8080, 0x8080);
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ 0x0000, 0x3000);
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static int hp_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ int reg;
+
+ reg = alc5625_read(codec, virtual_reg_FOR_MISC_FUNC) & (0x3 << 6);
+ if (reg && (reg >> 6) != 0x3)
+ return 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ printk(KERN_DEBUG "ALC5625: Powering down.\n");
+ hp_mute_unmute_depop(codec, 1); /* mute hp */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x0000, 0x0300);
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD3,
+ 0x0000, 0x0c00);
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ printk(KERN_DEBUG "ALC5625: Powering on.\n");
+ hp_depop_mode2(codec);
+ hp_mute_unmute_depop(codec, 0); /* unmute hp */
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int aux_pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ return 0;
+}
+
+/* SPKOUT Mux */
+static const struct snd_kcontrol_new alc5625_ctrl_spkmux =
+ SOC_DAPM_ENUM("Route", alc5625_enum[3]);
+
+/* HPLOUT MUX */
+static const struct snd_kcontrol_new alc5625_ctrl_hplmux =
+ SOC_DAPM_ENUM("Route", alc5625_enum[4]);
+
+/* HPROUT MUX */
+static const struct snd_kcontrol_new alc5625_ctrl_hprmux =
+ SOC_DAPM_ENUM("Route", alc5625_enum[5]);
+/* AUXOUT MUX */
+static const struct snd_kcontrol_new alc5625_ctrl_auxmux =
+ SOC_DAPM_ENUM("Route", alc5625_enum[6]);
+
+static const struct snd_soc_dapm_widget alc5625_dapm_widgets[] = {
+ SND_SOC_DAPM_INPUT("Left LineIn"),
+ SND_SOC_DAPM_INPUT("Right LineIn"),
+ SND_SOC_DAPM_INPUT("Phone"),
+ SND_SOC_DAPM_INPUT("Mic1"),
+ SND_SOC_DAPM_INPUT("Mic2"),
+
+ SND_SOC_DAPM_PGA("Mic1 Boost",
+ ALC5625_PWR_MANAG_ADD3, 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic2 Boost",
+ ALC5625_PWR_MANAG_ADD3, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback DAC",
+ ALC5625_PWR_MANAG_ADD2, 9, 0),
+ SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback DAC",
+ ALC5625_PWR_MANAG_ADD2, 8, 0),
+ SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback DAC",
+ ALC5625_PWR_MANAG_ADD2, 10, 0),
+ SND_SOC_DAPM_PGA("Left LineIn PGA",
+ ALC5625_PWR_MANAG_ADD3,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Right LineIn PGA",
+ ALC5625_PWR_MANAG_ADD3, 6, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Phone PGA",
+ ALC5625_PWR_MANAG_ADD3, 5, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic1 PGA",
+ ALC5625_PWR_MANAG_ADD3, 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("Mic2 PGA",
+ ALC5625_PWR_MANAG_ADD3, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("VoDAC PGA",
+ ALC5625_PWR_MANAG_ADD1, 7, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Left Rec Mixer",
+ ALC5625_PWR_MANAG_ADD2, 1, 0,
+ &alc5625_ctrl_adc_l[0],
+ ARRAY_SIZE(alc5625_ctrl_adc_l)),
+ SND_SOC_DAPM_MIXER("Right Rec Mixer",
+ ALC5625_PWR_MANAG_ADD2, 0, 0,
+ &alc5625_ctrl_adc_r[0],
+ ARRAY_SIZE(alc5625_ctrl_adc_r)),
+ SND_SOC_DAPM_MIXER_E("Left HP Mixer",
+ ALC5625_PWR_MANAG_ADD2, 5, 0,
+ &alc5625_ctrl_hp_l[0],
+ ARRAY_SIZE(alc5625_ctrl_hp_l),
+ mixer_event, SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_MIXER_E("Right HP Mixer",
+ ALC5625_PWR_MANAG_ADD2, 4, 0,
+ &alc5625_ctrl_hp_r[0],
+ ARRAY_SIZE(alc5625_ctrl_hp_r),
+ mixer_event, SND_SOC_DAPM_POST_REG),
+ SND_SOC_DAPM_MIXER("MoNo Mixer",
+ ALC5625_PWR_MANAG_ADD2, 2, 0,
+ &alc5625_ctrl_mono[0],
+ ARRAY_SIZE(alc5625_ctrl_mono)),
+ SND_SOC_DAPM_MIXER("SPK Mixer",
+ ALC5625_PWR_MANAG_ADD2, 3, 0,
+ &alc5625_ctrl_spk[0],
+ ARRAY_SIZE(alc5625_ctrl_spk)),
+ SND_SOC_DAPM_MIXER("HP Mixer",
+ SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("DAC Mixer",
+ SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Line Mixer",
+ SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("SPKOUT Mux",
+ SND_SOC_NOPM, 0, 0,
+ &alc5625_ctrl_spkmux),
+ SND_SOC_DAPM_MUX("HPLOUT Mux",
+ SND_SOC_NOPM, 0, 0,
+ &alc5625_ctrl_hplmux),
+ SND_SOC_DAPM_MUX("HPROUT Mux",
+ SND_SOC_NOPM, 0, 0,
+ &alc5625_ctrl_hprmux),
+ SND_SOC_DAPM_MUX("AUXOUT Mux",
+ SND_SOC_NOPM, 0, 0,
+ &alc5625_ctrl_auxmux),
+ SND_SOC_DAPM_PGA_E("SPKL Out PGA",
+ virtual_reg_FOR_MISC_FUNC, 4, 0,
+ NULL, 0, spk_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("SPKR Out PGA",
+ virtual_reg_FOR_MISC_FUNC, 5, 0,
+ NULL, 0, spk_pga_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPL Out PGA",
+ virtual_reg_FOR_MISC_FUNC, 6, 0,
+ NULL, 0, hp_pga_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("HPR Out PGA",
+ virtual_reg_FOR_MISC_FUNC, 7, 0,
+ NULL, 0, hp_pga_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("AUX Out PGA",
+ ALC5625_PWR_MANAG_ADD3, 14, 0,
+ NULL, 0, aux_pga_event,
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_ADC("Left ADC", "Left ADC HiFi Capture",
+ ALC5625_PWR_MANAG_ADD2, 7, 0),
+ SND_SOC_DAPM_ADC("Right ADC", "Right ADC HiFi Capture",
+ ALC5625_PWR_MANAG_ADD2, 6, 0),
+ SND_SOC_DAPM_OUTPUT("SPKL"),
+ SND_SOC_DAPM_OUTPUT("SPKR"),
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+ SND_SOC_DAPM_OUTPUT("AUX"),
+ SND_SOC_DAPM_MICBIAS("Mic1 Bias",
+ ALC5625_PWR_MANAG_ADD1, 3, 0),
+ SND_SOC_DAPM_MICBIAS("Mic2 Bias",
+ ALC5625_PWR_MANAG_ADD1, 2, 0),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+ /* Input PGA */
+ {"Left LineIn PGA", NULL, "Left LineIn"},
+ {"Right LineIn PGA", NULL, "Right LineIn"},
+ {"Phone PGA", NULL, "Phone"},
+ {"Mic1 Boost", NULL, "Mic1"},
+ {"Mic2 Boost", NULL, "Mic2"},
+ {"Mic1 PGA", NULL, "Mic1"},
+ {"Mic2 PGA", NULL, "Mic2"},
+ {"VoDAC PGA", NULL, "Voice DAC"},
+
+ /* Left ADC mixer */
+ {"Left Rec Mixer", "LineIn Capture Switch", "Left LineIn"},
+ {"Left Rec Mixer", "Phone Capture Switch", "Phone"},
+ {"Left Rec Mixer", "Mic1 Capture Switch", "Mic1 Boost"},
+ {"Left Rec Mixer", "Mic2 Capture Switch", "Mic2 Boost"},
+ {"Left Rec Mixer", "HP Mixer Capture Switch", "Left HP Mixer"},
+ {"Left Rec Mixer", "SPK Mixer Capture Switch", "SPK Mixer"},
+ {"Left Rec Mixer", "MoNo Mixer Capture Switch", "MoNo Mixer"},
+
+ /* Right ADC Mixer */
+ {"Right Rec Mixer", "LineIn Capture Switch", "Right LineIn"},
+ {"Right Rec Mixer", "Phone Capture Switch", "Phone"},
+ {"Right Rec Mixer", "Mic1 Capture Switch", "Mic1 Boost"},
+ {"Right Rec Mixer", "Mic2 Capture Switch", "Mic2 Boost"},
+ {"Right Rec Mixer", "HP Mixer Capture Switch", "Right HP Mixer"},
+ {"Right Rec Mixer", "SPK Mixer Capture Switch", "SPK Mixer"},
+ {"Right Rec Mixer", "MoNo Mixer Capture Switch", "MoNo Mixer"},
+
+ /* HPL mixer */
+ {"Left HP Mixer", "ADC Playback Switch", "Left Rec Mixer"},
+ {"Left HP Mixer", "LineIn Playback Switch", "Left LineIn PGA"},
+ {"Left HP Mixer", "Phone Playback Switch", "Phone PGA"},
+ {"Left HP Mixer", "Mic1 Playback Switch", "Mic1 PGA"},
+ {"Left HP Mixer", "Mic2 Playback Switch", "Mic2 PGA"},
+ {"Left HP Mixer", "HIFI DAC Playback Switch", "Left DAC"},
+ {"Left HP Mixer", "Voice DAC Playback Switch", "VoDAC PGA"},
+
+ /* HPR mixer */
+ {"Right HP Mixer", "ADC Playback Switch", "Right Rec Mixer"},
+ {"Right HP Mixer", "LineIn Playback Switch", "Right LineIn PGA"},
+ {"Right HP Mixer", "HIFI DAC Playback Switch", "Right DAC"},
+ {"Right HP Mixer", "Phone Playback Switch", "Phone PGA"},
+ {"Right HP Mixer", "Mic1 Playback Switch", "Mic1 PGA"},
+ {"Right HP Mixer", "Mic2 Playback Switch", "Mic2 PGA"},
+ {"Right HP Mixer", "Voice DAC Playback Switch", "VoDAC PGA"},
+
+ /* DAC Mixer */
+ {"DAC Mixer", NULL, "Left DAC"},
+ {"DAC Mixer", NULL, "Right DAC"},
+
+ /* line mixer */
+ {"Line Mixer", NULL, "Left LineIn PGA"},
+ {"Line Mixer", NULL, "Right LineIn PGA"},
+
+ /* spk mixer */
+ {"SPK Mixer", "Line Mixer Playback Switch", "Line Mixer"},
+ {"SPK Mixer", "Phone Playback Switch", "Phone PGA"},
+ {"SPK Mixer", "Mic1 Playback Switch", "Mic1 PGA"},
+ {"SPK Mixer", "Mic2 Playback Switch", "Mic2 PGA"},
+ {"SPK Mixer", "DAC Mixer Playback Switch", "DAC Mixer"},
+ {"SPK Mixer", "Voice DAC Playback Switch", "VoDAC PGA"},
+
+ /* mono mixer */
+ {"MoNo Mixer", "Line Mixer Playback Switch", "Line Mixer"},
+ {"MoNo Mixer", "ADCL Playback Switch", "Left Rec Mixer"},
+ {"MoNo Mixer", "ADCR Playback Switch", "Right Rec Mixer"},
+ {"MoNo Mixer", "Mic1 Playback Switch", "Mic1 PGA"},
+ {"MoNo Mixer", "Mic2 Playback Switch", "Mic2 PGA"},
+ {"MoNo Mixer", "DAC Mixer Playback Switch", "DAC Mixer"},
+ {"MoNo Mixer", "Voice DAC Playback Switch", "VoDAC PGA"},
+
+ /* hp mixer */
+ {"HP Mixer", NULL, "Left HP Mixer"},
+ {"HP Mixer", NULL, "Right HP Mixer"},
+
+ /* spkout mux */
+ {"SPKOUT Mux", "HP Mixer", "HP Mixer"},
+ {"SPKOUT Mux", "SPK Mixer", "SPK Mixer"},
+ {"SPKOUT Mux", "Mono Mixer", "MoNo Mixer"},
+
+ /* hpl out mux */
+ {"HPLOUT Mux", "HPL Mixer", "Left HP Mixer"},
+
+ /* hpr out mux */
+ {"HPROUT Mux", "HPR Mixer", "Right HP Mixer"},
+
+ /* aux out mux */
+ {"AUXOUT Mux", "HP Mixer", "HP Mixer"},
+ {"AUXOUT Mux", "SPK Mixer", "SPK Mixer"},
+ {"SPKOUT Mux", "Mono Mixer", "MoNo Mixer"},
+
+ /* spkl out pga */
+ {"SPKL Out PGA", NULL, "SPKOUT Mux"},
+
+ /* spkr out pga */
+ {"SPKR Out PGA", NULL, "SPKOUT Mux"},
+
+ /* hpl out pga */
+ {"HPL Out PGA", NULL, "HPLOUT Mux"},
+
+ /* hpr out pga */
+ {"HPR Out PGA", NULL, "HPROUT Mux"},
+
+ /* aux out pga */
+ {"AUX Out PGA", NULL, "AUXOUT Mux"},
+
+ /* left adc */
+ {"Left ADC", NULL, "Left Rec Mixer"},
+
+ /* right adc */
+ {"Right ADC", NULL, "Right Rec Mixer"},
+
+ /* output */
+ {"SPKL", NULL, "SPKL Out PGA"},
+ {"SPKR", NULL, "SPKR Out PGA"},
+ {"HPL", NULL, "HPL Out PGA"},
+ {"HPR", NULL, "HPR Out PGA"},
+ {"AUX", NULL, "AUX Out PGA"},
+};
+
+static int alc5625_add_widgets(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret;
+
+ ret = snd_soc_dapm_new_controls(dapm, alc5625_dapm_widgets,
+ ARRAY_SIZE(alc5625_dapm_widgets));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct _pll_div {
+ u32 pll_in;
+ u32 pll_out;
+ u16 regvalue;
+};
+
+/*
+ * watch out!
+ * our codec support you to select different source as pll input,
+ * but if you use both of the I2S audio interface and pcm interface
+ * instantially. The two DAI must have the same pll setting params,
+ * so you have to offer the same pll input, and set our codec's sysclk
+ * the same one, we suggest 24576000.
+ */
+static const struct _pll_div codec_master_pll1_div[] = {
+ { 2048000, 8192000, 0x0ea0},
+ { 3686400, 8192000, 0x4e27},
+ {12000000, 8192000, 0x456b},
+ {13000000, 8192000, 0x495f},
+ {13100000, 8192000, 0x0320},
+ { 2048000, 11289600, 0xf637},
+ { 3686400, 11289600, 0x2f22},
+ {12000000, 11289600, 0x3e2f},
+ {13000000, 11289600, 0x4d5b},
+ {13100000, 11289600, 0x363b},
+ { 2048000, 16384000, 0x1ea0},
+ { 3686400, 16384000, 0x9e27},
+ {12000000, 16384000, 0x452b},
+ {13000000, 16384000, 0x542f},
+ {13100000, 16384000, 0x03a0},
+ { 2048000, 16934400, 0xe625},
+ { 3686400, 16934400, 0x9126},
+ {12000000, 16934400, 0x4d2c},
+ {13000000, 16934400, 0x742f},
+ {13100000, 16934400, 0x3c27},
+ { 2048000, 22579200, 0x2aa0},
+ { 3686400, 22579200, 0x2f20},
+ {12000000, 22579200, 0x7e2f},
+ {13000000, 22579200, 0x742f},
+ {13100000, 22579200, 0x3c27},
+ { 2048000, 24576000, 0x2ea0},
+ { 3686400, 24576000, 0xee27},
+ {12000000, 24576000, 0x2915},
+ {13000000, 24576000, 0x772e},
+ {13100000, 24576000, 0x0d20},
+ {26000000, 24576000, 0x2027},
+ {26000000, 22579200, 0x392f},
+ {24576000, 22579200, 0x0921},
+ {24576000, 24576000, 0x02a0},
+};
+
+static const struct _pll_div codec_bclk_pll1_div[] = {
+ { 256000, 4096000, 0x3ea0},
+ { 352800, 5644800, 0x3ea0},
+ { 512000, 8192000, 0x3ea0},
+ { 705600, 11289600, 0x3ea0},
+ {1024000, 16384000, 0x3ea0},
+ {1411200, 22579200, 0x3ea0},
+ {1536000, 24576000, 0x3ea0},
+ {2048000, 16384000, 0x1ea0},
+ {2822400, 22579200, 0x1ea0},
+ {3072000, 24576000, 0x1ea0},
+ { 705600, 11289600, 0x3ea0},
+ { 705600, 8467200, 0x3ab0},
+};
+
+static const struct _pll_div codec_vbclk_pll1_div[] = {
+ { 256000, 4096000, 0x3ea0},
+ { 352800, 5644800, 0x3ea0},
+ { 512000, 8192000, 0x3ea0},
+ { 705600, 11289600, 0x3ea0},
+ {1024000, 16384000, 0x3ea0},
+ {1411200, 22579200, 0x3ea0},
+ {1536000, 24576000, 0x3ea0},
+ {2048000, 16384000, 0x1ea0},
+ {2822400, 22579200, 0x1ea0},
+ {3072000, 24576000, 0x1ea0},
+ { 705600, 11289600, 0x3ea0},
+ { 705600, 8467200, 0x3ab0},
+};
+
+struct _coeff_div_stereo {
+ unsigned int mclk;
+ unsigned int rate;
+ unsigned int reg60;
+ unsigned int reg62;
+};
+
+struct _coeff_div_voice {
+ unsigned int mclk;
+ unsigned int rate;
+ unsigned int reg64;
+};
+
+static const struct _coeff_div_stereo coeff_div_stereo[] = {
+ /*
+ * bclk is config to 32fs, if codec is choose to
+ * be slave mode , input bclk should be 32*fs
+ */
+ {24576000, 48000, 0x3174, 0x1010},
+ {12288000, 48000, 0x1174, 0x0000},
+ {18432000, 48000, 0x2174, 0x1111},
+ {36864000, 48000, 0x2274, 0x2020},
+ {49152000, 48000, 0xf074, 0x3030},
+ {24576000, 48000, 0x3172, 0x1010},
+ {24576000, 8000, 0xB274, 0x2424},
+ {24576000, 16000, 0xB174, 0x2222},
+ {24576000, 32000, 0xB074, 0x2121},
+ {22579200, 11025, 0X3374, 0x1414},
+ {22579200, 22050, 0X3274, 0x1212},
+ {22579200, 44100, 0X3174, 0x1010},
+ {0, 0, 0, 0},
+};
+
+static const struct _coeff_div_voice coeff_div_voice[] = {
+ /*
+ * bclk is config to 32fs, if codec is choose to be slave mode,
+ * input bclk should be 32*fs
+ */
+ {24576000, 16000, 0x2622},
+ {24576000, 8000, 0x2824},
+ {0, 0, 0},
+};
+
+static int get_coeff(unsigned int mclk, unsigned int rate, int mode)
+{
+ int i;
+
+ if (!mode) {
+ for (i = 0; i < ARRAY_SIZE(coeff_div_stereo); i++) {
+ if ((coeff_div_stereo[i].rate == rate) &&
+ (coeff_div_stereo[i].mclk == mclk))
+ return i;
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(coeff_div_voice); i++) {
+ if ((coeff_div_voice[i].rate == rate) &&
+ (coeff_div_voice[i].mclk == mclk))
+ return i;
+ }
+ }
+
+ return -EINVAL;
+ printk(KERN_ERR "can't find a matched mclk and rate in %s\n",
+ (mode ? "coeff_div_voice[]" : "coeff_div_audio[]"));
+}
+
+static int alc5625_codec_set_dai_pll(struct snd_soc_dai *codec_dai,
+ int pll_id, int source,
+ unsigned int freq_in,
+ unsigned int freq_out)
+{
+ int i;
+ int pll_src_regval = 0;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ const struct _pll_div *codec_pll_div = NULL;
+ int pll_div_count = 0;
+
+ if (pll_id < ALC5625_PLL1_FROM_MCLK || pll_id > ALC5625_PLL1_FROM_VBCLK)
+ return -EINVAL;
+
+ if (!freq_in || !freq_out)
+ return 0;
+
+ switch (pll_id) {
+ case ALC5625_PLL1_FROM_MCLK:
+ codec_pll_div = codec_master_pll1_div;
+ pll_div_count = ARRAY_SIZE(codec_master_pll1_div);
+ break;
+ case ALC5625_PLL1_FROM_BCLK:
+ codec_pll_div = codec_bclk_pll1_div;
+ pll_div_count = ARRAY_SIZE(codec_bclk_pll1_div);
+ pll_src_regval = 0x2000;
+ break;
+ case ALC5625_PLL1_FROM_VBCLK:
+ codec_pll_div = codec_vbclk_pll1_div;
+ pll_div_count = ARRAY_SIZE(codec_vbclk_pll1_div);
+ pll_src_regval = 0x3000;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = 0; i < pll_div_count; i++)
+ if ((freq_in == codec_pll_div[i].pll_in) &&
+ (freq_out == codec_pll_div[i].pll_out)) {
+ alc5625_write(codec,
+ ALC5625_GEN_CTRL_REG2,
+ pll_src_regval);
+
+ /* set pll code */
+ alc5625_write(codec,
+ ALC5625_PLL_CTRL,
+ codec_pll_div[i].regvalue);
+
+ /* enable pll power */
+ alc5625_write_mask(codec,
+ ALC5625_PWR_MANAG_ADD2,
+ 0x8000, 0x8000);
+
+ alc5625_write_mask(codec,
+ ALC5625_GEN_CTRL_REG1,
+ 0x8000, 0x8000);
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int alc5625_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq,
+ int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct alc5625_priv *alc5625 = snd_soc_codec_get_drvdata(codec);
+
+ if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+ alc5625->stereo_sysclk = freq;
+ return 0;
+ }
+
+ printk(KERN_ERR "unsupported sysclk freq %u for audio i2s\n", freq);
+ alc5625->stereo_sysclk = DEFAULT_SYSCLK;
+
+ return 0;
+}
+
+static int alc5625_voice_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq,
+ int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct alc5625_priv *alc5625 = snd_soc_codec_get_drvdata(codec);
+
+ if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+ alc5625->voice_sysclk = freq;
+ return 0;
+ }
+
+ printk(KERN_ERR "unsupported sysclk freq %u for voice pcm\n", freq);
+ alc5625->voice_sysclk = DEFAULT_SYSCLK;
+
+ return 0;
+}
+
+static int alc5625_hifi_pcm_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 alc5625_priv *alc5625 = snd_soc_codec_get_drvdata(codec);
+ unsigned int iface;
+
+ int rate = params_rate(params);
+ int coeff = get_coeff(alc5625->stereo_sysclk, rate, 0);
+
+ iface = alc5625_read(codec, ALC5625_MAIN_SDP_CTRL) & 0xfff3;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* Nothing to be done */
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ iface |= 0x000c;
+ }
+
+ alc5625_write(codec, ALC5625_MAIN_SDP_CTRL, iface);
+
+ /* power i2s and dac ref */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0xc801, 0xc801);
+ if (coeff >= 0) {
+ alc5625_write(codec, ALC5625_STEREO_DAC_CLK_CTRL1,
+ coeff_div_stereo[coeff].reg60);
+ alc5625_write(codec, ALC5625_STEREO_DAC_CLK_CTRL2,
+ coeff_div_stereo[coeff].reg62);
+ }
+
+ return 0;
+}
+
+static int alc5625_voice_pcm_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 alc5625_priv *alc5625 = snd_soc_codec_get_drvdata(codec);
+ unsigned int iface;
+ int rate = params_rate(params);
+ int coeff = get_coeff(alc5625->voice_sysclk, rate, 1);
+
+ iface = alc5625_read(codec, ALC5625_EXTEND_SDP_CTRL) & 0xfff3;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* Nothing to be done */
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ iface |= 0x000c;
+ }
+
+ /* power i2s and dac ref */
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x0801, 0x0801);
+ alc5625_write(codec, ALC5625_EXTEND_SDP_CTRL, iface);
+ if (coeff >= 0)
+ alc5625_write(codec, ALC5625_VOICE_DAC_PCMCLK_CTRL1,
+ coeff_div_voice[coeff].reg64);
+
+ return 0;
+}
+
+static int alc5625_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+
+ struct snd_soc_codec *codec = codec_dai->codec;
+ u16 iface = 0;
+
+ /* set master/slave interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface = 0x0000;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ iface = 0x8000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* Nothing to be done */
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= 0x0001;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= 0x0002;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= 0x0003;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Nothing to be done */
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x0080;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ alc5625_write(codec, ALC5625_MAIN_SDP_CTRL, iface);
+ return 0;
+}
+
+static int alc5625_voice_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ int iface;
+
+ /*set slave/master mode*/
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface = 0x0000;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ iface = 0x4000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* Nothing to be done */
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= 0x0001;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= 0x0002;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ iface |= 0x0003;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*clock inversion*/
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Nothing to be done */
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= 0x0080;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ iface |= 0x8000; /* enable vopcm */
+ alc5625_write(codec, ALC5625_EXTEND_SDP_CTRL, iface);
+ return 0;
+}
+
+static int alc5625_hifi_codec_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (mute)
+ alc5625_write_mask(codec, ALC5625_STEREO_DAC_VOL,
+ 0x8080, 0x8080);
+ else
+ alc5625_write_mask(codec, ALC5625_STEREO_DAC_VOL,
+ 0x0000, 0x8080);
+ return 0;
+}
+
+static int alc5625_voice_codec_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (mute)
+ alc5625_write_mask(codec, ALC5625_VOICE_DAC_OUT_VOL,
+ 0x1000, 0x1000);
+ else
+ alc5625_write_mask(codec, ALC5625_VOICE_DAC_OUT_VOL,
+ 0x0000, 0x1000);
+ return 0;
+}
+
+static int alc5625_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ alc5625_write(codec, ALC5625_PD_CTRL_STAT, 0x0000);
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD2,
+ 0x2000, 0x2000);
+ alc5625_write_mask(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x000e, 0x000e);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ break;
+ case SND_SOC_BIAS_OFF:
+ alc5625_write_mask(codec,
+ ALC5625_HP_OUT_VOL, 0x8080, 0x8080); /* mute hp */
+ alc5625_write_mask(codec, ALC5625_SPK_OUT_VOL,
+ 0x8080, 0x8080); /* mute spk */
+ alc5625_write(codec, ALC5625_PWR_MANAG_ADD3,
+ 0x0000); /* power off all bit */
+ alc5625_write(codec, ALC5625_PWR_MANAG_ADD1,
+ 0x0000); /* power off all bit */
+ alc5625_write(codec, ALC5625_PWR_MANAG_ADD2,
+ 0x0000); /* power off all bit */
+ break;
+ }
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+
+#define ALC5625_STEREO_RATES SNDRV_PCM_RATE_8000_48000
+
+#define ALC5626_VOICE_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000)
+
+#define ALC5625_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S8)
+
+static struct snd_soc_dai_ops alc5625_dai_ops_hifi = {
+
+ .hw_params = alc5625_hifi_pcm_hw_params,
+ .set_fmt = alc5625_hifi_codec_set_dai_fmt,
+ .set_pll = alc5625_codec_set_dai_pll,
+ .set_sysclk = alc5625_hifi_codec_set_dai_sysclk,
+ .digital_mute = alc5625_hifi_codec_mute,
+};
+
+static struct snd_soc_dai_ops alc5625_dai_ops_voice = {
+
+ .hw_params = alc5625_voice_pcm_hw_params,
+ .set_fmt = alc5625_voice_codec_set_dai_fmt,
+ .set_pll = alc5625_codec_set_dai_pll,
+ .set_sysclk = alc5625_voice_codec_set_dai_sysclk,
+ .digital_mute = alc5625_voice_codec_mute,
+};
+
+static struct snd_soc_dai_driver alc5625_dai[] = {
+ {
+ .name = "alc5625-aif1",
+ .playback = {
+ .stream_name = "HiFi Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = ALC5625_STEREO_RATES,
+ .formats = ALC5625_FORMATS,
+ },
+ .capture = {
+ .stream_name = "HiFi Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ALC5625_STEREO_RATES,
+ .formats = ALC5625_FORMATS,
+ },
+ .ops = &alc5625_dai_ops_hifi,
+ },
+
+ /* voice codec dai */
+ {
+ .name = "ALC5625 Voice",
+ .id = 1,
+ .playback = {
+ .stream_name = "Voice Playback",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = ALC5626_VOICE_RATES,
+ .formats = ALC5625_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Voice Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = ALC5626_VOICE_RATES,
+ .formats = ALC5625_FORMATS,
+ },
+
+ .ops = &alc5625_dai_ops_voice,
+
+ },
+};
+
+static void alc5625_work(struct work_struct *work)
+{
+ struct snd_soc_codec *codec =
+ container_of(work, struct snd_soc_codec,\
+ dapm.delayed_work.work);
+ alc5625_set_bias_level(codec, codec->dapm.bias_level);
+}
+
+
+static int alc5625_codec_init(struct snd_soc_codec *codec)
+{
+
+ int ret = 0;
+
+ codec->read = alc5625_read;
+ codec->write = alc5625_write;
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ codec->num_dai = 2;
+ codec->reg_cache = kmemdup(alc5625_reg, sizeof(alc5625_reg),
+ GFP_KERNEL);
+ if (codec->reg_cache == NULL)
+ return -ENOMEM;
+
+ alc5625_reset(codec);
+
+ alc5625_write(codec, ALC5625_PD_CTRL_STAT, 0);
+ alc5625_write(codec, ALC5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS);
+ alc5625_write(codec, ALC5625_PWR_MANAG_ADD2, PWR_MIXER_VREF);
+ alc5625_reg_init(codec);
+ alc5625_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+ codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+ schedule_delayed_work(&codec->dapm.delayed_work, msecs_to_jiffies(80));
+
+ ret = snd_soc_add_codec_controls(codec, alc5625_snd_ctrls,
+ ARRAY_SIZE(alc5625_snd_ctrls));
+ if (ret)
+ return ret;
+ alc5625_add_widgets(codec);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int alc5625_suspend(struct snd_soc_codec *codec)
+{
+ alc5625_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int alc5625_resume(struct snd_soc_codec *codec)
+{
+ alc5625_reset(codec);
+ alc5625_write(codec, ALC5625_PD_CTRL_STAT, 0);
+ alc5625_write(codec, ALC5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS);
+ alc5625_write(codec, ALC5625_PWR_MANAG_ADD2, PWR_MIXER_VREF);
+ alc5625_reg_init(codec);
+
+ /* charge alc5625 caps */
+ if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
+ alc5625_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+ codec->dapm.bias_level = SND_SOC_BIAS_ON;
+ schedule_delayed_work(&codec->dapm.delayed_work,
+ msecs_to_jiffies(100));
+ }
+
+ return 0;
+}
+#else
+#define alc5625_suspend NULL
+#define alc5625_resume NULL
+#endif
+
+static int alc5625_probe(struct snd_soc_codec *codec)
+{
+ struct alc5625_priv *alc5625 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ codec->control_data = alc5625->regmap;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5625->control_type);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ mutex_init(&codec->mutex);
+ INIT_DELAYED_WORK(&codec->dapm.delayed_work, alc5625_work);
+
+ ret = alc5625_codec_init(codec);
+
+ return ret;
+}
+
+static int run_delayed_work(struct delayed_work *dwork)
+{
+ int ret;
+
+ /* cancel any work waiting to be queued. */
+ ret = cancel_delayed_work(dwork);
+
+ /* if there was any work waiting then we run it now and
+ * wait for it's completion */
+ if (ret) {
+ schedule_delayed_work(dwork, 0);
+ flush_scheduled_work();
+ }
+ return ret;
+}
+
+static int alc5625_remove(struct snd_soc_codec *codec)
+{
+ if (codec->control_data)
+ alc5625_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ run_delayed_work(&codec->dapm.delayed_work);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_alc5625 = {
+ .probe = alc5625_probe,
+ .remove = alc5625_remove,
+ .suspend = alc5625_suspend,
+ .resume = alc5625_resume,
+ .read = alc5625_read,
+ .write = alc5625_write,
+ .set_bias_level = alc5625_set_bias_level,
+ .reg_cache_size = ARRAY_SIZE(alc5625_reg)*2,
+ .reg_cache_default = alc5625_reg,
+ .reg_word_size = 2,
+};
+
+static const struct regmap_config alc5625_i2c_regmap_config = {
+ .val_bits = 16,
+ .reg_bits = 8,
+};
+
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static __devinit int alc5625_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct alc5625_priv *alc5625;
+ int ret;
+
+ alc5625 = kzalloc(sizeof(struct alc5625_priv), GFP_KERNEL);
+ if (alc5625 == NULL)
+ return -ENOMEM;
+
+ alc5625->regmap = regmap_init_i2c(i2c, &alc5625_i2c_regmap_config);
+ if (IS_ERR(alc5625->regmap)) {
+ ret = PTR_ERR(alc5625->regmap);
+ goto err_free;
+ }
+
+ i2c_set_clientdata(i2c, alc5625);
+ alc5625->control_data = i2c;
+ alc5625->control_type = SND_SOC_REGMAP;
+
+ ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_alc5625,
+ alc5625_dai, ARRAY_SIZE(alc5625_dai));
+
+ if (ret < 0)
+ goto err_regmap;
+
+ return ret;
+
+err_regmap:
+ regmap_exit(alc5625->regmap);
+err_free:
+ if (ret < 0)
+ kfree(alc5625);
+ return ret;
+}
+
+static __devexit int alc5625_i2c_remove(struct i2c_client *client)
+{
+ struct alc5625_priv *alc5625 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ regmap_exit(alc5625->regmap);
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+static const struct i2c_device_id alc5625_i2c_id[] = {
+ { "alc5625", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, alc5625_i2c_id);
+
+static const struct of_device_id alc5625_of_match[] = {
+ { .compatible = "realtek,alc5625", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, alc5625_of_match);
+
+static struct i2c_driver alc5625_i2c_driver = {
+ .driver = {
+ .name = "alc5625-codec",
+ .owner = THIS_MODULE,
+ .of_match_table = alc5625_of_match,
+ },
+ .probe = alc5625_i2c_probe,
+ .remove = __devexit_p(alc5625_i2c_remove),
+ .id_table = alc5625_i2c_id,
+};
+#endif
+
+module_i2c_driver(alc5625_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC ALC5625 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/alc5625/alc5625.h b/drivers/staging/alc5625/alc5625.h
new file mode 100644
index 00000000000..5e02a36d91e
--- /dev/null
+++ b/drivers/staging/alc5625/alc5625.h
@@ -0,0 +1,865 @@
+/*
+ * alc5625.h -- Header file for ALC5625 ALSA SoC Audio driver
+ *
+ * Copyright (C) 2011 Insignal Co., Ltd.
+ *
+ * Author: Pan<pan@insginal.co.kr>
+ *
+ * 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 _ALC5625_H
+#define _ALC5625_H
+
+#define ALC5625_RESET 0X00 /* RESET CODEC TO DEFAULT */
+#define ALC5625_SPK_OUT_VOL 0X02 /* SPEAKER OUT VOLUME */
+#define ALC5625_HP_OUT_VOL 0X04 /* HEADPHONE OUTPUT VOLUME */
+#define ALC5625_AUX_OUT_VOL 0X06 /* AUXOUT VOLUME */
+#define ALC5625_PHONEIN_VOL 0X08 /* PHONE INPUT VOLUME */
+#define ALC5625_LINE_IN_VOL 0X0A /* LINE IN VOLUME */
+#define ALC5625_STEREO_DAC_VOL 0X0C /* STEREO DAC VOLUME */
+#define ALC5625_MIC_VOL 0X0E /* MICROPHONE VOLUME */
+
+/* STEREO DAC AND MIC ROUTING CONTROL */
+#define ALC5625_DAC_AND_MIC_CTRL 0X10
+#define ALC5625_ADC_REC_GAIN 0X12 /* ADC RECORD GAIN */
+#define ALC5625_ADC_REC_MIXER 0X14 /* ADC RECORD MIXER CONTROL */
+#define ALC5625_VOICE_DAC_OUT_VOL 0X18 /* VOICE DAC OUTPUT VOLUME */
+#define ALC5625_VODSP_PDM_CTL 0X1A /* VODSP & PDM CONTROL */
+#define ALC5625_OUTPUT_MIXER_CTRL 0X1C /* OUTPUT MIXER CONTROL */
+#define ALC5625_VODSP_CTL 0X1E /* VODSP CONTROL */
+#define ALC5625_MIC_CTRL 0X22 /* MICROPHONE CONTROL */
+#define ALC5625_DMIC_CTRL 0x24
+#define ALC5625_PD_CTRL_STAT 0X26 /* POWER DOWN CONTROL/STATUS */
+
+/* STEREO DAC,VOICE DAC,STEREO ADC FUNCTION SELECT */
+#define ALC5625_DAC_ADC_VODAC_FUN_SEL 0X2E
+
+/* MAIN SERIAL DATA PORT CONTROL(STEREO I2S) */
+#define ALC5625_MAIN_SDP_CTRL 0X34
+
+/* EXTEND SERIAL DATA PORT CONTROL(VOICE I2S/PCM) */
+#define ALC5625_EXTEND_SDP_CTRL 0X36
+#define ALC5625_PWR_MANAG_ADD1 0X3A /* POWER MANAGMENT ADDITION 1 */
+#define ALC5625_PWR_MANAG_ADD2 0X3C /* POWER MANAGMENT ADDITION 2 */
+#define ALC5625_PWR_MANAG_ADD3 0X3E /* POWER MANAGMENT ADDITION 3 */
+
+/* GENERAL PURPOSE CONTROL REGISTER 1 */
+#define ALC5625_GEN_CTRL_REG1 0X40
+
+/* GENERAL PURPOSE CONTROL REGISTER 2 */
+#define ALC5625_GEN_CTRL_REG2 0X42
+#define ALC5625_PLL_CTRL 0X44 /* PLL1 CONTROL */
+#define ALC5625_PLL2_CTRL 0X46 /* PLL2 CONTROL */
+#define ALC5625_LDO_CTRL 0X48 /* LDO CONTROL */
+#define ALC5625_GPIO_PIN_CONFIG 0X4C /* GPIO PIN CONFIGURATION */
+#define ALC5625_GPIO_PIN_POLARITY 0X4E /* GPIO PIN POLARITY */
+#define ALC5625_GPIO_PIN_STICKY 0X50 /* GPIO PIN STICKY */
+#define ALC5625_GPIO_PIN_WAKEUP 0X52 /* GPIO PIN WAKE UP */
+#define ALC5625_GPIO_PIN_STATUS 0X54 /* GPIO PIN STATUS */
+#define ALC5625_GPIO_PIN_SHARING 0X56 /* GPIO PIN SHARING */
+
+/* OVER TEMPERATURE AND CURRENT STATUS */
+#define ALC5625_OVER_TEMP_CURR_STATUS 0X58
+
+/* SOFT VOLUME CONTROL SETTING */
+#define ALC5625_SOFT_VOL_CTRL 0X5A
+#define ALC5625_GPIO_OUT_CTRL 0X5C /* GPIO OUTPUT PIN CONTRL */
+#define ALC5625_MISC_CTRL 0X5E /* MISC CONTROL */
+#define ALC5625_STEREO_DAC_CLK_CTRL1 0X60 /* STEREO DAC CLOCK CONTROL 1 */
+#define ALC5625_STEREO_DAC_CLK_CTRL2 0X62 /* STEREO DAC CLOCK CONTROL 2 */
+
+/* VOICE/PCM DAC CLOCK CONTROL 1 */
+#define ALC5625_VOICE_DAC_PCMCLK_CTRL1 0X64
+
+/* PSEDUEO STEREO /SPATIAL EFFECT BLOCK CONTROL */
+#define ALC5625_PSEDUEO_SPATIAL_CTRL 0X68
+#define ALC5625_PRIV_ADDR 0X6A /* PRIVATE ADDRESS */
+#define ALC5625_PRIV_DATA 0X6C /* PRIVATE DATA */
+
+/* EQ CONTROL AND STATUS /ADC HPF CONTROL */
+#define ALC5625_EQ_CTRL_ADC_HPF 0X6E
+#define ALC5625_VODSP_REG_ADDR 0x70 /* VODSP REGISTER ADDRESS */
+#define ALC5625_VODSP_REG_DATA 0x72 /* VODSP REGISTER DATA */
+#define ALC5625_VODSP_REG_CMD 0x74 /* VODSP REGISTER COMMAND */
+
+/* Bit define of Codec Register */
+#define ALC_L_MUTE (0x1<<15) /* Mute Left Control */
+
+/* Mute Left Zero-Cross Detector Control */
+#define ALC_L_ZC (0x1<<14)
+#define ALC_R_MUTE (0x1<<7) /* Mute Right Control */
+
+/* Mute Right Zero-Cross Detector Control */
+#define ALC_R_ZC (0x1<<6)
+
+/* Mute source to HP Mixer */
+#define ALC_M_HP_MIXER (0x1<<15)
+
+/* Mute source to Speaker Mixer */
+#define ALC_M_SPK_MIXER (0x1<<14)
+
+/* Mute source to Mono Mixer */
+#define ALC_M_MONO_MIXER (0x1<<13)
+
+/* Phone Input Volume(0x08) */
+/* Mute Phone In volume to HP mixer */
+#define M_PHONEIN_TO_HP_MIXER (0x1<<15)
+
+/* Mute Phone In volume to speaker mixer */
+#define M_PHONEIN_TO_SPK_MIXER (0x1<<14)
+
+/* Mic Routing Control(0x10) */
+/* Mute MIC1 to HP mixer */
+#define M_MIC1_TO_HP_MIXER (0x1<<15)
+
+/* Mute MiC1 to SPK mixer */
+#define M_MIC1_TO_SPK_MIXER (0x1<<14)
+
+/* Mute MIC1 to MONO mixer */
+#define M_MIC1_TO_MONO_MIXER (0x1<<13)
+
+/* Mute MIC2 to HP mixer */
+#define M_MIC2_TO_HP_MIXER (0x1<<11)
+
+/* Mute MiC2 to SPK mixer */
+#define M_MIC2_TO_SPK_MIXER (0x1<<10)
+
+/* Mute MIC2 to MONO mixer */
+#define M_MIC2_TO_MONO_MIXER (0x1<<9)
+
+/* Mute DAC to HP left mixer */
+#define M_DAC_TO_HPL_MIXER (0x1<<3)
+
+/* Mute DAC to HP right mixer */
+#define M_DAC_TO_HPR_MIXER (0x1<<2)
+
+/* Mute DAC to SPK mixer */
+#define M_DAC_TO_SPK_MIXER (0x1<<1)
+
+/* Mute DAC to MONO mixer */
+#define M_DAC_TO_MONO_MIXER (0x1<<0)
+
+/* ADC Record Gain(0x12) */
+/* Mute left of ADC to HP Mixer */
+#define M_ADC_L_TO_HP_MIXER (0x1<<15)
+
+/* Mute left of ADC to MONO Mixer */
+#define M_ADC_L_TO_MONO_MIXER (0x1<<14)
+
+/* ADC Zero-Cross Detector Control */
+#define ADC_L_ZC_DET (0x1<<13)
+
+ /* ADC Record Gain Left channel Mask */
+#define ADC_L_GAIN_MASK (0x1f<<8)
+
+/* Mute right of ADC to HP Mixer */
+#define M_ADC_R_TO_HP_MIXER (0x1<<7)
+
+/* Mute right of ADC to MONO Mixer */
+#define M_ADC_R_TO_MONO_MIXER (0x1<<6)
+
+/* ADC Zero-Cross Detector Control */
+#define ADC_R_ZC_DET (0x1<<5)
+
+/* ADC Record Gain Right channel Mask */
+#define ADC_R_GAIN_MASK (0x1f<<0)
+
+/* Voice DAC Output Volume(0x18) */
+#define M_V_DAC_TO_HP_MIXER (0x1<<15)
+#define M_V_DAC_TO_SPK_MIXER (0x1<<14)
+#define M_V_DAC_TO_MONO_MIXER (0x1<<13)
+
+/* AEC & PDM Control(0x1A) */
+#define VODSP_SRC1_PWR (0x1<<15) /* Enable SRC1 Power */
+#define VODSP_SRC2_PWR (0x1<<13) /* Enable SRC2 Power */
+
+#define VODSP_SRC2_S_SEL_MASK (0x1<<12)
+
+/* SRC2 source select AEC_TXDP */
+#define VODSP_SRC2_S_SEL_TXDP (0x0<<12)
+
+/* SRC2 source select AEC_TXDC */
+#define VODSP_SRC2_S_SEL_TXDC (0x1<<12)
+
+/* Enable AEC RXDP Power */
+#define VODSP_RXDP_PWR (0x1<<11)
+
+#define VODSP_RXDP_S_SEL_MASK (0x3<<9)
+
+/* AEC RxDP source select SRC1 Output */
+#define VODSP_RXDP_S_SEL_SRC1 (0x0<<9)
+
+/* AEC RxDP source select ADC Left to AEC Digital Path */
+#define VODSP_RXDP_S_SEL_ADCL (0x1<<9)
+
+/* AEC RxDP source select Voice to Stereo Digital Path */
+#define VODSP_RXDP_S_SEL_VOICE (0x2<<9)
+
+/* AEC RxDP source select ADC Right to AEC Digital Path */
+#define VODSP_RXDP_S_SEL_ADCR (0x3<<9)
+
+/* Enable AEC RXDC Power */
+#define VODSP_RXDC_PWR (0x1<<8)
+
+#define VOICE_PCM_S_SEL_MASK (0x1<<7)
+
+/* VSADC PCM interface source select ADC R */
+#define VOICE_PCM_S_SEL_ADC_R (0x0<<7)
+
+/* VSADC PCM interface source select AEC_TXDP */
+#define VOICE_PCM_S_SEL_AEC_TXDP (0x1<<7)
+
+#define REC_S_SEL_MASK (0x3<<4)
+
+/* Main Stereo Record I2S source select ADC L/R */
+#define REC_S_SEL_ADC (0x0<<4)
+
+/* Main Stereo Record I2S source select Voice to Stereo Digital Path */
+#define REC_S_SEL_VOICE (0x1<<4)
+
+/* Main Stereo Record I2S source select SRC2 */
+#define REC_S_SEL_SRC2 (0x2<<4)
+
+/*Output Mixer Control(0x1C) */
+#define SPKOUT_N_SOUR_MASK (0x3<<14)
+#define SPKOUT_N_SOUR_LN (0x2<<14)
+#define SPKOUT_N_SOUR_RP (0x1<<14)
+#define SPKOUT_N_SOUR_RN (0x0<<14)
+
+#define SPKOUT_SEL_CLASS_D (0x1<<13)
+#define SPKOUT_SEL_CLASS_AB (0x0<<13)
+
+#define SPK_CLASS_AB_S_AMP (0x0<<12)
+#define SPK_CALSS_AB_W_AMP (0x1<<12)
+
+#define SPKOUT_INPUT_SEL_MASK (0x3<<10)
+#define SPKOUT_INPUT_SEL_MONOMIXER (0x3<<10)
+#define SPKOUT_INPUT_SEL_SPKMIXER (0x2<<10)
+#define SPKOUT_INPUT_SEL_HPMIXER (0x1<<10)
+#define SPKOUT_INPUT_SEL_VMID (0x0<<10)
+
+#define HPL_INPUT_SEL_HPLMIXER (0x1<<9)
+#define HPR_INPUT_SEL_HPRMIXER (0x1<<8)
+
+#define AUXOUT_INPUT_SEL_MASK (0x3<<6)
+#define AUXOUT_INPUT_SEL_MONOMIXER (0x3<<6)
+#define AUXOUT_INPUT_SEL_SPKMIXER (0x2<<6)
+#define AUXOUT_INPUT_SEL_HPMIXER (0x1<<6)
+#define AUXOUT_INPUT_SEL_VMID (0x0<<6)
+
+/* Voice DSP Control(0x1E) */
+#define VODSP_SYSCLK_S_SEL_MASK (0x1<<15)
+#define VODSP_SYSCLK_S_SEL_M_CLK (0x0<<15)
+#define VODSP_SYSCLK_S_SEL_V_CLK (0x1<<15)
+
+#define VODSP_LRCK_SEL_MASK (0x1<<13)
+#define VODSP_LRCK_SEL_8K (0x0<<13)
+#define VODSP_LRCK_SEL_16K (0x1<<13)
+#define VODSP_TEST_MODE_ENA (0x1<<3)
+#define VODSP_NO_BP_MODE_ENA (0x1<<2)
+#define VODSP_NO_PD_MODE_ENA (0x1<<1)
+#define VODSP_NO_RST_MODE_ENA (0x1<<0)
+
+/* Micphone Control define(0x22) */
+#define MIC1 1
+#define MIC2 2
+#define MIC_BIAS_90_PRECNET_AVDD 1
+#define MIC_BIAS_75_PRECNET_AVDD 2
+
+#define MIC1_BOOST_CONTROL_MASK (0x3<<10)
+#define MIC1_BOOST_CONTROL_BYPASS (0x0<<10)
+#define MIC1_BOOST_CONTROL_20DB (0x1<<10)
+#define MIC1_BOOST_CONTROL_30DB (0x2<<10)
+#define MIC1_BOOST_CONTROL_40DB (0x3<<10)
+
+#define MIC2_BOOST_CONTROL_MASK (0x3<<8)
+#define MIC2_BOOST_CONTROL_BYPASS (0x0<<8)
+#define MIC2_BOOST_CONTROL_20DB (0x1<<8)
+#define MIC2_BOOST_CONTROL_30DB (0x2<<8)
+#define MIC2_BOOST_CONTROL_40DB (0x3<<8)
+
+#define MIC1_BIAS_VOLT_CTRL_MASK (0x1<<5)
+#define MIC1_BIAS_VOLT_CTRL_90P (0x0<<5)
+#define MIC1_BIAS_VOLT_CTRL_75P (0x1<<5)
+
+#define MIC2_BIAS_VOLT_CTRL_MASK (0x1<<4)
+#define MIC2_BIAS_VOLT_CTRL_90P (0x0<<4)
+#define MIC2_BIAS_VOLT_CTRL_75P (0x1<<4)
+
+/* PowerDown control of register(0x26) */
+/* power management bits */
+/* write this bit to power down the Speaker Amplifier */
+#define ALC_PWR_PR7 (0x1<<15)
+
+/* write this bit to power down the Headphone Out and MonoOut */
+#define ALC_PWR_PR6 (0x1<<14)
+
+/* write this bit to power down the internal clock(without PLL) */
+#define ALC_PWR_PR5 (0x1<<13)
+
+/* write this bit to power down the mixer(vref/vrefout out off) */
+#define ALC_PWR_PR3 (0x1<<11)
+
+/* write this bit to power down the mixer(vref/vrefout still on) */
+#define ALC_PWR_PR2 (0x1<<10)
+
+/* write this bit to power down the dac */
+#define ALC_PWR_PR1 (0x1<<9)
+
+/* write this bit to power down the adc */
+#define ALC_PWR_PR0 (0x1<<8)
+
+
+#define ALC_PWR_REF (0x1<<3) /* read only */
+#define ALC_PWR_ANL (0x1<<2) /* read only */
+#define ALC_PWR_DAC (0x1<<1) /* read only */
+#define ALC_PWR_ADC (0x1) /* read only */
+
+/* Stereo DAC/Voice DAC/Stereo ADC function(0x2E) */
+#define DAC_FUNC_SEL_MASK (0x3<<12)
+#define DAC_FUNC_SEL_DAC (0x0<<12)
+#define DAC_FUNC_SEL_SRC2 (0x1<<12)
+#define DAC_FUNC_SEL_VODSP_TXDP (0x2<<12)
+#define DAC_FUNC_SEL_VODSP_TXDC (0x3<<12)
+
+#define VODAC_SOUR_SEL_MASK (0x7<<8)
+#define VODAC_SOUR_SEL_VOICE (0x0<<8)
+#define VODAC_SOUR_SEL_SRC2 (0x1<<8)
+#define VODAC_SOUR_SEL_VODSP_TXDP (0x2<<8)
+#define VODAC_SOUR_SEL_VODSP_TXDC (0x3<<8)
+
+#define ADCR_FUNC_SEL_MASK (0x3<<4)
+#define ADCR_FUNC_SEL_ADC (0x0<<4)
+#define ADCR_FUNC_SEL_VOADC (0x1<<4)
+#define ADCR_FUNC_SEL_VODSP (0x2<<4)
+#define ADCR_FUNC_SEL_PDM (0x3<<4)
+
+#define ADCL_FUNC_SEL_MASK (0x3<<0)
+#define ADCL_FUNC_SEL_ADC (0x0<<0)
+#define ADCL_FUNC_SEL_VODSP (0x1<<0)
+
+/*
+ * Main Serial Data Port Control(0x34)
+ * 0:Master mode 1:Slave mode
+ */
+#define MAIN_I2S_MODE_SEL (0x1<<15)
+
+/* 0:Disable,ADC and DAC use the same fs,1:Enable */
+#define MAIN_I2S_SADLRCK_CTRL (0x1<<14)
+
+/* 0:Normal SADLRCK/SDALRCK,1:Invert SADLRCK/SDALRCK */
+#define MAIN_I2S_PCM_MODE (0x1<<6)
+
+/* Data Length Selection */
+/* main i2s Data Length mask */
+#define MAIN_I2S_DL_MASK (0x3<<2)
+#define MAIN_I2S_DL_16 (0x0<<2) /* 16 bits */
+#define MAIN_I2S_DL_20 (0x1<<2) /* 20 bits */
+#define MAIN_I2S_DL_24 (0x2<<2) /* 24 bits */
+#define MAIN_I2S_DL_32 (0x3<<2) /* 8 bits */
+
+/* PCM Data Format Selection */
+/* main i2s Data Format mask */
+#define MAIN_I2S_DF_MASK (0x3)
+
+/* I2S FORMAT */
+#define MAIN_I2S_DF_I2S (0x0)
+
+/* LEFT JUSTIFIED format */
+#define MAIN_I2S_DF_LEFT (0x1)
+
+/* PCM Mode A */
+#define MAIN_I2S_DF_PCM_A (0x2)
+
+/* PCM Mode B */
+#define MAIN_I2S_DF_PCM_B (0x3)
+
+/*
+ * Extend Serial Data Port Control(0x36)
+ * Enable PCM interface on GPIO 1,3,4,5
+ * 0:GPIO function,
+ * 1:Voice PCM interface
+ */
+#define EXT_I2S_FUNC_ENABLE (0x1<<15)
+
+/* 0:Master, 1:Slave */
+#define EXT_I2S_MODE_SEL (0x1<<14)
+
+/* 0:Disable, 1:Enable */
+#define EXT_I2S_AUTO_CLK_CTRL (0x1<<13)
+
+/* 0:Normal 1:Invert */
+#define EXT_I2S_BCLK_POLARITY (0x1<<7)
+
+/* 0:Normal VSLRCK,1:Invert VSLRCK */
+#define EXT_I2S_PCM_MODE (0x1<<6)
+/* Data Length Slection */
+/* Extend i2s Data Length mask */
+#define EXT_I2S_DL_MASK (0x3<<2)
+#define EXT_I2S_DL_32 (0x3<<2) /* 8 bits */
+#define EXT_I2S_DL_24 (0x2<<2) /* 24 bits */
+#define EXT_I2S_DL_20 (0x1<<2) /* 20 bits */
+#define EXT_I2S_DL_16 (0x0<<2) /* 16 bits */
+
+/* Voice Data Format */
+/* Extend i2s Data Format mask */
+#define EXT_I2S_DF_MASK (0x3)
+
+/* I2S FORMAT */
+#define EXT_I2S_DF_I2S (0x0)
+
+/* LEFT JUSTIFIED format */
+#define EXT_I2S_DF_LEFT (0x1)
+
+/* PCM Mode A */
+#define EXT_I2S_DF_PCM_A (0x2)
+
+/* PCM Mode B */
+#define EXT_I2S_DF_PCM_B (0x3)
+
+/* Power managment addition 1 (0x3A),0:Disable,1:Enable */
+#define PWR_DAC_DF2SE_L (0x1<<15)
+#define PWR_DAC_DF2SE_R (0x1<<14)
+#define PWR_ZC_DET_PD (0x1<<13)
+#define PWR_I2S_INTERFACE (0x1<<11)
+#define PWR_AMP_POWER (0x1<<10)
+#define PWR_HP_OUT_AMP (0x1<<9)
+#define PWR_HP_OUT_ENH_AMP (0x1<<8)
+#define PWR_VOICE_DF2SE (0x1<<7)
+#define PWR_SOFTGEN_EN (0x1<<6)
+#define PWR_MIC_BIAS1_DET (0x1<<5)
+#define PWR_MIC_BIAS2_DET (0x1<<4)
+#define PWR_MIC_BIAS1 (0x1<<3)
+#define PWR_MIC_BIAS2 (0x1<<2)
+#define PWR_MAIN_BIAS (0x1<<1)
+#define PWR_DAC_REF (0x1)
+
+/* Power managment addition 2(0x3C),0:Disable,1:Enable */
+#define PWR_PLL1 (0x1<<15)
+#define PWR_PLL2 (0x1<<14)
+#define PWR_MIXER_VREF (0x1<<13)
+#define PWR_TEMP_SENSOR (0x1<<12)
+#define PWR_AUX_ADC (0x1<<11)
+#define PWR_VOICE_CLOCK (0x1<<10)
+#define PWR_L_DAC_CLK (0x1<<9)
+#define PWR_R_DAC_CLK (0x1<<8)
+#define PWR_L_ADC_CLK (0x1<<7)
+#define PWR_R_ADC_CLK (0x1<<6)
+#define PWR_L_HP_MIXER (0x1<<5)
+#define PWR_R_HP_MIXER (0x1<<4)
+#define PWR_SPK_MIXER (0x1<<3)
+#define PWR_MONO_MIXER (0x1<<2)
+#define PWR_L_ADC_REC_MIXER (0x1<<1)
+#define PWR_R_ADC_REC_MIXER (0x1)
+
+/* Power managment addition 3(0x3E),0:Disable,1:Enable */
+#define PWR_OSC_EN (0x1<<15)
+#define PWR_AUXOUT_VOL (0x1<<14)
+#define PWR_SPK_OUT (0x1<<13)
+#define PWR_SPK_OUT_N (0x1<<12)
+#define PWR_HP_L_OUT_VOL (0x1<<11)
+#define PWR_HP_R_OUT_VOL (0x1<<10)
+#define PWR_VODSP_INTERFACE (0x1<<9)
+#define PWR_I2C_FOR_VODSP (0x1<<8)
+#define PWR_LINE_IN_L (0x1<<7)
+#define PWR_LINE_IN_R (0x1<<6)
+#define PWR_PHONE_VOL (0x1<<5)
+#define PWR_PHONE_ADMIXER (0x1<<4)
+#define PWR_MIC1_VOL_CTRL (0x1<<3)
+#define PWR_MIC2_VOL_CTRL (0x1<<2)
+#define PWR_MIC1_BOOST (0x1<<1)
+#define PWR_MIC2_BOOST (0x1)
+
+/* General Purpose Control Register 1(0x40) */
+#define GP_CLK_FROM_PLL (0x1<<15)
+#define GP_CLK_FROM_MCLK (0x0<<15)
+
+/* Enable DAC High Pass Filter */
+#define GP_DAC_HI_PA_ENA (0x1<<10)
+
+#define GP_EXTCLK_S_SEL_PLL2 (0x1<<6)
+#define GP_EXTCLK_S_SEL_PLL1 (0x0<<6)
+
+#define GP_EXTCLK_DIR_SEL_OUTPUT (0x1<<5)
+#define GP_EXTCLK_DIR_SEL_INTPUT (0x0<<5)
+
+#define GP_VOSYS_S_SEL_PLL2 (0x0<<4)
+#define GP_VOSYS_S_SEL_EXTCLK (0x1<<4)
+
+#define GP_SPK_AMP_CTRL_MASK (0x7<<1)
+#define GP_SPK_AMP_CTRL_RATIO_225 (0x0<<1) /* 2.25 Vdd */
+#define GP_SPK_AMP_CTRL_RATIO_200 (0x1<<1) /* 2.00 Vdd */
+#define GP_SPK_AMP_CTRL_RATIO_175 (0x2<<1) /* 1.75 Vdd */
+#define GP_SPK_AMP_CTRL_RATIO_150 (0x3<<1) /* 1.50 Vdd */
+#define GP_SPK_AMP_CTRL_RATIO_125 (0x4<<1) /* 1.25 Vdd */
+#define GP_SPK_AMP_CTRL_RATIO_100 (0x5<<1) /* 1.00 Vdd */
+
+/* General Purpose Control Register 2(0x42) */
+#define GP2_PLL1_SOUR_SEL_MASK (0x3<<12)
+#define GP2_PLL1_SOUR_SEL_MCLK (0x0<<12)
+#define GP2_PLL1_SOUR_SEL_BCLK (0x2<<12)
+#define GP2_PLL1_SOUR_SEL_VBCLK (0x3<<12)
+
+/* PLL Control(0x44) */
+#define PLL_M_CODE_MASK 0xF /* PLL M code mask */
+#define PLL_K_CODE_MASK (0x7<<4) /* PLL K code mask */
+#define PLL_BYPASS_N (0x1<<7) /* bypass PLL N code */
+#define PLL_N_CODE_MASK (0xFF<<8) /* PLL N code mask */
+
+#define PLL_CTRL_M_VAL(m) ((m)&0xf)
+#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4)
+#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8)
+
+/* PLL2 CONTROL */
+#define PLL2_ENA (0x1<<15)
+#define PLL_2_RATIO_8X (0x0)
+#define PLL_2_RATIO_16X (0x1)
+
+/* LDO Control(0x48) */
+#define LDO_ENABLE (0x1<<15)
+
+#define LDO_OUT_VOL_CTRL_MASK (0xf<<0)
+#define LDO_OUT_VOL_CTRL_1_55V (0xf<<0)
+#define LDO_OUT_VOL_CTRL_1_50V (0xe<<0)
+#define LDO_OUT_VOL_CTRL_1_45V (0xd<<0)
+#define LDO_OUT_VOL_CTRL_1_40V (0xc<<0)
+#define LDO_OUT_VOL_CTRL_1_35V (0xb<<0)
+#define LDO_OUT_VOL_CTRL_1_30V (0xa<<0)
+#define LDO_OUT_VOL_CTRL_1_25V (0x9<<0)
+#define LDO_OUT_VOL_CTRL_1_20V (0x8<<0)
+#define LDO_OUT_VOL_CTRL_1_15V (0x7<<0)
+#define LDO_OUT_VOL_CTRL_1_05V (0x6<<0)
+#define LDO_OUT_VOL_CTRL_1_00V (0x5<<0)
+#define LDO_OUT_VOL_CTRL_0_95V (0x4<<0)
+#define LDO_OUT_VOL_CTRL_0_90V (0x3<<0)
+#define LDO_OUT_VOL_CTRL_0_85V (0x2<<0)
+#define LDO_OUT_VOL_CTRL_0_80V (0x1<<0)
+#define LDO_OUT_VOL_CTRL_0_75V (0x0<<0)
+
+/* GPIO Pin Configuration(0x4C) */
+#define GPIO_1 (0x1<<1)
+#define GPIO_2 (0x1<<2)
+#define GPIO_3 (0x1<<3)
+#define GPIO_4 (0x1<<4)
+#define GPIO_5 (0x1<<5)
+
+/* INTERRUPT CONTROL(0x5E) */
+#define DISABLE_FAST_VREG (0x1<<15)
+
+#define AVC_TARTGET_SEL_MASK (0x3<<12)
+#define AVC_TARTGET_SEL_NONE (0x0<<12)
+#define AVC_TARTGET_SEL_R (0x1<<12)
+#define AVC_TARTGET_SEL_L (0x2<<12)
+#define AVC_TARTGET_SEL_BOTH (0x3<<12)
+
+#define HP_DEPOP_MODE2_EN (0x1<<8)
+#define HP_DEPOP_MODE1_EN (0x1<<9)
+#define HP_L_M_UM_DEPOP_EN (0x1<<7)
+#define HP_R_M_UM_DEPOP_EN (0x1<<6)
+#define M_UM_DEPOP_EN (0x1<<5)
+
+/* Stereo DAC Clock Control 1(0x60) */
+#define STEREO_BCLK_DIV1_MASK (0xF<<12)
+#define STEREO_BCLK_DIV1_1 (0x0<<12)
+#define STEREO_BCLK_DIV1_2 (0x1<<12)
+#define STEREO_BCLK_DIV1_3 (0x2<<12)
+#define STEREO_BCLK_DIV1_4 (0x3<<12)
+#define STEREO_BCLK_DIV1_5 (0x4<<12)
+#define STEREO_BCLK_DIV1_6 (0x5<<12)
+#define STEREO_BCLK_DIV1_7 (0x6<<12)
+#define STEREO_BCLK_DIV1_8 (0x7<<12)
+#define STEREO_BCLK_DIV1_9 (0x8<<12)
+#define STEREO_BCLK_DIV1_10 (0x9<<12)
+#define STEREO_BCLK_DIV1_11 (0xA<<12)
+#define STEREO_BCLK_DIV1_12 (0xB<<12)
+#define STEREO_BCLK_DIV1_13 (0xC<<12)
+#define STEREO_BCLK_DIV1_14 (0xD<<12)
+#define STEREO_BCLK_DIV1_15 (0xE<<12)
+#define STEREO_BCLK_DIV1_16 (0xF<<12)
+
+#define STEREO_BCLK_DIV2_MASK (0x7<<8)
+#define STEREO_BCLK_DIV2_2 (0x0<<8)
+#define STEREO_BCLK_DIV2_4 (0x1<<8)
+#define STEREO_BCLK_DIV2_8 (0x2<<8)
+#define STEREO_BCLK_DIV2_16 (0x3<<8)
+#define STEREO_BCLK_DIV2_32 (0x4<<8)
+
+#define STEREO_AD_LRCK_DIV1_MASK (0xF<<4)
+#define STEREO_AD_LRCK_DIV1_1 (0x0<<4)
+#define STEREO_AD_LRCK_DIV1_2 (0x1<<4)
+#define STEREO_AD_LRCK_DIV1_3 (0x2<<4)
+#define STEREO_AD_LRCK_DIV1_4 (0x3<<4)
+#define STEREO_AD_LRCK_DIV1_5 (0x4<<4)
+#define STEREO_AD_LRCK_DIV1_6 (0x5<<4)
+#define STEREO_AD_LRCK_DIV1_7 (0x6<<4)
+#define STEREO_AD_LRCK_DIV1_8 (0x7<<4)
+#define STEREO_AD_LRCK_DIV1_9 (0x8<<4)
+#define STEREO_AD_LRCK_DIV1_10 (0x9<<4)
+#define STEREO_AD_LRCK_DIV1_11 (0xA<<4)
+#define STEREO_AD_LRCK_DIV1_12 (0xB<<4)
+#define STEREO_AD_LRCK_DIV1_13 (0xC<<4)
+#define STEREO_AD_LRCK_DIV1_14 (0xD<<4)
+#define STEREO_AD_LRCK_DIV1_15 (0xE<<4)
+#define STEREO_AD_LRCK_DIV1_16 (0xF<<4)
+
+#define STEREO_AD_LRCK_DIV2_MASK (0x7<<1)
+#define STEREO_AD_LRCK_DIV2_2 (0x0<<1)
+#define STEREO_AD_LRCK_DIV2_4 (0x1<<1)
+#define STEREO_AD_LRCK_DIV2_8 (0x2<<1)
+#define STEREO_AD_LRCK_DIV2_16 (0x3<<1)
+#define STEREO_AD_LRCK_DIV2_32 (0x4<<1)
+
+#define STEREO_DA_LRCK_DIV_MASK (1)
+#define STEREO_DA_LRCK_DIV_32 (0)
+#define STEREO_DA_LRCK_DIV_64 (1)
+
+/* Stereo DAC Clock Control 2(0x62) */
+#define STEREO_DA_FILTER_DIV1_MASK (0xF<<12)
+#define STEREO_DA_FILTER_DIV1_1 (0x0<<12)
+#define STEREO_DA_FILTER_DIV1_2 (0x1<<12)
+#define STEREO_DA_FILTER_DIV1_3 (0x2<<12)
+#define STEREO_DA_FILTER_DIV1_4 (0x3<<12)
+#define STEREO_DA_FILTER_DIV1_5 (0x4<<12)
+#define STEREO_DA_FILTER_DIV1_6 (0x5<<12)
+#define STEREO_DA_FILTER_DIV1_7 (0x6<<12)
+#define STEREO_DA_FILTER_DIV1_8 (0x7<<12)
+#define STEREO_DA_FILTER_DIV1_9 (0x8<<12)
+#define STEREO_DA_FILTER_DIV1_10 (0x9<<12)
+#define STEREO_DA_FILTER_DIV1_11 (0xA<<12)
+#define STEREO_DA_FILTER_DIV1_12 (0xB<<12)
+#define STEREO_DA_FILTER_DIV1_13 (0xC<<12)
+#define STEREO_DA_FILTER_DIV1_14 (0xD<<12)
+#define STEREO_DA_FILTER_DIV1_15 (0xE<<12)
+#define STEREO_DA_FILTER_DIV1_16 (0xF<<12)
+
+#define STEREO_DA_FILTER_DIV2_MASK (0x7<<9)
+#define STEREO_DA_FILTER_DIV2_2 (0x0<<9)
+#define STEREO_DA_FILTER_DIV2_4 (0x1<<9)
+#define STEREO_DA_FILTER_DIV2_8 (0x2<<9)
+#define STEREO_DA_FILTER_DIV2_16 (0x3<<9)
+#define STEREO_DA_FILTER_DIV2_32 (0x4<<9)
+
+#define STEREO_AD_FILTER_DIV1_MASK (0xF<<4)
+#define STEREO_AD_FILTER_DIV1_1 (0x0<<4)
+#define STEREO_AD_FILTER_DIV1_2 (0x1<<4)
+#define STEREO_AD_FILTER_DIV1_3 (0x2<<4)
+#define STEREO_AD_FILTER_DIV1_4 (0x3<<4)
+#define STEREO_AD_FILTER_DIV1_5 (0x4<<4)
+#define STEREO_AD_FILTER_DIV1_6 (0x5<<4)
+#define STEREO_AD_FILTER_DIV1_7 (0x6<<4)
+#define STEREO_AD_FILTER_DIV1_8 (0x7<<4)
+#define STEREO_AD_FILTER_DIV1_9 (0x8<<4)
+#define STEREO_AD_FILTER_DIV1_10 (0x9<<4)
+#define STEREO_AD_FILTER_DIV1_11 (0xA<<4)
+#define STEREO_AD_FILTER_DIV1_12 (0xB<<4)
+#define STEREO_AD_FILTER_DIV1_13 (0xC<<4)
+#define STEREO_AD_FILTER_DIV1_14 (0xD<<4)
+#define STEREO_AD_FILTER_DIV1_15 (0xE<<4)
+#define STEREO_AD_FILTER_DIV1_16 (0xF<<4)
+
+#define STEREO_AD_FILTER_DIV2_MASK (0x7<<1)
+#define STEREO_AD_FILTER_DIV2_1 (0x0<<1)
+#define STEREO_AD_FILTER_DIV2_2 (0x1<<1)
+#define STEREO_AD_FILTER_DIV2_4 (0x2<<1)
+#define STEREO_AD_FILTER_DIV2_8 (0x3<<1)
+#define STEREO_AD_FILTER_DIV2_16 (0x4<<1)
+#define STEREO_AD_FILTER_DIV2_32 (0x5<<1)
+
+/* Voice DAC PCM Clock Control 1(0x64) */
+#define VOICE_BCLK_DIV1_MASK (0xF<<12)
+#define VOICE_BCLK_DIV1_1 (0x0<<12)
+#define VOICE_BCLK_DIV1_2 (0x1<<12)
+#define VOICE_BCLK_DIV1_3 (0x2<<12)
+#define VOICE_BCLK_DIV1_4 (0x3<<12)
+#define VOICE_BCLK_DIV1_5 (0x4<<12)
+#define VOICE_BCLK_DIV1_6 (0x5<<12)
+#define VOICE_BCLK_DIV1_7 (0x6<<12)
+#define VOICE_BCLK_DIV1_8 (0x7<<12)
+#define VOICE_BCLK_DIV1_9 (0x8<<12)
+#define VOICE_BCLK_DIV1_10 (0x9<<12)
+#define VOICE_BCLK_DIV1_11 (0xA<<12)
+#define VOICE_BCLK_DIV1_12 (0xB<<12)
+#define VOICE_BCLK_DIV1_13 (0xC<<12)
+#define VOICE_BCLK_DIV1_14 (0xD<<12)
+#define VOICE_BCLK_DIV1_15 (0xE<<12)
+#define VOICE_BCLK_DIV1_16 (0xF<<12)
+
+#define VOICE_BCLK_DIV2_MASK (0x7<<8)
+#define VOICE_BCLK_DIV2_2 (0x0<<8)
+#define VOICE_BCLK_DIV2_4 (0x1<<8)
+#define VOICE_BCLK_DIV2_8 (0x2<<8)
+#define VOICE_BCLK_DIV2_16 (0x3<<8)
+#define VOICE_BCLK_DIV2_32 (0x4<<8)
+
+#define VOICE_AD_LRCK_DIV1_MASK (0xF<<4)
+#define VOICE_AD_LRCK_DIV1_1 (0x0<<4)
+#define VOICE_AD_LRCK_DIV1_2 (0x1<<4)
+#define VOICE_AD_LRCK_DIV1_3 (0x2<<4)
+#define VOICE_AD_LRCK_DIV1_4 (0x3<<4)
+#define VOICE_AD_LRCK_DIV1_5 (0x4<<4)
+#define VOICE_AD_LRCK_DIV1_6 (0x5<<4)
+#define VOICE_AD_LRCK_DIV1_7 (0x6<<4)
+#define VOICE_AD_LRCK_DIV1_8 (0x7<<4)
+#define VOICE_AD_LRCK_DIV1_9 (0x8<<4)
+#define VOICE_AD_LRCK_DIV1_10 (0x9<<4)
+#define VOICE_AD_LRCK_DIV1_11 (0xA<<4)
+#define VOICE_AD_LRCK_DIV1_12 (0xB<<4)
+#define VOICE_AD_LRCK_DIV1_13 (0xC<<4)
+#define VOICE_AD_LRCK_DIV1_14 (0xD<<4)
+#define VOICE_AD_LRCK_DIV1_15 (0xE<<4)
+#define VOICE_AD_LRCK_DIV1_16 (0xF<<4)
+
+#define VOICE_AD_LRCK_DIV2_MASK (0x7<<1)
+#define VOICE_AD_LRCK_DIV2_2 (0x0<<1)
+#define VOICE_AD_LRCK_DIV2_4 (0x1<<1)
+#define VOICE_AD_LRCK_DIV2_8 (0x2<<1)
+#define VOICE_AD_LRCK_DIV2_16 (0x3<<1)
+#define VOICE_AD_LRCK_DIV2_32 (0x4<<1)
+
+#define VOICE_DA_LRCK_DIV_MASK (1)
+#define VOICE_DA_LRCK_DIV_32 (0)
+#define VOICE_DA_LRCK_DIV_64 (1)
+
+
+/* Psedueo Stereo & Spatial Effect Block Control(0x68) */
+#define SPATIAL_CTRL_EN (0x1<<15)
+#define ALL_PASS_FILTER_EN (0x1<<14)
+#define PSEUDO_STEREO_EN (0x1<<13)
+#define STEREO_EXPENSION_EN (0x1<<12)
+
+#define SPATIAL_3D_GAIN1_MASK (0x3<<10)
+#define SPATIAL_3D_GAIN1_1_0 (0x0<<10)
+#define SPATIAL_3D_GAIN1_1_5 (0x1<<10)
+#define SPATIAL_3D_GAIN1_2_0 (0x2<<10)
+
+#define SPATIAL_3D_RATIO1_MASK (0x3<<8)
+#define SPATIAL_3D_RATIO1_0_0 (0x0<<8)
+#define SPATIAL_3D_RATIO1_0_66 (0x1<<8)
+#define SPATIAL_3D_RATIO1_1_0 (0x2<<8)
+
+#define SPATIAL_3D_GAIN2_MASK (0x3<<6)
+#define SPATIAL_3D_GAIN2_1_0 (0x0<<6)
+#define SPATIAL_3D_GAIN2_1_5 (0x1<<6)
+#define SPATIAL_3D_GAIN2_2_0 (0x2<<6)
+
+#define SPATIAL_3D_RATIO2_MASK (0x3<<4)
+#define SPATIAL_3D_RATIO2_0_0 (0x0<<4)
+#define SPATIAL_3D_RATIO2_0_66 (0x1<<4)
+#define SPATIAL_3D_RATIO2_1_0 (0x2<<4)
+
+#define APF_MASK (0x3)
+#define APF_FOR_48K (0x3)
+#define APF_FOR_44_1K (0x2)
+#define APF_FOR_32K (0x1)
+
+/* EQ Control and Status /ADC HPF Control(0x6E) */
+/* HW EQ block control */
+#define EN_HW_EQ_BLK (0x1<<15)
+
+#define EQ_SOUR_SEL_DAC (0x0<<14)
+#define EQ_SOUR_SEL_ADC (0x1<<14)
+
+/* EQ parameter update control */
+#define EQ_CHANGE_EN (0x1<<7)
+
+/* EQ High Pass Filter Control */
+#define EN_HW_EQ_HPF (0x1<<4)
+
+/* EQ Band-3 Control */
+#define EN_HW_EQ_BP3 (0x1<<3)
+
+/* EQ Band-2 Control */
+#define EN_HW_EQ_BP2 (0x1<<2)
+
+/* EQ Band-1 Control */
+#define EN_HW_EQ_BP1 (0x1<<1)
+
+/* EQ Low Pass Filter Control */
+#define EN_HW_EQ_LPF (0x1<<0)
+
+/* AEC register command(0x74) */
+/* VODSP I2C busy flag */
+#define VODSP_BUSY (0x1<<15)
+
+#define VODSP_S_FROM_VODSP_RD (0x0<<14)
+#define VODSP_S_FROM_MX72 (0x1<<14)
+
+/* VODSP CLK select Mask */
+#define VODSP_CLK_SEL_MASK (0x3<<12)
+
+/* VODSP CLK select 12.288Mhz */
+#define VODSP_CLK_SEL_12_288M (0x0<<12)
+
+/* VODSP CLK select 6.144Mhz */
+#define VODSP_CLK_SEL_6_144M (0x1<<12)
+
+/* VODSP CLK select 3.072Mhz */
+#define VODSP_CLK_SEL_3_072M (0x2<<12)
+
+/* VODSP CLK select 2.0488Mhz */
+#define VODSP_CLK_SEL_2_048M (0x3<<12)
+
+/* VODSP Read Enable */
+#define VODSP_READ_ENABLE (0x1<<9)
+
+/* VODSP Write Enable */
+#define VODSP_WRITE_ENABLE (0x1<<8)
+
+#define VODSP_CMD_MASK (0xFF<<0)
+#define VODSP_CMD_MW (0x3B<<0) /* Memory Write */
+#define VODSP_CMD_MR (0x37<<0) /* Memory Read */
+#define VODSP_CMD_RR (0x60<<0) /* Register Read */
+#define VODSP_CMD_RW (0x68<<0) /* Register Write */
+
+/*
+ * Index register of codec
+ * Index(0x20) for Auto Volume Control
+ */
+#define AVC_CH_SEL_MASK (0x1<<7)
+#define AVC_CH_SEL_L_CH (0x0<<7)
+#define AVC_CH_SEL_R_CH (0x1<<7)
+#define ENABLE_AVC_GAIN_CTRL (0x1<<15)
+
+#define DEFAULT_SYSCLK 24576000
+
+enum ALC5625_PLL_SEL {
+ ALC5625_PLL1_FROM_MCLK = 0,
+ ALC5625_PLL1_FROM_BCLK,
+ ALC5625_PLL1_FROM_VBCLK,
+};
+
+enum ALC5625_AEC_MODE {
+ PCM_IN_PCM_OUT = 0,
+ ANALOG_IN_ANALOG_OUT,
+ DAC_IN_ADC_OUT,
+ VODSP_AEC_DISABLE
+};
+
+enum ALC5625_PCM_MODE {
+ PCM_MASTER_MODE_A = 0,
+ PCM_MASTER_MODE_B,
+ PCM_SLAVE_MODE_A,
+ PCM_SLAVE_MODE_B,
+};
+
+enum ALC5625_FUNC_SEL {
+ ALC5625_AEC_DISABLE = 0,
+ ALC5625_AEC_PCM_IN_OUT,
+ ALC5625_AEC_IIS_IN_OUT,
+ ALC5625_AEC_ANALOG_IN_OUT,
+};
+
+struct alc5625_setup_data {
+ int i2c_bus;
+ int i2c_address;
+};
+
+struct voice_dsp_reg {
+ u16 index;
+ u16 val;
+};
+
+#endif
diff --git a/drivers/staging/alc5625/origen_alc5625.c b/drivers/staging/alc5625/origen_alc5625.c
new file mode 100644
index 00000000000..f2b6f3585a0
--- /dev/null
+++ b/drivers/staging/alc5625/origen_alc5625.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2011 Insignal Co., Ltd.
+ *
+ * Author: Pan <pan@insginal.co.kr>
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "../../../sound/soc/samsung/i2s.h"
+
+static int set_epll_rate(unsigned long rate)
+{
+ struct clk *fout_epll;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ printk(KERN_ERR "%s: failed to get fout_epll\n", __func__);
+ return -ENOENT;
+ }
+
+ if (rate == clk_get_rate(fout_epll))
+ goto out;
+
+ clk_set_rate(fout_epll, rate);
+out:
+ clk_put(fout_epll);
+
+ return 0;
+}
+
+static int origen_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int bfs, psr, rfs, ret;
+ unsigned long rclk;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U24:
+ case SNDRV_PCM_FORMAT_S24:
+ bfs = 48;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bfs = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_rate(params)) {
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ rfs = (bfs == 48) ? 384 : 256;
+ break;
+ case 64000:
+ rfs = 384;
+ break;
+ case 8000:
+ case 11025:
+ case 12000:
+ rfs = (bfs == 48) ? 768 : 512;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rclk = params_rate(params) * rfs;
+
+ switch (rclk) {
+ case 4096000:
+ case 5644800:
+ case 6144000:
+ case 8467200:
+ case 9216000:
+ psr = 8;
+ break;
+ case 8192000:
+ case 11289600:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ psr = 4;
+ break;
+ case 22579200:
+ case 24576000:
+ case 33868800:
+ case 36864000:
+ psr = 2;
+ break;
+ case 67737600:
+ case 73728000:
+ psr = 1;
+ break;
+ default:
+ printk(KERN_ERR "Not yet supported!\n");
+ return -EINVAL;
+ }
+
+ set_epll_rate(rclk * psr);
+
+ /* Set the Codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* Set the AP DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, rfs,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops origen_ops = {
+ .hw_params = origen_hw_params,
+};
+
+static int origen_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+ snd_soc_dapm_sync(dapm);
+
+ return 0;
+}
+
+static struct snd_soc_dai_link origen_dai[] = {
+ { /* Primary DAI i/f */
+ .name = "ALC5625 PAIF",
+ .stream_name = "Pri_Dai",
+ .cpu_dai_name = "samsung-i2s.0",
+ .codec_dai_name = "alc5625-aif1",
+ .platform_name = "samsung-audio",
+ .codec_name = "alc5625-codec.1-001e",
+ .init = origen_wm8994_init_paiftx,
+ .ops = &origen_ops,
+ },
+};
+
+static struct snd_soc_card snd_soc_origen_audio = {
+ .name = "ORIGEN-I2S",
+ .dai_link = origen_dai,
+ .num_links = ARRAY_SIZE(origen_dai),
+};
+
+static int __devinit origen_audio_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct snd_soc_card *card = &snd_soc_origen_audio;
+
+ card->dev = &pdev->dev;
+
+ ret = snd_soc_register_card(card);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+ ret);
+
+ return ret;
+}
+
+static int __devexit origen_audio_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static const struct of_device_id origen_audio_of_match[] = {
+ { .compatible = "samsung,origen_audio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, origen_audio_of_match);
+
+static struct platform_driver origen_audio_driver = {
+ .driver = {
+ .name = "origen-audio",
+ .owner = THIS_MODULE,
+ .of_match_table = origen_audio_of_match,
+ },
+ .probe = origen_audio_probe,
+ .remove = __devexit_p(origen_audio_remove),
+};
+
+static int __init origen_audio_init(void)
+{
+ return platform_driver_register(&origen_audio_driver);
+}
+late_initcall(origen_audio_init);
+
+static void __exit origen_audio_exit(void)
+{
+ platform_driver_unregister(&origen_audio_driver);
+}
+module_exit(origen_audio_exit);
+
+MODULE_AUTHOR("Pan, <pan@insignal.co.kr>");
+MODULE_DESCRIPTION("ALSA SoC ORIGEN+ALC5625");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:origen-audio");
diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c
index b179dbab93b..921e25ee911 100644
--- a/drivers/staging/bcm/nvm.c
+++ b/drivers/staging/bcm/nvm.c
@@ -577,7 +577,7 @@ static int FlashSectorErase(struct bcm_mini_adapter *Adapter,
* the sector erase cycle is 500 ms to 40000 msec. hence sleeping 10 ms
* won't hamper performance in any case.
*/
- udelay(10000);
+ mdelay(10);
} while ((uiStatus & 0x1) && (iRetries < 400));
if (uiStatus & 0x1) {