diff options
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/alc5625/Kconfig | 13 | ||||
-rw-r--r-- | drivers/staging/alc5625/Makefile | 3 | ||||
-rw-r--r-- | drivers/staging/alc5625/alc5625.c | 2276 | ||||
-rw-r--r-- | drivers/staging/alc5625/alc5625.h | 865 | ||||
-rw-r--r-- | drivers/staging/alc5625/origen_alc5625.c | 236 | ||||
-rw-r--r-- | drivers/staging/bcm/nvm.c | 2 |
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) ? ®80 : + ((reg == 0x82) ? ®82 : ®84)); + *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) { |