From b91d4cb1a9a03f0d4ed5e663b58a7e4709890768 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=AE=8B=E7=A7=80=E6=9D=B0?= Date: Tue, 6 Mar 2012 20:17:40 +0800 Subject: [PATCH] phonepad: modify codec rt5625 driver for kernel3.0 --- sound/soc/codecs/rt5625.c | 4428 +++++++++++++++++++--------------- sound/soc/codecs/rt5625.h | 1541 ++++++------ sound/soc/rk29/rk29_rt5625.c | 538 ++--- 3 files changed, 3562 insertions(+), 2945 deletions(-) diff --git a/sound/soc/codecs/rt5625.c b/sound/soc/codecs/rt5625.c index 129acc4c5d79..c2704cbbc508 100644 --- a/sound/soc/codecs/rt5625.c +++ b/sound/soc/codecs/rt5625.c @@ -1,14 +1,22 @@ +/* + * rt5625.c -- RT5625 ALSA SoC audio codec driver + * + * Copyright 2011 Realtek Semiconductor Corp. + * Author: Johnny Hsu + * + * 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 #include -#include #include #include #include #include #include #include -#include -#include #include #include #include @@ -16,149 +24,123 @@ #include #include #include -#include #include "rt5625.h" -#if REALTEK_HWDEP - -#include -#include - +#define RT5625_PROC +#ifdef RT5625_PROC +#include +#include +#include +char debug_write_read = 0; #endif -#if 0 +#if 1 #define DBG(x...) printk(KERN_INFO x) #else #define DBG(x...) do { } while (0) #endif -#define AUDIO_NAME "rt5625" -#define RT5625_VERSION "0.03 alsa 1.0.21" -#define ALSA_SOC_VERSION "1.0.21" +static struct snd_soc_codec *rt5625_codec; -#define RT5625_EQ_FUNC_ENA 0 +#define RT5625_REG_RW 1 /* for debug */ +//#define RT5625_DEMO 1 /* only for demo; please remove it */ -static void hp_depop_mode2(struct snd_soc_codec *codec); -static void hp_mute_unmute_depop(struct snd_soc_codec *codec,int mute); +#define RT5625_F_SMT_PHO +#define RT5625_PLY_BIT 0 +#define RT5625_PLY_MASK (0x1) +#define RT5625_REC_BIT 1 +#define RT5625_REC_MASK (0x1 << RT5625_REC_BIT) +#define RT5625_3G_BIT 2 +#define RT5625_3G_MASK (0x1 << RT5625_3G_BIT) +#define RT5625_BT_BIT 3 +#define RT5625_BT_MASK (0x1 << RT5625_BT_BIT) +#define RT5625_VOIP_BIT 4 +#define RT5625_VOIP_MASK (0x1 << RT5625_VOIP_BIT) struct rt5625_priv { unsigned int stereo_sysclk; unsigned int voice_sysclk; -}; -struct rt5625_init_reg { - u8 reg_index; - u16 reg_value; + int vodsp_fun; +#ifdef RT5625_F_SMT_PHO + int app_bmp;/* bit{0, 1, 2, 3, 4} = {play, rec, 3g, bt, voip} */ + int pll_sel; + int pll2_sel; + int dac_active; + int adc_active; + int headset; + int vodsp_fun_bak; +#endif }; -static struct rt5625_init_reg rt5625_init_list[] = { - - {RT5625_HP_OUT_VOL , 0x8888}, //default is -12db - {RT5625_SPK_OUT_VOL , 0x8080}, //default is 0db - {RT5625_DAC_AND_MIC_CTRL , 0xee03}, //DAC to hpmixer - {RT5625_OUTPUT_MIXER_CTRL , 0x0748}, //all output from hpmixer - {RT5625_MIC_CTRL , 0x0500}, //mic boost 20db - {RT5625_ADC_REC_MIXER , 0x3f3f}, //record source from mic1 - {RT5625_GEN_CTRL_REG1 , 0x0c0a}, //speaker vdd ratio is 1 - {RT5625_ADC_REC_GAIN , 0xd5d5}, //gain 15db of ADC by default - +#ifdef RT5625_F_SMT_PHO +static u16 rt5625_voip_back[][2] = { + {RT5625_VODSP_PDM_CTL, 0x0000}, + {RT5625_F_DAC_ADC_VDAC, 0x0000}, }; +#define RT5625_VOIP_BK_NUM \ + (sizeof(rt5625_voip_back) / sizeof(rt5625_voip_back[0])) +#endif -#define RT5625_INIT_REG_NUM ARRAY_SIZE(rt5625_init_list) - -#if (RT5625_EQ_FUNC_ENA==1) -//************************************************************************************************* -//eq table -//************************************************************************************************* -enum -{ - NORMAL=0, - CLUB, - DANCE, - LIVE, - POP, - ROCK, - OPPO, - TREBLE, - BASS +#ifdef RT5625_DEMO +struct rt5625_init_reg { + u8 reg; + u16 val; }; -typedef struct _HW_EQ_PRESET -{ - u16 HwEqType; - u16 EqValue[14]; - u16 HwEQCtrl; - -}HW_EQ_PRESET; - - -HW_EQ_PRESET HwEq_Preset[]={ -/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0x6e*/ - {NORMAL,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x0000}, - {CLUB ,{0x1C10,0x0000,0xC1CC,0x1E5D,0x0699,0xCD48,0x188D,0x0699,0xC3B6,0x1CD0,0x0699,0x0436,0x0000},0x800E}, - {DANCE ,{0x1F2C,0x095B,0xC071,0x1F95,0x0616,0xC96E,0x1B11,0xFC91,0xDCF2,0x1194,0xFAF2,0x0436,0x0000},0x800F}, - {LIVE ,{0x1EB5,0xFCB6,0xC24A,0x1DF8,0x0E7C,0xC883,0x1C10,0x0699,0xDA41,0x1561,0x0295,0x0436,0x0000},0x800F}, - {POP ,{0x1EB5,0xFCB6,0xC1D4,0x1E5D,0x0E23,0xD92E,0x16E6,0xFCB6,0x0000,0x0969,0xF988,0x0436,0x0000},0x800F}, - {ROCK ,{0x1EB5,0xFCB6,0xC071,0x1F95,0x0424,0xC30A,0x1D27,0xF900,0x0C5D,0x0FC7,0x0E23,0x0436,0x0000},0x800F}, - {OPPO ,{0x0000,0x0000,0xCA4A,0x17F8,0x0FEC,0xCA4A,0x17F8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x800F}, - {TREBLE,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x188D,0x1699},0x8010}, - {BASS ,{0x1A43,0x0C00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x8001}, - +static struct rt5625_init_reg init_list[] = { + {RT5625_HP_OUT_VOL , 0x8888}, //default is -12db + {RT5625_SPK_OUT_VOL , 0x8080}, //default is 0db + {RT5625_PHONEIN_VOL , 0xe800}, //phone differential + {RT5625_DAC_MIC_CTRL , 0xee01}, //DAC to hpmixer & spkmixer + {RT5625_OUTMIX_CTRL , 0x2bc8}, //spk from spkmixer; hp from hpmixer; aux from monomixer; classAB + {RT5625_ADC_REC_MIXER , 0x1f1f}, //record source from mic1 & mic2 + {RT5625_GEN_CTRL1 , 0x0c08}, //speaker vdd ratio is 1; 1.25VDD ratio }; +#define RT5625_INIT_REG_LEN ARRAY_SIZE(init_list) +static int rt5625_reg_init(struct snd_soc_codec *codec) +{ + int i; + for (i = 0; i < RT5625_INIT_REG_LEN; i++) + snd_soc_write(codec, init_list[i].reg, init_list[i].val); + return 0; +} #endif -//************************************************************************************************* -//************************************************************************************************* - -/* - * 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 = 0, reg82 = 0; -/* - * 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 - * bit[12~15] for eq function - */ - #define VIRTUAL_REG_FOR_MISC_FUNC 0x84 -static unsigned int reg84 = 0; - - -static const u16 rt5625_reg[] = { - 0x59b4, 0x8080, 0x8080, 0x8080, /*reg00-reg06*/ - 0xc800, 0xe808, 0x1010, 0x0808, /*reg08-reg0e*/ - 0xe0ef, 0xcbcb, 0x7f7f, 0x0000, /*reg10-reg16*/ - 0xe010, 0x0000, 0x8008, 0x2007, /*reg18-reg1e*/ - 0x0000, 0x0000, 0x00c0, 0xef00, /*reg20-reg26*/ - 0x0000, 0x0000, 0x0000, 0x0000, /*reg28-reg2e*/ - 0x0000, 0x0000, 0x0000, 0x0000, /*reg30-reg36*/ - 0x0000, 0x0000, 0x0000, 0x0000, /*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*/ +static const u16 rt5625_reg[0x80] = { + [RT5625_RESET] = 0x59b4, + [RT5625_SPK_OUT_VOL] = 0x8080, + [RT5625_HP_OUT_VOL] = 0x8080, + [RT5625_AUX_OUT_VOL] = 0x8080, + [RT5625_PHONEIN_VOL] = 0xc800, + [RT5625_LINE_IN_VOL] = 0xe808, + [RT5625_DAC_VOL] = 0x1010, + [RT5625_MIC_VOL] = 0x0808, + [RT5625_DAC_MIC_CTRL] = 0xee0f, + [RT5625_ADC_REC_GAIN] = 0xcbcb, + [RT5625_ADC_REC_MIXER] = 0x7f7f, + [RT5625_VDAC_OUT_VOL] = 0xe010, + [RT5625_OUTMIX_CTRL] = 0x8008, + [RT5625_VODSP_CTL] = 0x2007, + [RT5625_DMIC_CTRL] = 0x00c0, + [RT5625_PD_CTRL] = 0xef00, + [RT5625_GEN_CTRL1] = 0x0c0a, + [RT5625_LDO_CTRL] = 0x0029, + [RT5625_GPIO_CONFIG] = 0xbe3e, + [RT5625_GPIO_POLAR] = 0x3e3e, + [RT5625_GPIO_STATUS] = 0x803a, + [RT5625_SOFT_VOL_CTRL] = 0x0009, + [RT5625_DAC_CLK_CTRL1] = 0x3075, + [RT5625_DAC_CLK_CTRL2] = 0x1010, + [RT5625_VDAC_CLK_CTRL1] = 0x3110, + [RT5625_PS_CTRL] = 0x0553, + [RT5625_VENDOR_ID1] = 0x10ec, + [RT5625_VENDOR_ID2] = 0x5c02, }; - -Voice_DSP_Reg VODSP_AEC_Init_Value[]= -{ +rt5625_dsp_reg rt5625_dsp_init[] = { {0x232C, 0x0025}, {0x230B, 0x0001}, {0x2308, 0x007F}, @@ -168,13 +150,13 @@ Voice_DSP_Reg VODSP_AEC_Init_Value[]= {0x2304, 0x00FA}, {0x2305, 0x0500}, {0x2306, 0x4000}, - {0x230D, 0x0900}, + {0x230D, 0x0300}, {0x230E, 0x0280}, {0x2312, 0x00B1}, {0x2314, 0xC000}, {0x2316, 0x0041}, - {0x2317, 0x2200}, - {0x2318, 0x0C00}, + {0x2317, 0x2800}, + {0x2318, 0x0800}, {0x231D, 0x0050}, {0x231F, 0x4000}, {0x2330, 0x0008}, @@ -193,1770 +175,2631 @@ Voice_DSP_Reg VODSP_AEC_Init_Value[]= {0x22D4, 0x2800}, {0x22D5, 0x3000}, {0x2399, 0x2800}, - {0x230C, 0x0000}, //to enable VODSP AEC function + {0x230C, 0x0000}, }; - - -#define SET_VODSP_REG_INIT_NUM ARRAY_SIZE(VODSP_AEC_Init_Value) -static struct snd_soc_device *rt5625_socdev; - -static inline unsigned int rt5625_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - - if (reg > 0x7e) +#define RT5625_DSP_INIT_NUM ARRAY_SIZE(rt5625_dsp_init) + +static int rt5625_volatile_register( + struct snd_soc_codec *codec, unsigned int reg) +{ + switch (reg) { + case RT5625_RESET: + case RT5625_PD_CTRL: + case RT5625_GPIO_STATUS: + case RT5625_OTC_STATUS: + case RT5625_PRIV_DATA: + case RT5625_EQ_CTRL: + case RT5625_DSP_DATA: + case RT5625_DSP_CMD: + case RT5625_VENDOR_ID1: + case RT5625_VENDOR_ID2: + return 1; + default: return 0; - return cache[reg / 2]; + } } - -static unsigned int rt5625_read_hw_reg(struct snd_soc_codec *codec, unsigned int reg) -{ - u8 data[2] = {0}; - unsigned int value = 0x0; - - data[0] = reg; - - i2c_master_reg8_recv(codec->control_data,reg,data,2,100 * 1000); - - value = (data[0]<<8) | data[1]; - - DBG(KERN_INFO "rt5625_read ok, reg = %x, value = %x\n", reg, value); - - return value; +static int rt5625_readable_register( + struct snd_soc_codec *codec, unsigned int reg) +{ + switch (reg) { + case RT5625_RESET: + case RT5625_SPK_OUT_VOL: + case RT5625_HP_OUT_VOL: + case RT5625_AUX_OUT_VOL: + case RT5625_PHONEIN_VOL: + case RT5625_LINE_IN_VOL: + case RT5625_DAC_VOL: + case RT5625_MIC_VOL: + case RT5625_DAC_MIC_CTRL: + case RT5625_ADC_REC_GAIN: + case RT5625_ADC_REC_MIXER: + case RT5625_VDAC_OUT_VOL: + case RT5625_VODSP_PDM_CTL: + case RT5625_OUTMIX_CTRL: + case RT5625_VODSP_CTL: + case RT5625_MIC_CTRL: + case RT5625_DMIC_CTRL: + case RT5625_PD_CTRL: + case RT5625_F_DAC_ADC_VDAC: + case RT5625_SDP_CTRL: + case RT5625_EXT_SDP_CTRL: + case RT5625_PWR_ADD1: + case RT5625_PWR_ADD2: + case RT5625_PWR_ADD3: + case RT5625_GEN_CTRL1: + case RT5625_GEN_CTRL2: + case RT5625_PLL_CTRL: + case RT5625_PLL2_CTRL: + case RT5625_LDO_CTRL: + case RT5625_GPIO_CONFIG: + case RT5625_GPIO_POLAR: + case RT5625_GPIO_STICKY: + case RT5625_GPIO_WAKEUP: + case RT5625_GPIO_STATUS: + case RT5625_GPIO_SHARING: + case RT5625_OTC_STATUS: + case RT5625_SOFT_VOL_CTRL: + case RT5625_GPIO_OUT_CTRL: + case RT5625_MISC_CTRL: + case RT5625_DAC_CLK_CTRL1: + case RT5625_DAC_CLK_CTRL2: + case RT5625_VDAC_CLK_CTRL1: + case RT5625_PS_CTRL: + case RT5625_PRIV_INDEX: + case RT5625_PRIV_DATA: + case RT5625_EQ_CTRL: + case RT5625_DSP_ADDR: + case RT5625_DSP_DATA: + case RT5625_DSP_CMD: + case RT5625_VENDOR_ID1: + case RT5625_VENDOR_ID2: + return 1; + default: + return 0; + } } - -static unsigned int rt5625_read(struct snd_soc_codec *codec, unsigned int reg) +static unsigned int rt5625_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 rt5625_read_hw_reg(codec, reg); -} + unsigned int val; - -static inline void rt5625_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; + val = codec->hw_read(codec, reg); + return val; } static int rt5625_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { + unsigned int val; u8 data[3]; - unsigned int *regvalue = NULL; data[0] = reg; - data[1] = (value & 0xff00) >> 8; - data[2] = value & 0x00ff; + data[1] = (value >> 8) & 0xff; + data[2] = value & 0xff; - if ((reg == 0x80) - || (reg == 0x82) - || (reg == 0x84)) - { - regvalue = ((reg == 0x80) ? ®80 : ((reg == 0x82) ? ®82 : ®84)); - *regvalue = value; - DBG("rt5625_write ok, reg = %x, value = %x\n", reg, value); - return 0; - } - rt5625_write_reg_cache(codec, reg, value); - - if (codec->hw_write(codec->control_data, data, 3) == 3) - { - DBG("rt5625_write ok, reg = %x, value = %x\n", reg, value); - return 0; - } - else - { - printk("rt5625_write fail\n"); - return -EIO; - } + val = codec->hw_write(codec->control_data, data, 3); + return val; } -int rt5625_write_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask) +static int rt5625_reset(struct snd_soc_codec *codec) { - - unsigned char RetVal=0; - unsigned int CodecData; - - DBG("rt5625_write_mask ok, reg = %x, value = %x ,mask= %x\n", reg, value,mask); + return snd_soc_write(codec, RT5625_RESET, 0); +} - if(!mask) - return 0; +/** + * rt5625_index_write - Write private register. + * @codec: SoC audio codec device. + * @reg: Private register index. + * @value: Private register Data. + * + * Modify private register for advanced setting. It can be written through + * private index (0x6a) and data (0x6c) register. + * + * Returns 0 for success or negative error code. + */ +static int rt5625_index_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + int ret; - if(mask!=0xffff) - { - CodecData=rt5625_read(codec,reg); - CodecData&=~mask; - CodecData|=(value&mask); - RetVal=rt5625_write(codec,reg,CodecData); - } - else - { - RetVal=rt5625_write(codec,reg,value); + ret = snd_soc_write(codec, RT5625_PRIV_INDEX, reg); + if (ret < 0) { + dev_err(codec->dev, "Failed to set private addr: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_PRIV_DATA, value); + if (ret < 0) { + dev_err(codec->dev, "Failed to set private value: %d\n", ret); + goto err; } + return 0; - return RetVal; +err: + return ret; } - -void rt5625_write_index(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) +/** + * rt5625_index_read - Read private register. + * @codec: SoC audio codec device. + * @reg: Private register index. + * + * Read advanced setting from private register. It can be read through + * private index (0x6a) and data (0x6c) register. + * + * Returns private register value or negative error code. + */ +static unsigned int rt5625_index_read( + struct snd_soc_codec *codec, unsigned int reg) { - - rt5625_write(codec,0x6a,reg); - rt5625_write(codec,0x6c,value); -} + int ret; -unsigned int rt5625_read_index(struct snd_soc_codec *codec, unsigned int reg) -{ - unsigned int value = 0x0; - rt5625_write(codec,0x6a,reg); - value=rt5625_read(codec,0x6c); - - return value; + ret = snd_soc_write(codec, RT5625_PRIV_INDEX, reg); + if (ret < 0) { + dev_err(codec->dev, "Failed to set private addr: %d\n", ret); + return ret; + } + return snd_soc_read(codec, RT5625_PRIV_DATA); } -void rt5625_write_index_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask) +/** + * rt5625_index_update_bits - update private register bits + * @codec: Audio codec + * @reg: Private register index. + * @mask: Register mask + * @value: New value + * + * Writes new register value. + * + * Returns 1 for change, 0 for no change, or negative error code. + */ +static int rt5625_index_update_bits(struct snd_soc_codec *codec, + unsigned int reg, unsigned int mask, unsigned int value) { - -// unsigned char RetVal=0; - unsigned int CodecData; - - DBG("rt5625_write_index_mask ok, reg = %x, value = %x ,mask= %x\n", reg, value,mask); + unsigned int old, new; + int change, ret; - if(!mask) - return; - - if(mask!=0xffff) - { - CodecData=rt5625_read_index(codec,reg); - CodecData&=~mask; - CodecData|=(value&mask); - rt5625_write_index(codec,reg,CodecData); - } - else - { - rt5625_write_index(codec,reg,value); + ret = rt5625_index_read(codec, reg); + if (ret < 0) { + dev_err(codec->dev, "Failed to read private reg: %d\n", ret); + goto err; } -} -//#define rt5625_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value) + old = ret; + new = (old & ~mask) | (value & mask); + change = old != new; + if (change) { + ret = rt5625_index_write(codec, reg, new); + if (ret < 0) { + dev_err(codec->dev, + "Failed to write private reg: %d\n", ret); + goto err; + } + } + return change; -#define rt5625_reset(c) rt5625_write(c, RT5625_RESET, 0) +err: + return ret; +} -/*read/write dsp reg*/ -static int rt5625_wait_vodsp_i2c_done(struct snd_soc_codec *codec) +/** + * rt5625_dsp_done - Wait until DSP is ready. + * @codec: SoC Audio Codec device. + * + * To check voice DSP status and confirm it's ready for next work. + * + * Returns 0 for success or negative error code. + */ +static int rt5625_dsp_done(struct snd_soc_codec *codec) { - unsigned int checkcount = 0, vodsp_data; + unsigned int count = 0, dsp_val; - vodsp_data = rt5625_read(codec, RT5625_VODSP_REG_CMD); - while(vodsp_data & VODSP_BUSY) - { - if(checkcount > 10) + dsp_val = snd_soc_read(codec, RT5625_DSP_CMD); + while(dsp_val & RT5625_DSP_BUSY_MASK) { + if(count > 10) return -EBUSY; - vodsp_data = rt5625_read(codec, RT5625_VODSP_REG_CMD); - checkcount ++; + dsp_val = snd_soc_read(codec, RT5625_DSP_CMD); + count ++; } + return 0; } -static int rt5625_write_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg, unsigned int value) +/** + * rt5625_dsp_write - Write DSP register. + * @codec: SoC audio codec device. + * @reg: DSP register index. + * @value: DSP register Data. + * + * Modify voice DSP register for sound effect. The DSP can be controlled + * through DSP addr (0x70), data (0x72) and cmd (0x74) register. It has + * to wait until the DSP is ready. + * + * Returns 0 for success or negative error code. + */ +static int rt5625_dsp_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) { - int ret = 0; - - if(ret != rt5625_wait_vodsp_i2c_done(codec)) - return -EBUSY; + int ret; - rt5625_write(codec, RT5625_VODSP_REG_ADDR, vodspreg); - rt5625_write(codec, RT5625_VODSP_REG_DATA, value); - rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_WRITE_ENABLE | VODSP_CMD_MW); + ret = rt5625_dsp_done(codec); + if (ret < 0) { + dev_err(codec->dev, "DSP is busy: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_ADDR, reg); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_DATA, value); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP data reg: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_CMD, + RT5625_DSP_W_EN | RT5625_DSP_CMD_MW); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret); + goto err; + } mdelay(10); - return ret; + return 0; +err: + return ret; } -static unsigned int rt5625_read_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg) +/** + * rt5625_dsp_read - Read DSP register. + * @codec: SoC audio codec device. + * @reg: DSP register index. + * + * Read DSP setting value from voice DSP. The DSP can be controlled + * through DSP addr (0x70), data (0x72) and cmd (0x74) register. Each + * command has to wait until the DSP is ready. + * + * Returns DSP register value or negative error code. + */ +static unsigned int rt5625_dsp_read( + struct snd_soc_codec *codec, unsigned int reg) { + unsigned int val_h, val_l; int ret = 0; - unsigned int nDataH, nDataL; - unsigned int value; - if(ret != rt5625_wait_vodsp_i2c_done(codec)) - return -EBUSY; - - rt5625_write(codec, RT5625_VODSP_REG_ADDR, vodspreg); - rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_MR); + ret = rt5625_dsp_done(codec); + if (ret < 0) { + dev_err(codec->dev, "DSP is busy: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_ADDR, reg); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_CMD, + RT5625_DSP_R_EN | RT5625_DSP_CMD_MR); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret); + goto err; + } + + /* Read DSP high byte data */ + ret = rt5625_dsp_done(codec); + if (ret < 0) { + dev_err(codec->dev, "DSP is busy: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_ADDR, 0x26); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_CMD, + RT5625_DSP_R_EN | RT5625_DSP_CMD_RR); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret); + goto err; + } + ret = rt5625_dsp_done(codec); + if (ret < 0) { + dev_err(codec->dev, "DSP is busy: %d\n", ret); + goto err; + } + ret = snd_soc_read(codec, RT5625_DSP_DATA); + if (ret < 0) { + dev_err(codec->dev, "Failed to read DSP data reg: %d\n", ret); + goto err; + } + val_h = ret; - if (ret != rt5625_wait_vodsp_i2c_done(codec)) - return -EBUSY; - rt5625_write(codec, RT5625_VODSP_REG_ADDR, 0x26); - rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR); + /* Read DSP low byte data */ + ret = snd_soc_write(codec, RT5625_DSP_ADDR, 0x25); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP addr reg: %d\n", ret); + goto err; + } + ret = snd_soc_write(codec, RT5625_DSP_CMD, + RT5625_DSP_R_EN | RT5625_DSP_CMD_RR); + if (ret < 0) { + dev_err(codec->dev, "Failed to write DSP cmd reg: %d\n", ret); + goto err; + } + ret = rt5625_dsp_done(codec); + if (ret < 0) { + dev_err(codec->dev, "DSP is busy: %d\n", ret); + goto err; + } + ret = snd_soc_read(codec, RT5625_DSP_DATA); + if (ret < 0) { + dev_err(codec->dev, "Failed to read DSP data reg: %d\n", ret); + goto err; + } + val_l = ret; - if(ret != rt5625_wait_vodsp_i2c_done(codec)) - return -EBUSY; - nDataH = rt5625_read(codec, RT5625_VODSP_REG_DATA); - rt5625_write(codec, RT5625_VODSP_REG_ADDR, 0x25); - rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR); + return ((val_h & 0xff) << 8) |(val_l & 0xff); - if(ret != rt5625_wait_vodsp_i2c_done(codec)) - return -EBUSY; - nDataL = rt5625_read(codec, RT5625_VODSP_REG_DATA); - value = ((nDataH & 0xff) << 8) |(nDataL & 0xff); - DBG("%s vodspreg=0x%x, value=0x%x\n", __func__, vodspreg, value); - return value; +err: + return ret; } -static int rt5625_reg_init(struct snd_soc_codec *codec) -{ - int i; +/* ADCR function select */ +static const char *adcr_fun_sel[] = { + "Stereo ADC", "Voice ADC", "VoDSP", "PDM Slave"}; - for (i = 0; i < RT5625_INIT_REG_NUM; i++) - rt5625_write(codec, rt5625_init_list[i].reg_index, rt5625_init_list[i].reg_value); +static const struct soc_enum adcr_fun_sel_enum = + SOC_ENUM_SINGLE(RT5625_F_DAC_ADC_VDAC, RT5625_ADCR_F_SFT, + ARRAY_SIZE(adcr_fun_sel), adcr_fun_sel); - return 0; -} +/* ADCL function select */ +static const char *adcl_fun_sel[] = {"Stereo ADC", "VoDSP"}; -//************************************************************************************************* -//************************************************************************************************* -#if (RT5625_EQ_FUNC_ENA==1) -//eq function -static void rt5625_update_eqmode(struct snd_soc_codec *codec, int mode) -{ - u16 HwEqIndex=0; +static const struct soc_enum adcl_fun_sel_enum = + SOC_ENUM_SINGLE(RT5625_F_DAC_ADC_VDAC, RT5625_ADCL_F_SFT, + ARRAY_SIZE(adcl_fun_sel), adcl_fun_sel); - if(mode==NORMAL) - { - /*clear EQ parameter*/ - for(HwEqIndex=0;HwEqIndex<=0x0C;HwEqIndex++) - { - rt5625_write_index(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex]); - } - - rt5625_write_mask(codec, 0x6e,0x0,EN_HW_EQ_BLK | EN_HW_EQ_HPF | EN_HW_EQ_BP3 | EN_HW_EQ_BP2 | EN_HW_EQ_BP1 | EN_HW_EQ_LPF); /*disable EQ block*/ - } - else - { - /*Fill EQ parameter*/ - for(HwEqIndex=0;HwEqIndex<=0x0C;HwEqIndex++) - { - rt5625_write_index(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex]); - } +/* Voice DSP */ +static const char *rt5625_aec_fun[] = {"Disable", "Enable"}; - //enable EQ block - rt5625_write_mask(codec, 0x6e,HwEq_Preset[mode].HwEQCtrl,EN_HW_EQ_BLK | EN_HW_EQ_HPF | EN_HW_EQ_BP3 | EN_HW_EQ_BP2 | EN_HW_EQ_BP1 | EN_HW_EQ_LPF); - - //update EQ parameter - rt5625_write_mask(codec, 0x6e,0x0080,0x0080); - } -} +static const SOC_ENUM_SINGLE_DECL(rt5625_aec_fun_enum, 0, 0, rt5625_aec_fun); +static const char *rt5625_dsp_lrck[] = {"8KHz", "16KHz"}; -static int rt5625_eq_sel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u16 Virtual_reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC); - int rt5625_mode=((Virtual_reg)&0xf000)>>12; - - if ( rt5625_mode == ucontrol->value.integer.value[0]) - return 0; +static const SOC_ENUM_SINGLE_DECL(rt5625_dsp_lrck_enum, + RT5625_VODSP_CTL, RT5625_DSP_LRCK_SFT, rt5625_dsp_lrck); - rt5625_update_eqmode(codec, ucontrol->value.enumerated.item[0]); +static const char *rt5625_bp_ctrl[] = {"Bypass", "Normal"}; - Virtual_reg &= 0x0fff; - Virtual_reg |= (ucontrol->value.integer.value[0])<<12; - rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, Virtual_reg); - - return 0; -} -#endif -//************************************************************************************************* -//************************************************************************************************* -static const char *rt5625_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 *rt5625_spk_out_sel[] = {"Class AB", "Class D"}; /*1*/ -static const char *rt5625_spk_l_source_sel[] = {"LPRN", "LPRP", "LPLN", "MM"}; /*2*/ -static const char *rt5625_spkmux_source_sel[] = {"VMID", "HP Mixer", - "SPK Mixer", "Mono Mixer"}; /*3*/ -static const char *rt5625_hplmux_source_sel[] = {"VMID","HPL Mixer"}; /*4*/ -static const char *rt5625_hprmux_source_sel[] = {"VMID","HPR Mixer"}; /*5*/ -static const char *rt5625_auxmux_source_sel[] = {"VMID", "HP Mixer", - "SPK Mixer", "Mono Mixer"}; /*6*/ -static const char *rt5625_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 *rt5625_mic1_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"}; /*8*/ -static const char *rt5625_mic2_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"}; /*9*/ -static const char *rt5625_dmic_boost_sel[] = {"Bypass", "+6db", "+12db", "+18db", - "+24db", "+30db", "+36db", "+42db"}; /*10*/ -static const char *rt5625_adcr_func_sel[] = {"Stereo ADC", "Voice ADC", - "VoDSP Interface", "PDM Slave Interface"}; /*11*/ -#if (RT5625_EQ_FUNC_ENA==1) -static const char *rt5625_eq_sel[] = {"NORMAL", "CLUB","DANCE", "LIVE","POP", /*12*/ - "ROCK", "OPPO", "TREBLE", "BASS"}; -#endif +static const SOC_ENUM_SINGLE_DECL(rt5625_bp_ctrl_enum, + RT5625_VODSP_CTL, RT5625_DSP_BP_SFT, rt5625_bp_ctrl); -static const struct soc_enum rt5625_enum[] = { - -SOC_ENUM_SINGLE(VIRTUAL_REG_FOR_MISC_FUNC, 0, 4, rt5625_aec_path_sel), /*0*/ -SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 13, 2, rt5625_spk_out_sel), /*1*/ -SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 14, 4, rt5625_spk_l_source_sel), /*2*/ -SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 10, 4, rt5625_spkmux_source_sel),/*3*/ -SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 9, 2, rt5625_hplmux_source_sel), /*4*/ -SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 8, 2, rt5625_hprmux_source_sel),/*5*/ -SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 6, 4, rt5625_auxmux_source_sel),/*6*/ -SOC_ENUM_SINGLE(RT5625_GEN_CTRL_REG1, 1, 6, rt5625_spkamp_ratio_sel), /*7*/ -SOC_ENUM_SINGLE(RT5625_MIC_CTRL, 10, 4, rt5625_mic1_boost_sel), /*8*/ -SOC_ENUM_SINGLE(RT5625_MIC_CTRL, 8, 4, rt5625_mic2_boost_sel), /*9*/ -SOC_ENUM_SINGLE(RT5625_DMIC_CTRL, 0, 8, rt5625_dmic_boost_sel), /*10*/ -SOC_ENUM_SINGLE(RT5625_DAC_ADC_VODAC_FUN_SEL, 4, 4, rt5625_adcr_func_sel), /*11*/ -#if (RT5625_EQ_FUNC_ENA==1) -SOC_ENUM_SINGLE(VIRTUAL_REG_FOR_MISC_FUNC, 12, 9, rt5625_eq_sel), /*EQ mode select mode 12*/ -#endif -}; +static const char *rt5625_pd_ctrl[] = {"Power down", "Normal"}; + +static const SOC_ENUM_SINGLE_DECL(rt5625_pd_ctrl_enum, + RT5625_VODSP_CTL, RT5625_DSP_PD_SFT, rt5625_pd_ctrl); + +static const char *rt5625_rst_ctrl[] = {"Reset", "Normal"}; + +static const SOC_ENUM_SINGLE_DECL(rt5625_rst_ctrl_enum, + RT5625_VODSP_CTL, RT5625_DSP_RST_SFT, rt5625_rst_ctrl); +/* Speaker */ +static const char *rt5625_spk_out[] = {"Class AB", "Class D"}; +static const SOC_ENUM_SINGLE_DECL(rt5625_spk_out_enum, + RT5625_OUTMIX_CTRL, RT5625_SPK_T_SFT, rt5625_spk_out); +static const char *rt5625_spkl_src[] = {"LPRN", "LPRP", "LPLN", "MM"}; -//***************************************************************************** -//function:Enable the Voice PCM interface Path -//***************************************************************************** -static int ConfigPcmVoicePath(struct snd_soc_codec *codec,unsigned int bEnableVoicePath,unsigned int mode) +static const SOC_ENUM_SINGLE_DECL(rt5625_spkl_src_enum, + RT5625_OUTMIX_CTRL, RT5625_SPKN_S_SFT, rt5625_spkl_src); + +static const char *rt5625_spkamp_ratio[] = {"2.25 Vdd", "2.00 Vdd", + "1.75 Vdd", "1.50 Vdd", "1.25 Vdd", "1.00 Vdd"}; + +static const SOC_ENUM_SINGLE_DECL(rt5625_spkamp_ratio_enum, + RT5625_GEN_CTRL1, RT5625_SPK_R_SFT, rt5625_spkamp_ratio); + +/* Output/Input Mode */ +//static const char *rt5625_auxout_mode[] = {"Differential", "Single ended"}; + +//static const SOC_ENUM_SINGLE_DECL(rt5625_auxout_mode_enum, +// RT5625_OUTMIX_CTRL, RT5625_AUXOUT_MODE_SFT, rt5625_auxout_mode); + +//static const char *rt5625_input_mode[] = {"Single ended", "Differential"}; + +//static const SOC_ENUM_SINGLE_DECL(rt5625_phone_mode_enum, +// RT5625_PHONEIN_VOL, RT5625_PHO_DIFF_SFT, rt5625_input_mode); + +//static const SOC_ENUM_SINGLE_DECL(rt5625_mic1_mode_enum, +// RT5625_MIC_VOL, RT5625_MIC1_DIFF_SFT, rt5625_input_mode); + +//static const SOC_ENUM_SINGLE_DECL(rt5625_mic2_mode_enum, +// RT5625_MIC_VOL, RT5625_MIC2_DIFF_SFT, rt5625_input_mode); + +static int rt5625_adcr_fun_sel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + unsigned int val, mask, bitmask; - if(bEnableVoicePath) - { - //Power on DAC reference - rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD1,PWR_DAC_REF|PWR_VOICE_DF2SE,PWR_DAC_REF|PWR_VOICE_DF2SE); - //Power on Voice DAC/ADC - rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD2,PWR_VOICE_CLOCK,PWR_VOICE_CLOCK); - //routing voice to HPMixer - rt5625_write_mask(codec,RT5625_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 - - //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 B - //the register 0x36 value's should is 0xC083 - rt5625_write(codec,RT5625_EXTEND_SDP_CTRL,0xC083); - - //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 - rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524); - - break; + for (bitmask = 1; bitmask < e->max; bitmask <<= 1) + ; + if (ucontrol->value.enumerated.item[0] > e->max - 1) + return -EINVAL; + val = ucontrol->value.enumerated.item[0] << e->shift_l; + mask = (bitmask - 1) << e->shift_l; + + snd_soc_update_bits(codec, RT5625_PD_CTRL, + RT5625_PWR_PR0, RT5625_PWR_PR0); + if ((rt5625->app_bmp & RT5625_3G_MASK) && + rt5625->vodsp_fun == RT5625_AEC_EN) { + snd_soc_update_bits(codec, e->reg, mask, RT5625_ADCR_F_PDM); + } else if (rt5625->app_bmp & RT5625_VOIP_MASK && + rt5625->vodsp_fun == RT5625_AEC_EN) { + snd_soc_update_bits(codec, e->reg, mask, RT5625_ADCR_F_PDM); + } else if (rt5625->app_bmp & RT5625_BT_MASK) { + snd_soc_update_bits(codec, e->reg, mask, RT5625_ADCR_F_VADC); + } else { + snd_soc_update_bits(codec, e->reg, mask, val); + } + snd_soc_update_bits(codec, RT5625_PD_CTRL, RT5625_PWR_PR0, 0); - 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 - rt5625_write(codec,RT5625_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 - rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524); - - break; + return 0; +} - 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 - rt5625_write(codec,RT5625_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 - rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524); - - break; +static int rt5625_adcl_fun_sel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + unsigned int val, mask, bitmask; - default: - //do nothing - break; + for (bitmask = 1; bitmask < e->max; bitmask <<= 1) + ; + if (ucontrol->value.enumerated.item[0] > e->max - 1) + return -EINVAL; + val = ucontrol->value.enumerated.item[0] << e->shift_l; + mask = (bitmask - 1) << e->shift_l; + + snd_soc_update_bits(codec, RT5625_PD_CTRL, + RT5625_PWR_PR0, RT5625_PWR_PR0); + if ((rt5625->app_bmp & RT5625_3G_MASK) && + rt5625->vodsp_fun == RT5625_AEC_EN) { + snd_soc_update_bits(codec, e->reg, mask, RT5625_ADCL_F_DSP); + } else { + snd_soc_update_bits(codec, e->reg, mask, val); + } + snd_soc_update_bits(codec, RT5625_PD_CTRL, RT5625_PWR_PR0, 0); - } - } - else - { - //Power down Voice Different to sing-end power - rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD1,0,PWR_VOICE_DF2SE); - //Power down Voice DAC/ADC - rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD2,0,PWR_VOICE_CLOCK); - //Disable Voice PCM interface - rt5625_write_mask(codec,RT5625_EXTEND_SDP_CTRL,0,EXT_I2S_FUNC_ENABLE); - } - return 0; } -static int init_vodsp_aec(struct snd_soc_codec *codec) +static int rt5625_init_vodsp_aec(struct snd_soc_codec *codec) { - int i; - int ret = 0; + int i, ret = 0; /*disable LDO power*/ - rt5625_write_mask(codec, RT5625_LDO_CTRL,0,LDO_ENABLE); + snd_soc_update_bits(codec, RT5625_LDO_CTRL, + RT5625_LDO_MASK, RT5625_LDO_DIS); mdelay(20); - rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA); + snd_soc_update_bits(codec, RT5625_VODSP_CTL, + RT5625_DSP_PD_MASK, RT5625_DSP_PD_NOR); /*enable LDO power and set output voltage to 1.2V*/ - rt5625_write_mask(codec, RT5625_LDO_CTRL,LDO_ENABLE|LDO_OUT_VOL_CTRL_1_20V,LDO_ENABLE|LDO_OUT_VOL_CTRL_MASK); + snd_soc_update_bits(codec, RT5625_LDO_CTRL, + RT5625_LDO_MASK | RT5625_LDO_VC_MASK, + RT5625_LDO_EN | RT5625_LDO_VC_1_20V); mdelay(20); /*enable power of VODSP I2C interface*/ - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); + snd_soc_update_bits(codec, RT5625_PWR_ADD3, RT5625_P_DSP_IF | + RT5625_P_DSP_I2C, RT5625_P_DSP_IF | RT5625_P_DSP_I2C); mdelay(1); - rt5625_write_mask(codec, RT5625_VODSP_CTL,0,VODSP_NO_RST_MODE_ENA); /*Reset VODSP*/ + /*Reset VODSP*/ + snd_soc_update_bits(codec, RT5625_VODSP_CTL, + RT5625_DSP_RST_MASK, RT5625_DSP_RST_EN); mdelay(1); - rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_NO_RST_MODE_ENA,VODSP_NO_RST_MODE_ENA); /*set VODSP to non-reset status*/ + /*set VODSP to non-reset status*/ + snd_soc_update_bits(codec, RT5625_VODSP_CTL, + RT5625_DSP_RST_MASK, RT5625_DSP_RST_NOR); mdelay(20); /*initize AEC paramter*/ - for(i = 0; i < SET_VODSP_REG_INIT_NUM; i++) - { - ret = rt5625_write_vodsp_reg(codec, VODSP_AEC_Init_Value[i].VoiceDSPIndex,VODSP_AEC_Init_Value[i].VoiceDSPValue); + for(i = 0; i < RT5625_DSP_INIT_NUM; i++) { + ret = rt5625_dsp_write(codec, rt5625_dsp_init[i].index, + rt5625_dsp_init[i].value); if(ret) return -EIO; } - - schedule_timeout_uninterruptible(msecs_to_jiffies(10)); + mdelay(10); + //printk("[DSP poweron] 0x%04x: 0x%04x\n", 0x230C, rt5625_dsp_read(codec, 0x230C)); return 0; } -//*********************************************************************************************** -//function:Enable/Disable the vodsp interface Path -//For system clock only suport specific clock,realtek suggest customer to use 24.576Mhz or 22.5792Mhz -//clock fro MCLK(MCLK=48k*512 or 44.1k*512Mhz) -//*********************************************************************************************** -static int set_vodsp_aec_path(struct snd_soc_codec *codec, unsigned int mode) +static int rt5625_aec_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - switch(mode) - { - - case PCM_IN_PCM_OUT: - //set PCM format - ConfigPcmVoicePath(codec,1,PCM_MASTER_MODE_B); - //set AEC path - rt5625_write_mask(codec, 0x26,0x0300,0x0300); - rt5625_write_mask(codec, RT5625_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); - rt5625_write_mask(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|VODAC_SOUR_SEL_VODSP_TXDC - ,ADCR_FUNC_SEL_MASK|VODAC_SOUR_SEL_MASK); - rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_LRCK_SEL_8K,VODSP_LRCK_SEL_MASK); - rt5625_write_mask(codec, 0x26,0x0000,0x0300); - //set input&output path and power - rt5625_write_mask(codec, 0x3a,0x0c8f,0x0c8f);//power on related bit - rt5625_write_mask(codec, 0x3c,0xa4cb,0xa4cb);//power on related bit - rt5625_write_mask(codec, 0x3e,0x3302,0xf302);//power on related bit - - rt5625_write(codec, 0x10, 0xee0f);//mute DAC to hpmixer - rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode - rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db - rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db - rt5625_write(codec, 0x14, 0x7f3f);//Mic1->ADCMixer_R - rt5625_write(codec, 0x18, 0xa010);//VoDAC to speakerMixer,0db - rt5625_write(codec, 0x1c, 0x8808);//speaker source from speakermixer - - rt5625_write_mask(codec, 0x02,0x0000,0x8080); //unmute speaker + ucontrol->value.integer.value[0] = rt5625->vodsp_fun; + return 0; +} - break; - - - case ANALOG_IN_ANALOG_OUT: - rt5625_write_mask(codec, 0x26,0x0300,0x0300); - rt5625_write_mask(codec, RT5625_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); - rt5625_write_mask(codec, RT5625_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); - rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_LRCK_SEL_16K,VODSP_LRCK_SEL_MASK); - rt5625_write_mask(codec, 0x26,0x0000,0x0300); - //set input&output path and power - rt5625_write_mask(codec, 0x3a,0xcc8f,0xcc8f);//power on related bit - rt5625_write_mask(codec, 0x3c,0xa7cf,0xa7cf);//power on related bit - rt5625_write_mask(codec, 0x3e,0xf312,0xf312);//power on related bit - - rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode - rt5625_write(codec, 0x08, 0xe800);//set phone in to differential mode - rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db - rt5625_write(codec, 0x14, 0x773f);//Mic1->ADCMixer_R,phone in-->ADCMixer_L - rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db - rt5625_write(codec, 0x1c, 0x88c8);//speaker from spkmixer,monoOut from monoMixer - rt5625_write(codec, 0x18, 0xA010);//unmute VoDAC to spkmixer - rt5625_write(codec, 0x10, 0xee0e);//unmute DAC to monoMixer - rt5625_write(codec, 0x62, 0x2222); - rt5625_write(codec, 0x64, 0x3122); - rt5625_write_mask(codec, 0x02,0x0000,0x8080); //unmute speaker - rt5625_write_mask(codec, 0x06,0x0000,0x8080); //unmute auxout - break; - case DAC_IN_ADC_OUT: - rt5625_write_mask(codec, 0x26,0x0300,0x0300); - rt5625_write_mask(codec,RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|DAC_FUNC_SEL_VODSP_TXDC - ,ADCR_FUNC_SEL_MASK|DAC_FUNC_SEL_MASK); - rt5625_write_mask(codec,RT5625_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); - rt5625_write_mask(codec,RT5625_VODSP_CTL,VODSP_LRCK_SEL_16K,VODSP_LRCK_SEL_MASK); - rt5625_write_mask(codec, 0x26,0x0000,0x0300); - //set input&output path and power - rt5625_write_mask(codec, 0x3a,0xcc0f,0xcc0f);//power on related bit - rt5625_write_mask(codec, 0x3c,0xa7cb,0xa7cb);//power on related bit - rt5625_write_mask(codec, 0x3e,0x3302,0x3302);//power on related bit - - rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode - rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db - rt5625_write(codec, 0x14, 0x7f3f);//Mic1->ADCMixer_R - rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db - rt5625_write(codec, 0x1c, 0x8808);//speaker out from spkMixer - rt5625_write(codec, 0x10, 0xee0d);//unmute DAC to spkMixer - rt5625_write(codec, 0x60, 0x3075); - rt5625_write(codec, 0x62, 0x1010); - rt5625_write_mask(codec, 0x02,0x0000,0x8080); //unmute speaker +static int rt5625_aec_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - break; + if(ucontrol->value.integer.value[0] == rt5625->vodsp_fun) + return 0; + rt5625->vodsp_fun = ucontrol->value.integer.value[0]; - case VODSP_AEC_DISABLE: - default: - rt5625_write_mask(codec, 0x02,0x8080,0x8080);//mute speaker out - rt5625_write_mask(codec, 0x06,0x8080,0x8080);//mute auxout - rt5625_write(codec, 0x22, 0x0500);//Mic boost 20db by default - rt5625_write(codec, 0x14, 0x3f3f);//record from Mic1 by default - rt5625_write(codec, 0x12, 0xD5D5);//ADC_Mixer_R boost 15 db by default - rt5625_write(codec, 0x1c, 0x0748);//all output from HPmixer by default - rt5625_write(codec, 0x10, 0xee03);//DAC to HPmixer by default - rt5625_write(codec, 0x18, 0xe010);//mute VoDAC to mixer by default - rt5625_write_mask(codec, 0x26,0x0300,0x0300); - /*set stereo DAC&Voice DAC&Stereo ADC function select to default*/ - rt5625_write(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,0); - /*set VODSP&PDM Control to default*/ - rt5625_write(codec, RT5625_VODSP_PDM_CTL,0); - rt5625_write_mask(codec, 0x26,0x0000,0x0300); - rt5625_write_mask(codec, 0x3e,0x0000,0xf312);//power down related bit - rt5625_write_mask(codec, 0x3a,0x0000,0xcc8d);//power down related bit - rt5625_write_mask(codec, 0x3c,0x0000,0x07cf);//power down related bit - - - break; - } + switch(rt5625->vodsp_fun) { + case RT5625_AEC_EN: + break; + case RT5625_AEC_DIS: + if (!(rt5625->app_bmp & RT5625_3G_MASK) || + ((rt5625->app_bmp & RT5625_3G_MASK) && rt5625->headset)) { + snd_soc_update_bits(codec, RT5625_VODSP_CTL, + RT5625_DSP_PD_MASK, RT5625_DSP_PD_EN); + snd_soc_update_bits(codec, RT5625_PWR_ADD3, + RT5625_P_DSP_IF | RT5625_P_DSP_I2C, 0); + snd_soc_update_bits(codec, RT5625_LDO_CTRL, + RT5625_LDO_MASK, RT5625_LDO_DIS); + } + break; + default: + break; + } return 0; } -static int enable_vodsp_aec(struct snd_soc_codec *codec, unsigned int VodspAEC_En, unsigned int AEC_mode) +#ifdef RT5625_F_SMT_PHO +static int rt5625_app_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int ret = 0; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - - if (VodspAEC_En != 0) - { + pr_info("App status: %x\n", rt5625->app_bmp); - //enable power of VODSP I2C interface & VODSP interface - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); - //enable power of VODSP I2S interface - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1,PWR_I2S_INTERFACE,PWR_I2S_INTERFACE); - //select input/output of VODSP AEC - set_vodsp_aec_path(codec, AEC_mode); + return 0; +} +static int rt5625_cap_voip_chk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int i, upd; + + /* VoIP start up if record & playback all turn on, or AEC * + * is disabled. otherwise, cheat dapm. */ + if ((rt5625->app_bmp & RT5625_REC_MASK) == 0 || + (rt5625->app_bmp & RT5625_PLY_MASK) == 0) { + /* backup registers for voip routing */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + rt5625_voip_back[i][1] = + snd_soc_read(codec, rt5625_voip_back[i][0]); + /* cheat dapm */ + snd_soc_update_bits(codec, RT5625_VODSP_PDM_CTL, + RT5625_REC_IIS_S_MASK, RT5625_REC_IIS_S_SRC2); + return 0; } - else - { - //disable VODSP AEC path - set_vodsp_aec_path(codec, VODSP_AEC_DISABLE); - //set VODSP AEC to power down mode - rt5625_write_mask(codec, RT5625_VODSP_CTL,0,VODSP_NO_PD_MODE_ENA); - //disable power of VODSP I2C interface & VODSP interface - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,0,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP); + + if (rt5625->headset) { + /* backup registers for voip routing */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + rt5625_voip_back[i][1] = + snd_soc_read(codec, rt5625_voip_back[i][0]); + /* cheat dapm */ + snd_soc_update_bits(codec, RT5625_VODSP_PDM_CTL, + RT5625_REC_IIS_S_MASK, RT5625_REC_IIS_S_SRC2); + } else + rt5625->vodsp_fun = RT5625_AEC_EN; + + upd = (rt5625->app_bmp & ~RT5625_VOIP_MASK) | + (ucontrol->value.integer.value[0] << RT5625_VOIP_BIT); + if (rt5625->app_bmp != upd) { + rt5625->app_bmp = upd; + rt5625->app_bmp &= ~(RT5625_3G_MASK | RT5625_BT_MASK); } - return ret; + return 0; } -static void rt5625_aec_config(struct snd_soc_codec *codec, unsigned int mode) +static int rt5625_cap_voip_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - DBG("rt5625_aec_config %d\n",mode); + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int i; - if (mode == VODSP_AEC_DISABLE) - { - enable_vodsp_aec(codec,0, mode); - /*disable LDO power*/ - rt5625_write_mask(codec, RT5625_LDO_CTRL,0,LDO_ENABLE); - } - else - { - init_vodsp_aec(codec); - - enable_vodsp_aec(codec,1, mode); + if (rt5625->app_bmp & RT5625_VOIP_MASK) { + if (rt5625->headset) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_R_MIC1 | RT5625_M_RM_L_PHO, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_R_MIC1 | RT5625_M_RM_L_PHO); + /* recover all changes by voip */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + snd_soc_write(codec, rt5625_voip_back[i][0], + rt5625_voip_back[i][1]); + snd_soc_update_bits(codec, RT5625_VODSP_PDM_CTL, + RT5625_SRC1_PWR | RT5625_SRC2_PWR, 0); + } else { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | RT5625_M_RM_R_MIC2 | RT5625_M_RM_L_PHO, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | RT5625_M_RM_R_MIC2 | RT5625_M_RM_L_PHO); + rt5625->vodsp_fun = RT5625_AEC_EN; + /* Mic1 & Mic2 boost 0db */ + snd_soc_update_bits(codec, RT5625_MIC_CTRL, + RT5625_MIC1_BST_MASK | RT5625_MIC2_BST_MASK, + RT5625_MIC1_BST_BYPASS | RT5625_MIC2_BST_BYPASS); + /* Capture volume gain 9db */ + snd_soc_update_bits(codec, RT5625_ADC_REC_GAIN, + RT5625_G_ADCL_MASK | RT5625_G_ADCR_MASK, (0x11 << 8 ) | 0x11); + } + } else { + /* recover all changes by voip */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + snd_soc_write(codec, rt5625_voip_back[i][0], + rt5625_voip_back[i][1]); + snd_soc_update_bits(codec, RT5625_VODSP_PDM_CTL, + RT5625_SRC1_PWR | RT5625_SRC2_PWR, 0); + if (rt5625->app_bmp & RT5625_3G_MASK && + rt5625->vodsp_fun == RT5625_AEC_EN) { + /* Mic1 boost 0db */ + snd_soc_update_bits(codec, RT5625_MIC_CTRL, + RT5625_MIC1_BST_MASK, RT5625_MIC1_BST_BYPASS); + /* Capture volume gain 9db */ + snd_soc_update_bits(codec, RT5625_ADC_REC_GAIN, + RT5625_G_ADCR_MASK, 0x11); + } } -} -//**************************************************************************************************************** -//* -//*function:disable rt5625's function. -//* -//* -//**************************************************************************************************************** -static int rt5625_func_aec_disable(struct snd_soc_codec *codec,int mode) -{ - switch(mode) - { - case RT5625_AEC_PCM_IN_OUT: - case RT5625_AEC_IIS_IN_OUT: - case RT5625_AEC_ANALOG_IN_OUT: - - rt5625_aec_config(codec,VODSP_AEC_DISABLE); //disable AEC function and path - - break; - - default: + return 0; +} - break; +static int rt5625_hs_voip_chk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int i, upd; + + rt5625->headset = true; + if ((rt5625->app_bmp & RT5625_REC_MASK) == 0 || + (rt5625->app_bmp & RT5625_PLY_MASK) == 0) { + /* backup registers for voip routing */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + rt5625_voip_back[i][1] = + snd_soc_read(codec, rt5625_voip_back[i][0]); + rt5625->vodsp_fun_bak = rt5625->vodsp_fun; + /* cheat dapm */ + snd_soc_update_bits(codec, RT5625_VODSP_PDM_CTL, + RT5625_REC_IIS_S_MASK | RT5625_RXDP_PWR, RT5625_REC_IIS_S_ADC); + return 0; + } + + upd = (rt5625->app_bmp & ~RT5625_VOIP_MASK) | + (ucontrol->value.integer.value[0] << RT5625_VOIP_BIT); + if (rt5625->app_bmp != upd) { + rt5625->app_bmp = upd; + rt5625->app_bmp &= ~(RT5625_3G_MASK | RT5625_BT_MASK); } return 0; } - -static int rt5625_get_dsp_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int rt5625_hs_voip_put(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 = (rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC)) & 0x03; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int i; + + if (rt5625->app_bmp & RT5625_VOIP_MASK) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_MIC1 | RT5625_M_RM_L_PHO, + RT5625_M_RM_R_MIC1 | RT5625_M_RM_L_PHO); + /* Mic1 & Mic2 boost 0db */ + snd_soc_update_bits(codec, RT5625_MIC_CTRL, + RT5625_MIC1_BST_MASK | RT5625_MIC2_BST_MASK, + RT5625_MIC1_BST_BYPASS | RT5625_MIC2_BST_BYPASS); + /* Capture volume gain 9db */ + snd_soc_update_bits(codec, RT5625_ADC_REC_GAIN, + RT5625_G_ADCL_MASK | RT5625_G_ADCR_MASK, (0x11 << 8 ) | 0x11); + } else { + /* recover all changes by voip */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + snd_soc_write(codec, rt5625_voip_back[i][0], + rt5625_voip_back[i][1]); + rt5625->vodsp_fun = rt5625->vodsp_fun_bak; + if ((rt5625->app_bmp & RT5625_3G_MASK) && rt5625->vodsp_fun == RT5625_AEC_EN) { + snd_soc_update_bits(codec, RT5625_F_DAC_ADC_VDAC, + RT5625_ADCR_F_MASK, RT5625_ADCR_F_PDM); + } else if (rt5625->app_bmp & RT5625_BT_MASK) { + snd_soc_update_bits(codec, RT5625_F_DAC_ADC_VDAC, + RT5625_ADCR_F_MASK, RT5625_ADCR_F_VADC); + } else { + snd_soc_update_bits(codec, RT5625_F_DAC_ADC_VDAC, + RT5625_ADCR_F_MASK, RT5625_ADCR_F_ADC); + } + } - ucontrol->value.integer.value[0] = mode; return 0; } - -static int rt5625_set_dsp_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int rt5625_voip_chk_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u16 Virtual_reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC); - int rt5625_mode=(Virtual_reg)&0x03; - - DBG("rt5625_mode=%d,value[0]=%ld,Virtual_reg=%x\n",rt5625_mode,ucontrol->value.integer.value[0],Virtual_reg); - - if ( rt5625_mode == ucontrol->value.integer.value[0]) + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int i, upd; + + rt5625->headset = false; + /* voip start-up if record is on-going; otherwise, cheat dapm */ + if ((rt5625->app_bmp & RT5625_REC_MASK) == 0 || + (rt5625->app_bmp & RT5625_PLY_MASK) == 0) { + /* backup registers for voip routing */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + rt5625_voip_back[i][1] = + snd_soc_read(codec, rt5625_voip_back[i][0]); + rt5625->vodsp_fun_bak = rt5625->vodsp_fun; + /* cheat dapm */ + snd_soc_update_bits(codec, RT5625_VODSP_PDM_CTL, + RT5625_RXDP_S_MASK | RT5625_REC_IIS_S_MASK | RT5625_RXDP_PWR, + RT5625_RXDP_S_SRC1 | RT5625_REC_IIS_S_SRC2); return 0; + } - switch(ucontrol->value.integer.value[0]) - { - case RT5625_AEC_PCM_IN_OUT: - - rt5625_aec_config(codec,PCM_IN_PCM_OUT);//enable AEC PCM in/out function and path + upd = (rt5625->app_bmp & ~RT5625_VOIP_MASK) | + (ucontrol->value.integer.value[0] << RT5625_VOIP_BIT); + if (rt5625->app_bmp != upd) { + rt5625->app_bmp = upd; + rt5625->app_bmp &= ~(RT5625_3G_MASK | RT5625_BT_MASK); + } - break; + return 0; +} - case RT5625_AEC_IIS_IN_OUT: +static int rt5625_voip_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int i; - rt5625_aec_config(codec,DAC_IN_ADC_OUT);//enable AEC IIS in/out function and path + if (rt5625->app_bmp & RT5625_VOIP_MASK) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_MIC2 | RT5625_M_RM_L_PHO, + RT5625_M_RM_R_MIC2 | RT5625_M_RM_L_PHO); + /* Mic1 & Mic2 boost 0db */ + snd_soc_update_bits(codec, RT5625_MIC_CTRL, + RT5625_MIC1_BST_MASK | RT5625_MIC2_BST_MASK, + RT5625_MIC1_BST_BYPASS | RT5625_MIC2_BST_BYPASS); + /* Capture volume gain 9db */ + snd_soc_update_bits(codec, RT5625_ADC_REC_GAIN, + RT5625_G_ADCL_MASK | RT5625_G_ADCR_MASK, (0x11 << 8 ) | 0x11); + } else { + /* recover all changes by voip */ + for(i = 0; i < RT5625_VOIP_BK_NUM; i++) + snd_soc_write(codec, rt5625_voip_back[i][0], + rt5625_voip_back[i][1]); + rt5625->vodsp_fun = rt5625->vodsp_fun_bak; + snd_soc_update_bits(codec, RT5625_VODSP_PDM_CTL, + RT5625_SRC1_PWR | RT5625_SRC2_PWR, 0); + if ((rt5625->app_bmp & RT5625_3G_MASK) && rt5625->vodsp_fun == RT5625_AEC_EN) { + snd_soc_update_bits(codec, RT5625_F_DAC_ADC_VDAC, + RT5625_ADCR_F_MASK, RT5625_ADCR_F_PDM); + } else if (rt5625->app_bmp & RT5625_BT_MASK) { + snd_soc_update_bits(codec, RT5625_F_DAC_ADC_VDAC, + RT5625_ADCR_F_MASK, RT5625_ADCR_F_VADC); + } else { + snd_soc_update_bits(codec, RT5625_F_DAC_ADC_VDAC, + RT5625_ADCR_F_MASK, RT5625_ADCR_F_ADC); + } + } - break; + return 0; +} - case RT5625_AEC_ANALOG_IN_OUT: - - rt5625_aec_config(codec,ANALOG_IN_ANALOG_OUT);//enable AEC analog in/out function and path - - break; +static int rt5625_voip_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - case RT5625_AEC_DISABLE: - - rt5625_func_aec_disable(codec,rt5625_mode); //disable previous select function. - - break; + ucontrol->value.integer.value[0] = + (rt5625->app_bmp & RT5625_VOIP_MASK) >> RT5625_VOIP_BIT; - default: + return 0; +} - break; - } +static int rt5625_play_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - Virtual_reg &= 0xfffc; - Virtual_reg |= (ucontrol->value.integer.value[0]); - rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, Virtual_reg); + ucontrol->value.integer.value[0] = + (rt5625->app_bmp & RT5625_PLY_MASK) >> RT5625_PLY_BIT; - DBG("2rt5625_mode=%d,value[0]=%ld,Virtual_reg=%x\n",rt5625_mode,ucontrol->value.integer.value[0],Virtual_reg); return 0; } -static int rt5625_dump_dsp_reg(struct snd_soc_codec *codec) +static int rt5625_play_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int i; - - rt5625_write_mask(codec, RT5625_VODSP_CTL, VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA); - for (i = 0; i < SET_VODSP_REG_INIT_NUM; i++) { - rt5625_read_vodsp_reg(codec, VODSP_AEC_Init_Value[i].VoiceDSPIndex); + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int upd; + + upd = (rt5625->app_bmp & ~RT5625_PLY_MASK) | + (ucontrol->value.integer.value[0] << RT5625_PLY_BIT); + if (rt5625->app_bmp != upd) + rt5625->app_bmp = upd; + + if (!(rt5625->app_bmp & RT5625_3G_MASK) || + ((rt5625->app_bmp & RT5625_3G_MASK) && rt5625->headset)) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_PHO, RT5625_M_RM_L_PHO); } + return 0; } - -static int rt5625_dump_dsp_put(struct snd_kcontrol *kcontrol, +static int rt5625_rec_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int mode = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = + (rt5625->app_bmp & RT5625_REC_MASK) >> RT5625_REC_BIT; - mode &= ~(0x01 << 8); - mode |= (ucontrol->value.integer.value[0] << 8); - rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, mode); - rt5625_dump_dsp_reg(codec); - return 0; } -static const struct snd_kcontrol_new rt5625_snd_controls[] = { -SOC_ENUM_EXT("rt5625 aec mode sel", rt5625_enum[0], rt5625_get_dsp_mode, rt5625_set_dsp_mode), -SOC_ENUM("SPK Amp Type", rt5625_enum[1]), -SOC_ENUM("Left SPK Source", rt5625_enum[2]), -SOC_ENUM("SPK Amp Ratio", rt5625_enum[7]), -SOC_ENUM("Mic1 Boost", rt5625_enum[8]), -SOC_ENUM("Mic2 Boost", rt5625_enum[9]), -SOC_ENUM("Dmic Boost", rt5625_enum[10]), -SOC_ENUM("ADCR Func", rt5625_enum[11]), -SOC_DOUBLE("PCM Playback Volume", RT5625_STEREO_DAC_VOL, 8, 0, 63, 1), -SOC_DOUBLE("LineIn Playback Volume", RT5625_LINE_IN_VOL, 8, 0, 31, 1), -SOC_SINGLE("Phone Playback Volume", RT5625_PHONEIN_VOL, 8, 31, 1), -SOC_SINGLE("Mic1 Playback Volume", RT5625_MIC_VOL, 8, 31, 1), -SOC_SINGLE("Mic2 Playback Volume", RT5625_MIC_VOL, 0, 31, 1), -SOC_DOUBLE("PCM Capture Volume", RT5625_ADC_REC_GAIN, 8, 0, 31, 1), -SOC_DOUBLE("SPKOUT Playback Volume", RT5625_SPK_OUT_VOL, 8, 0, 31, 1), -SOC_DOUBLE("SPKOUT Playback Switch", RT5625_SPK_OUT_VOL, 15, 7, 1, 1), -SOC_DOUBLE("HPOUT Playback Volume", RT5625_HP_OUT_VOL, 8, 0, 31, 1), -SOC_DOUBLE("HPOUT Playback Switch", RT5625_HP_OUT_VOL, 15, 7, 1, 1), -SOC_DOUBLE("AUXOUT Playback Volume", RT5625_AUX_OUT_VOL, 8, 0, 31, 1), -SOC_DOUBLE("AUXOUT Playback Switch", RT5625_AUX_OUT_VOL, 15, 7, 1, 1), -SOC_DOUBLE("ADC Record Gain", RT5625_ADC_REC_GAIN, 8, 0, 31, 0), -SOC_SINGLE_EXT("VoDSP Dump", VIRTUAL_REG_FOR_MISC_FUNC, 8, 1, 0, - snd_soc_get_volsw, rt5625_dump_dsp_put), -#if (RT5625_EQ_FUNC_ENA==1) -SOC_ENUM_EXT("EQ Mode", rt5625_enum[12], snd_soc_get_enum_double, rt5625_eq_sel_put), -#endif -}; - -static int rt5625_add_controls(struct snd_soc_codec *codec) +static int rt5625_rec_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - int err, i; - - for (i = 0; i < ARRAY_SIZE(rt5625_snd_controls); i++){ - err = snd_ctl_add(codec->card, - snd_soc_cnew(&rt5625_snd_controls[i], - codec, NULL)); - if (err < 0) - return err; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int upd; + + upd = (rt5625->app_bmp & ~RT5625_REC_MASK) | + (ucontrol->value.integer.value[0] << RT5625_REC_BIT); + if (rt5625->app_bmp != upd) + rt5625->app_bmp = upd; + + if (!(rt5625->app_bmp & RT5625_3G_MASK) || + ((rt5625->app_bmp & RT5625_3G_MASK) && rt5625->headset)) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_PHO, RT5625_M_RM_L_PHO); } + + return 0; } -static void hp_depop_mode2(struct snd_soc_codec *codec) +static int rt5625_bt_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN); - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3, PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL, - PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL); - rt5625_write(codec, RT5625_MISC_CTRL,HP_DEPOP_MODE2_EN); - - DBG("delay 500 msec\n"); - - schedule_timeout_uninterruptible(msecs_to_jiffies(500)); - + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_HP_OUT_AMP|PWR_HP_OUT_ENH_AMP, - PWR_HP_OUT_AMP|PWR_HP_OUT_ENH_AMP); - //rt5625_write_mask(codec, RT5625_MISC_CTRL, 0, HP_DEPOP_MODE2_EN); + ucontrol->value.integer.value[0] = + (rt5625->app_bmp & RT5625_BT_MASK) >> RT5625_BT_BIT; + return 0; } -//enable depop function for mute/unmute -static void hp_mute_unmute_depop(struct snd_soc_codec *codec,int mute) +static int rt5625_bt_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - if(mute) - { - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN); - rt5625_write(codec, RT5625_MISC_CTRL,M_UM_DEPOP_EN|HP_R_M_UM_DEPOP_EN|HP_L_M_UM_DEPOP_EN); - //Mute headphone right/left channel - rt5625_write_mask(codec,RT5625_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); - mdelay(50); + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int upd; + + if (!(rt5625->app_bmp & RT5625_REC_MASK)) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | + RT5625_M_RM_R_MIC1 | RT5625_M_RM_R_MIC2, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | + RT5625_M_RM_R_MIC1 | RT5625_M_RM_R_MIC2); } - else - { - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN); - rt5625_write(codec, RT5625_MISC_CTRL, M_UM_DEPOP_EN|HP_R_M_UM_DEPOP_EN|HP_L_M_UM_DEPOP_EN); - //unMute headphone right/left channel - rt5625_write_mask(codec,RT5625_HP_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); - mdelay(50); + + upd = (rt5625->app_bmp & ~RT5625_BT_MASK) | + (ucontrol->value.integer.value[0] << RT5625_BT_BIT); + if (rt5625->app_bmp != upd) { + rt5625->app_bmp = upd; + rt5625->app_bmp &= ~(RT5625_3G_MASK | RT5625_VOIP_MASK); } + return 0; } +static int rt5625_3g_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = + (rt5625->app_bmp & RT5625_3G_MASK) >> RT5625_3G_BIT; -/* - * _DAPM_ Controls - */ - /*Left ADC Rec mixer*/ - /*Left ADC Rec mixer*/ -static const struct snd_kcontrol_new rt5625_left_adc_rec_mixer_controls[] = { -SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5625_ADC_REC_MIXER, 14, 1, 1), -SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, 13, 1, 1), -SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, 12, 1, 1), -SOC_DAPM_SINGLE("Phone Capture Switch", RT5625_ADC_REC_MIXER, 11, 1, 1), -SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, 10, 1, 1), -SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, 9, 1, 1), -SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, 8, 1, 1), + return 0; +} -}; +static int rt5625_3g_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int upd; + + rt5625->headset = false; + if (!(rt5625->app_bmp & RT5625_REC_MASK)) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | RT5625_M_RM_R_MIC2, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | RT5625_M_RM_R_MIC2); + } -/*Left ADC Rec mixer*/ -static const struct snd_kcontrol_new rt5625_right_adc_rec_mixer_controls[] = { -SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5625_ADC_REC_MIXER, 6, 1, 1), -SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, 5, 1, 1), -SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, 4, 1, 1), -SOC_DAPM_SINGLE("Phone Capture Switch", RT5625_ADC_REC_MIXER, 3, 1, 1), -SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, 2, 1, 1), -SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, 1, 1, 1), -SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, 0, 1, 1), -}; + upd = (rt5625->app_bmp & ~RT5625_3G_MASK) | + (ucontrol->value.integer.value[0] << RT5625_3G_BIT); + if (rt5625->app_bmp != upd) { + rt5625->app_bmp = upd; + rt5625->app_bmp &= ~(RT5625_BT_MASK | RT5625_VOIP_MASK); + } -/*Left hpmixer mixer*/ -static const struct snd_kcontrol_new rt5625_left_hp_mixer_controls[] = { -SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_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", RT5625_DAC_AND_MIC_CTRL, 3, 1, 1), + return 0; +} -}; +static int rt5625_hs_3g_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int upd; + + rt5625->headset = true; + if (!(rt5625->app_bmp & RT5625_REC_MASK)) { + snd_soc_update_bits(codec, RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | + RT5625_M_RM_R_MIC1 | RT5625_M_RM_R_MIC2, + RT5625_M_RM_L_MIC1 | RT5625_M_RM_L_MIC2 | + RT5625_M_RM_R_MIC1 | RT5625_M_RM_R_MIC2); + } + upd = (rt5625->app_bmp & ~RT5625_3G_MASK) | + (ucontrol->value.integer.value[0] << RT5625_3G_BIT); + if (rt5625->app_bmp != upd) { + rt5625->app_bmp = upd; + rt5625->app_bmp &= ~(RT5625_BT_MASK | RT5625_VOIP_MASK); + } -/*Right hpmixer mixer*/ -static const struct snd_kcontrol_new rt5625_right_hp_mixer_controls[] = { -SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_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", RT5625_DAC_AND_MIC_CTRL, 2, 1, 1), + return 0; +} -}; +static int rt5625_dump_dsp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + int i; + u16 val; -/*mono mixer*/ -static const struct snd_kcontrol_new rt5625_mono_mixer_controls[] = { -SOC_DAPM_SINGLE("ADCL Playback Switch", RT5625_ADC_REC_GAIN, 14, 1, 1), -SOC_DAPM_SINGLE("ADCR Playback Switch", RT5625_ADC_REC_GAIN, 6, 1, 1), -SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, 13, 1, 1), -SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 13, 1, 1), -SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 9, 1, 1), -SOC_DAPM_SINGLE("DAC Mixer Playback Switch", RT5625_DAC_AND_MIC_CTRL, 0, 1, 1), -SOC_DAPM_SINGLE("Voice DAC Playback Switch", RT5625_VOICE_DAC_OUT_VOL, 13, 1, 1), -}; + pr_info("\n[ RT5625 DSP Register ]\n"); + for (i = 0; i < RT5625_DSP_INIT_NUM; i++) { + val = rt5625_dsp_read(codec, rt5625_dsp_init[i].index); + if (val) pr_info(" 0x%x: 0x%x\n", + rt5625_dsp_init[i].index, val); + } + return 0; +} -/*speaker mixer*/ -static const struct snd_kcontrol_new rt5625_spk_mixer_controls[] = { -SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, 14, 1, 1), -SOC_DAPM_SINGLE("Phone Playback Switch", RT5625_PHONEIN_VOL, 14, 1, 1), -SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 14, 1, 1), -SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 10, 1, 1), -SOC_DAPM_SINGLE("DAC Mixer Playback Switch", RT5625_DAC_AND_MIC_CTRL, 1, 1, 1), -SOC_DAPM_SINGLE("Voice DAC Playback Switch", RT5625_VOICE_DAC_OUT_VOL, 14, 1, 1), -}; +static int rt5625_dac_active_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); -static int mixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) + ucontrol->value.integer.value[0] = rt5625->dac_active; + return 0; +} + +static int rt5625_dac_active_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = w->codec; - unsigned int l, r; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_widget *w; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - DBG("enter %s\n", __func__); + if(ucontrol->value.integer.value[0] == rt5625->dac_active) + return 0; + rt5625->dac_active = ucontrol->value.integer.value[0]; - l= rt5625_read(codec, HPL_MIXER); - r = rt5625_read(codec, HPR_MIXER); - - if ((l & 0x1) || (r & 0x1)) - rt5625_write_mask(codec, 0x0a, 0x0000, 0x8000); - else - rt5625_write_mask(codec, 0x0a, 0x8000, 0x8000); + /* playback is on-going; do nothing when turn off BT */ + if (rt5625->dac_active == 0 && rt5625->app_bmp & RT5625_PLY_MASK) + return 0; - if ((l & 0x2) || (r & 0x2)) - rt5625_write_mask(codec, 0x08, 0x0000, 0x8000); - else - rt5625_write_mask(codec, 0x08, 0x8000, 0x8000); + list_for_each_entry(w, &dapm->card->widgets, list) + { + if (!w->sname || w->dapm != dapm) + continue; + if (strstr(w->sname, "Playback")) { + pr_info("widget %s %s %s\n", w->name, w->sname, + rt5625->dac_active ? "active" : "inactive"); + w->active = rt5625->dac_active; + } + } - if ((l & 0x4) || (r & 0x4)) - rt5625_write_mask(codec, 0x10, 0x0000, 0x8000); - else - rt5625_write_mask(codec, 0x10, 0x8000, 0x8000); + if (!(rt5625->dac_active)) + snd_soc_dapm_sync(dapm); - if ((l & 0x8) || (r & 0x8)) - rt5625_write_mask(codec, 0x10, 0x0000, 0x0800); - else - rt5625_write_mask(codec, 0x10, 0x0800, 0x0800); + return 0; +} - if ((l & 0x10) || (r & 0x10)) - rt5625_write_mask(codec, 0x18, 0x0000, 0x8000); - else - rt5625_write_mask(codec, 0x18, 0x8000, 0x8000); +static int rt5625_adc_active_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + ucontrol->value.integer.value[0] = rt5625->adc_active; return 0; } +static int rt5625_adc_active_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_widget *w; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); -/* - * 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; - - DBG("enter %s\n", __func__); - reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 4); - if ((reg >> 4) != 0x3 && reg != 0) + if(ucontrol->value.integer.value[0] == rt5625->adc_active) return 0; + rt5625->adc_active = ucontrol->value.integer.value[0]; - switch (event) + /* record is on-going; do nothing when turn off BT */ + if (rt5625->adc_active == 0 && rt5625->app_bmp & RT5625_REC_MASK) + return 0; + + list_for_each_entry(w, &dapm->card->widgets, list) { - case SND_SOC_DAPM_POST_PMU: - DBG("after virtual spk power up!\n"); - rt5625_write_mask(codec, 0x3e, 0x3000, 0x3000); - rt5625_write_mask(codec, 0x02, 0x0000, 0x8080); - rt5625_write_mask(codec, 0x3a, 0x0400, 0x0400);//power on spk amp - break; - case SND_SOC_DAPM_POST_PMD: - DBG("aftet virtual spk power down!\n"); - rt5625_write_mask(codec, 0x3a, 0x0000, 0x0400);//power off spk amp - rt5625_write_mask(codec, 0x02, 0x8080, 0x8080); - rt5625_write_mask(codec, 0x3e, 0x0000, 0x3000); - break; - default: - return 0; + if (!w->sname || w->dapm != dapm) + continue; + if (strstr(w->sname, "Capture")) { + pr_info("widget %s %s %s\n", w->name, w->sname, + rt5625->adc_active ? "active" : "inactive"); + w->active = rt5625->adc_active; + } } - return 0; -} - + if (!(rt5625->adc_active)) + snd_soc_dapm_sync(dapm); + return 0; +} -static int hp_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +static int rt5625_pll_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = w->codec; - int reg; + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - DBG("enter %s\n", __func__); + ucontrol->value.integer.value[0] = rt5625->pll_sel; + return 0; +} - reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 6); - if ((reg >> 6) != 0x3 && reg != 0) - return 0; - - switch (event) - { - case SND_SOC_DAPM_POST_PMD: - DBG("aftet virtual hp power down!\n"); +static int rt5625_pll_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); - hp_mute_unmute_depop(codec,1);//mute hp - rt5625_write_mask(codec, 0x3a, 0x0000, 0x0300); - rt5625_write_mask(codec, 0x3e, 0x0000, 0x0c00); - break; + if(ucontrol->value.integer.value[0] == rt5625->pll_sel) + return 0; + rt5625->pll_sel = ucontrol->value.integer.value[0]; + + switch(rt5625->pll_sel) { + case RT5625_PLL_DIS: + pr_info("%s(): Disable\n", __func__); + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_PLL1, 0); + snd_soc_write(codec, RT5625_DAC_CLK_CTRL2, 0); + break; - case SND_SOC_DAPM_POST_PMU: + case RT5625_PLL_112896_225792: + pr_info("%s(): 11.2896>22.5792\n", __func__); + snd_soc_write(codec, RT5625_GEN_CTRL2, 0x0000); + snd_soc_write(codec, RT5625_PLL_CTRL, 0x06a0); + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_PLL1, RT5625_SCLK_PLL1); + snd_soc_write(codec, RT5625_DAC_CLK_CTRL2, 0x0210); + break; - DBG("after virtual hp power up!\n"); - hp_depop_mode2(codec); - hp_mute_unmute_depop(codec,0);//unmute hp - break; + case RT5625_PLL_112896_24576: + pr_info("%s(): 11.2896->24.576\n", __func__); + snd_soc_write(codec, RT5625_GEN_CTRL2, 0x0000); + snd_soc_write(codec, RT5625_PLL_CTRL, 0x922f); + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_PLL1, RT5625_SCLK_PLL1); + snd_soc_write(codec, RT5625_DAC_CLK_CTRL2, 0x0210); + break; - default: - return 0; - } + default: + break; + } return 0; } - - -static int aux_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +static int rt5625_pll2_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = rt5625->pll2_sel; return 0; } -/*SPKOUT Mux*/ -static const struct snd_kcontrol_new rt5625_spkout_mux_out_controls = -SOC_DAPM_ENUM("Route", rt5625_enum[3]); +static int rt5625_pll2_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); -/*HPLOUT MUX*/ -static const struct snd_kcontrol_new rt5625_hplout_mux_out_controls = -SOC_DAPM_ENUM("Route", rt5625_enum[4]); + if(ucontrol->value.integer.value[0] == rt5625->pll2_sel) + return 0; + rt5625->pll2_sel = ucontrol->value.integer.value[0]; + + if(rt5625->pll2_sel != RT5625_PLL_DIS) { + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_VSCLK_MASK, RT5625_VSCLK_PLL2); + snd_soc_write(codec, RT5625_PLL2_CTRL, RT5625_PLL2_EN); + snd_soc_write(codec, RT5625_VDAC_CLK_CTRL1, + RT5625_VBCLK_DIV1_4); + snd_soc_update_bits(codec, RT5625_EXT_SDP_CTRL, + RT5625_PCM_CS_MASK, RT5625_PCM_CS_VSCLK); + } -/*HPROUT MUX*/ -static const struct snd_kcontrol_new rt5625_hprout_mux_out_controls = -SOC_DAPM_ENUM("Route", rt5625_enum[5]); -/*AUXOUT MUX*/ -static const struct snd_kcontrol_new rt5625_auxout_mux_out_controls = -SOC_DAPM_ENUM("Route", rt5625_enum[6]); + return 0; +} -static const struct snd_soc_dapm_widget rt5625_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", RT5625_PWR_MANAG_ADD3, 1, 0, NULL, 0), -SND_SOC_DAPM_PGA("Mic2 Boost", RT5625_PWR_MANAG_ADD3, 0, 0, NULL, 0), - -SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback DAC", RT5625_PWR_MANAG_ADD2, 9, 0), -SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback DAC", RT5625_PWR_MANAG_ADD2, 8, 0), -SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback DAC", RT5625_PWR_MANAG_ADD2, 10, 0), - -SND_SOC_DAPM_PGA("Left LineIn PGA", RT5625_PWR_MANAG_ADD3, 7, 0, NULL, 0), -SND_SOC_DAPM_PGA("Right LineIn PGA", RT5625_PWR_MANAG_ADD3, 6, 0, NULL, 0), -SND_SOC_DAPM_PGA("Phone PGA", RT5625_PWR_MANAG_ADD3, 5, 0, NULL, 0), -SND_SOC_DAPM_PGA("Mic1 PGA", RT5625_PWR_MANAG_ADD3, 3, 0, NULL, 0), -SND_SOC_DAPM_PGA("Mic2 PGA", RT5625_PWR_MANAG_ADD3, 2, 0, NULL, 0), -SND_SOC_DAPM_PGA("VoDAC PGA", RT5625_PWR_MANAG_ADD1, 7, 0, NULL, 0), -SND_SOC_DAPM_MIXER("Left Rec Mixer", RT5625_PWR_MANAG_ADD2, 1, 0, - &rt5625_left_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5625_left_adc_rec_mixer_controls)), -SND_SOC_DAPM_MIXER("Right Rec Mixer", RT5625_PWR_MANAG_ADD2, 0, 0, - &rt5625_right_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5625_right_adc_rec_mixer_controls)), -SND_SOC_DAPM_MIXER_E("Left HP Mixer", RT5625_PWR_MANAG_ADD2, 5, 0, - &rt5625_left_hp_mixer_controls[0], ARRAY_SIZE(rt5625_left_hp_mixer_controls), - mixer_event, SND_SOC_DAPM_POST_REG), -SND_SOC_DAPM_MIXER_E("Right HP Mixer", RT5625_PWR_MANAG_ADD2, 4, 0, - &rt5625_right_hp_mixer_controls[0], ARRAY_SIZE(rt5625_right_hp_mixer_controls), - mixer_event, SND_SOC_DAPM_POST_REG), -SND_SOC_DAPM_MIXER("MoNo Mixer", RT5625_PWR_MANAG_ADD2, 2, 0, - &rt5625_mono_mixer_controls[0], ARRAY_SIZE(rt5625_mono_mixer_controls)), -SND_SOC_DAPM_MIXER("SPK Mixer", RT5625_PWR_MANAG_ADD2, 3, 0, - &rt5625_spk_mixer_controls[0], ARRAY_SIZE(rt5625_spk_mixer_controls)), -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, &rt5625_spkout_mux_out_controls), -SND_SOC_DAPM_MUX("HPLOUT Mux", SND_SOC_NOPM, 0, 0, &rt5625_hplout_mux_out_controls), -SND_SOC_DAPM_MUX("HPROUT Mux", SND_SOC_NOPM, 0, 0, &rt5625_hprout_mux_out_controls), -SND_SOC_DAPM_MUX("AUXOUT Mux", SND_SOC_NOPM, 0, 0, &rt5625_auxout_mux_out_controls), - -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",RT5625_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", RT5625_PWR_MANAG_ADD2, 7, 0), -SND_SOC_DAPM_ADC("Right ADC", "Right ADC HiFi Capture", RT5625_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", RT5625_PWR_MANAG_ADD1, 3, 0), -SND_SOC_DAPM_MICBIAS("Mic2 Bias", RT5625_PWR_MANAG_ADD1, 2, 0), -}; +static const char *rt5625_pll_sel[] = {"Disable", "11.2896->22.5792", "11.2896->24.576"}; -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"}, +static const SOC_ENUM_SINGLE_DECL(rt5625_pll_sel_enum, 0, 0, rt5625_pll_sel); - /*aux out mux*/ - {"AUXOUT Mux", "HP Mixer", "HP Mixer"}, - {"AUXOUT Mux", "SPK Mixer", "SPK Mixer"}, - {"AUXOUT Mux", "Mono Mixer", "MoNo Mixer"}, +static const char *rt5625_pll2_sel[] = {"Disable", "Enable"}; - /*spkl out pga*/ - {"SPKL Out PGA", NULL, "SPKOUT Mux"}, +static const SOC_ENUM_SINGLE_DECL(rt5625_pll2_sel_enum, 0, 0, rt5625_pll2_sel); +#endif - /*spkr out pga*/ - {"SPKR Out PGA", NULL, "SPKOUT Mux"}, - - /*hpl out pga*/ - {"HPL Out PGA", NULL, "HPLOUT Mux"}, +static const char *rt5625_AUXOUT_mode[] = {"Differential mode", "Single-ended mode"}; +static const char *rt5625_Differential_Input_Control[] = {"Disable", "Enable"}; - /*hpr out pga*/ - {"HPR Out PGA", NULL, "HPROUT Mux"}, +static const struct soc_enum rt5625_differential_enum[] = { +SOC_ENUM_SINGLE(RT5625_OUTMIX_CTRL, 4, 2, rt5625_AUXOUT_mode), /*0*/ +SOC_ENUM_SINGLE(RT5625_PHONEIN_VOL, 13, 2, rt5625_Differential_Input_Control),/*1*/ +SOC_ENUM_SINGLE(RT5625_MIC_VOL, 15, 2, rt5625_Differential_Input_Control), /*2*/ +SOC_ENUM_SINGLE(RT5625_MIC_VOL, 7, 2, rt5625_Differential_Input_Control), /*3*/ +}; - /*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 const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -3525, 75, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dmic_bst_tlv, 0, 600, 0); +/* {0, +20, +30, +40} dB */ +static unsigned int mic_bst_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0), }; +#ifdef RT5625_REG_RW +#define REGVAL_MAX 0xffff +static unsigned int regctl_addr = 0x3e; +static int rt5625_regctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = REGVAL_MAX; + return 0; +} -static int rt5625_add_widgets(struct snd_soc_codec *codec) +static int rt5625_regctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - snd_soc_dapm_new_controls(codec, rt5625_dapm_widgets, - ARRAY_SIZE(rt5625_dapm_widgets)); - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - snd_soc_dapm_new_widgets(codec); + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = regctl_addr; + ucontrol->value.integer.value[1] = snd_soc_read(codec, regctl_addr); + return 0; +} +static int rt5625_regctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + regctl_addr = ucontrol->value.integer.value[0]; + if(ucontrol->value.integer.value[1] <= REGVAL_MAX) + snd_soc_write(codec, regctl_addr, ucontrol->value.integer.value[1]); return 0; } +#endif -struct _pll_div{ - u32 pll_in; - u32 pll_out; - u16 regvalue; +static const struct snd_kcontrol_new rt5625_snd_controls[] = { + SOC_DOUBLE_TLV("SPKOUT Playback Volume", RT5625_SPK_OUT_VOL, + RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 1, out_vol_tlv), + SOC_DOUBLE("SPKOUT Playback Switch", RT5625_SPK_OUT_VOL, + RT5625_L_MUTE_SFT, RT5625_R_MUTE_SFT, 1, 1), + SOC_ENUM("SPK Amp Type", rt5625_spk_out_enum), + SOC_ENUM("Left SPK Source", rt5625_spkl_src_enum), + SOC_ENUM("SPK Amp Ratio", rt5625_spkamp_ratio_enum), + //SOC_DOUBLE_TLV("Headphone Playback Volume", RT5625_HP_OUT_VOL, + // RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 1, out_vol_tlv), + //SOC_DOUBLE("Headphone Playback Switch", RT5625_HP_OUT_VOL, + // RT5625_L_MUTE_SFT, RT5625_R_MUTE_SFT, 1, 1), + //SOC_ENUM("AUXOUT Mode Control", rt5625_auxout_mode_enum), + SOC_DOUBLE_TLV("AUXOUT Playback Volume", RT5625_AUX_OUT_VOL, + RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 1, out_vol_tlv), + SOC_DOUBLE("AUXOUT Playback Switch", RT5625_AUX_OUT_VOL, + RT5625_L_MUTE_SFT, RT5625_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("PCM Playback Volume", RT5625_DAC_VOL, + RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 63, 1, dmic_bst_tlv), + //SOC_ENUM("Phone Mode Control", rt5625_phone_mode_enum), + SOC_SINGLE_TLV("Phone Playback Volume", RT5625_PHONEIN_VOL, + RT5625_L_VOL_SFT, 31, 1, in_vol_tlv), + //SOC_ENUM("MIC1 Mode Control", rt5625_mic1_mode_enum), + SOC_SINGLE_TLV("MIC1 Boost", RT5625_MIC_CTRL, + RT5625_MIC1_BST_SFT, 3, 0, mic_bst_tlv), + SOC_SINGLE_TLV("Mic1 Playback Volume", RT5625_MIC_VOL, + RT5625_L_VOL_SFT, 31, 1, in_vol_tlv), + //SOC_ENUM("MIC2 Mode Control", rt5625_mic2_mode_enum), + SOC_SINGLE_TLV("MIC2 Boost", RT5625_MIC_CTRL, + RT5625_MIC2_BST_SFT, 3, 0, mic_bst_tlv), + SOC_SINGLE_TLV("Mic2 Playback Volume", RT5625_MIC_VOL, + RT5625_R_VOL_SFT, 31, 1, in_vol_tlv), + SOC_SINGLE_TLV("Dmic Boost", RT5625_DMIC_CTRL, + RT5625_DIG_BST_SFT, 7, 0, dmic_bst_tlv), + SOC_DOUBLE_TLV("LineIn Playback Volume", RT5625_LINE_IN_VOL, + RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 1, in_vol_tlv), + SOC_DOUBLE_TLV("PCM Capture Volume", RT5625_ADC_REC_GAIN, + RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 0, adc_vol_tlv), + //SOC_DOUBLE_TLV("ADC Record Gain", RT5625_ADC_REC_GAIN, + // RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 0, adc_vol_tlv), + /* This item does'nt affect path connected; only for clock choosen */ + SOC_ENUM_EXT("ADCR fun select Control", adcr_fun_sel_enum, + snd_soc_get_enum_double, rt5625_adcr_fun_sel_put), + SOC_ENUM_EXT("ADCL fun select Control", adcl_fun_sel_enum, + snd_soc_get_enum_double, rt5625_adcl_fun_sel_put), + + /* Voice DSP */ + SOC_ENUM_EXT("VoDSP AEC", rt5625_aec_fun_enum, + rt5625_aec_get, rt5625_aec_put), + SOC_ENUM("VoDSP LRCK Control", rt5625_dsp_lrck_enum), + SOC_ENUM("VoDSP BP Pin Control", rt5625_bp_ctrl_enum), + SOC_ENUM("VoDSP Power Down Pin Control", rt5625_pd_ctrl_enum), + SOC_ENUM("VoDSP Reset Pin Control", rt5625_rst_ctrl_enum), + +#ifdef RT5625_F_SMT_PHO + SOC_SINGLE_EXT("VoDSP Dump", 0, 0, 1, 0, rt5625_dump_dsp_get, NULL), + SOC_SINGLE_EXT("DAC Switch", 0, 0, 1, 0, rt5625_dac_active_get, rt5625_dac_active_put), + SOC_SINGLE_EXT("ADC Switch", 0, 0, 1, 0, rt5625_adc_active_get, rt5625_adc_active_put), + SOC_ENUM_EXT("PLL Switch", rt5625_pll_sel_enum, rt5625_pll_get, rt5625_pll_put), + SOC_ENUM_EXT("PLL2 Switch", rt5625_pll2_sel_enum, rt5625_pll2_get, rt5625_pll2_put), + SOC_SINGLE_EXT("VoIP Check", 0, 0, 1, 0, rt5625_voip_get, rt5625_voip_chk_put), + SOC_SINGLE_EXT("VoIP Switch", 0, 0, 1, 0, rt5625_voip_get, rt5625_voip_put), + SOC_SINGLE_EXT("Capture VoIP Check", 0, 0, 1, 0, rt5625_voip_get, rt5625_cap_voip_chk_put), + SOC_SINGLE_EXT("Capture VoIP Switch", 0, 0, 1, 0, rt5625_voip_get, rt5625_cap_voip_put), + SOC_SINGLE_EXT("Headset VoIP Check", 0, 0, 1, 0, rt5625_voip_get, rt5625_hs_voip_chk_put), + SOC_SINGLE_EXT("Headset VoIP Switch", 0, 0, 1, 0, rt5625_voip_get, rt5625_hs_voip_put), + SOC_SINGLE_EXT("Playback Switch", 0, 0, 1, 0, rt5625_play_get, rt5625_play_put), + SOC_SINGLE_EXT("Record Switch", 0, 0, 1, 0, rt5625_rec_get, rt5625_rec_put), + SOC_SINGLE_EXT("BT Switch", 0, 0, 1, 0, rt5625_bt_get, rt5625_bt_put), + SOC_SINGLE_EXT("3G Switch", 0, 0, 1, 0, rt5625_3g_get, rt5625_3g_put), + SOC_SINGLE_EXT("Headset 3G Switch", 0, 0, 1, 0, rt5625_3g_get, rt5625_hs_3g_put), + SOC_SINGLE_EXT("APP disp", 0, 0, 1, 0, rt5625_app_get, NULL), +#endif + //SOC_DOUBLE_TLV("SPKOUT Playback Volume", RT5625_SPK_OUT_VOL, + // RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 1, out_vol_tlv), + //SOC_DOUBLE("SPKOUT Playback Switch", RT5625_SPK_OUT_VOL, + // RT5625_L_MUTE_SFT, RT5625_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("HPOUT Playback Volume", RT5625_HP_OUT_VOL, + RT5625_L_VOL_SFT, RT5625_R_VOL_SFT, 31, 1, out_vol_tlv), + SOC_DOUBLE("HPOUT Playback Switch", RT5625_HP_OUT_VOL, + RT5625_L_MUTE_SFT, RT5625_R_MUTE_SFT, 1, 1), + SOC_ENUM("AUXOUT mode switch", rt5625_differential_enum[0]), + SOC_ENUM("Phone Differential Input Control", rt5625_differential_enum[1]), + SOC_ENUM("MIC1 Differential Input Control", rt5625_differential_enum[2]), + SOC_ENUM("MIC2 Differential Input Control", rt5625_differential_enum[3]), + +#ifdef RT5625_REG_RW + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Register Control", + .info = rt5625_regctl_info, + .get = rt5625_regctl_get, + .put = rt5625_regctl_put, + }, +#endif }; -/************************************************************** - * 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}, - { 11289600, 24576000, 0x950F}, - { 12000000, 24576000, 0x2915}, - { 12288000, 24576000, 0x0600}, - { 13000000, 24576000, 0x772e}, - { 13100000, 24576000, 0x0d20}, - { 26000000, 24576000, 0x2027}, - { 26000000, 22579200, 0x392f}, - { 24576000, 22579200, 0x0921}, - { 24576000, 24576000, 0x02a0}, + /*Left ADC Rec mixer*/ +static const struct snd_kcontrol_new rt5625_adcl_rec_mixer[] = { + SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MIC1_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MIC2_SFT, 1, 1), + SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_LINE_SFT, 1, 1), + SOC_DAPM_SINGLE("Phone Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_PHO_SFT, 1, 1), + SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_L_MM_SFT, 1, 1), }; -static const struct _pll_div codec_bclk_pll1_div[] = { +/*Right ADC Rec mixer*/ +static const struct snd_kcontrol_new rt5625_adcr_rec_mixer[] = { + SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_MIC1_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_MIC2_SFT, 1, 1), + SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_LINE_SFT, 1, 1), + SOC_DAPM_SINGLE("Phone Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_PHO_SFT, 1, 1), + SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, + RT5625_M_RM_R_MM_SFT, 1, 1), +}; - { 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}, - { 2822400, 11289600, 0x1ee0}, - { 3072000, 12288000, 0x1ee0}, +/* HP Mixer for mono input */ +static const struct snd_kcontrol_new rt5625_hp_mixer[] = { + SOC_DAPM_SINGLE("LineIn Playback Switch", RT5625_LINE_IN_VOL, + RT5625_M_LI_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("Phone Playback Switch", RT5625_PHONEIN_VOL, + RT5625_M_PHO_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_MIC1_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_MIC2_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("Voice DAC Playback Switch", RT5625_VDAC_OUT_VOL, + RT5625_M_VDAC_HM_SFT, 1, 1), }; -static const struct _pll_div codec_vbclk_pll1_div[] = { +/* Left HP Mixer */ +static const struct snd_kcontrol_new rt5625_hpl_mixer[] = { + SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_ADC_REC_GAIN, + RT5625_M_ADCL_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_DACL_HM_SFT, 1, 1), +}; - { 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}, +/* Right HP Mixer */ +static const struct snd_kcontrol_new rt5625_hpr_mixer[] = { + SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_ADC_REC_GAIN, + RT5625_M_ADCR_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_DACR_HM_SFT, 1, 1), }; +/* Mono Mixer */ +static const struct snd_kcontrol_new rt5625_mono_mixer[] = { + SOC_DAPM_SINGLE("ADCL Playback Switch", RT5625_ADC_REC_GAIN, + RT5625_M_ADCL_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("ADCR Playback Switch", RT5625_ADC_REC_GAIN, + RT5625_M_ADCR_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, + RT5625_M_LI_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_MIC1_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_MIC2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC Mixer Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_DAC_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("Voice DAC Playback Switch", RT5625_VDAC_OUT_VOL, + RT5625_M_VDAC_MM_SFT, 1, 1), +}; -struct _coeff_div_stereo { - unsigned int mclk; - unsigned int rate; - unsigned int reg60; - unsigned int reg62; +/* Speaker Mixer */ +static const struct snd_kcontrol_new rt5625_spk_mixer[] = { + SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, + RT5625_M_LI_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("Phone Playback Switch", RT5625_PHONEIN_VOL, + RT5625_M_PHO_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_MIC1_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_MIC2_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC Mixer Playback Switch", RT5625_DAC_MIC_CTRL, + RT5625_M_DAC_SM_SFT, 1, 1), + SOC_DAPM_SINGLE("Voice DAC Playback Switch", RT5625_VDAC_OUT_VOL, + RT5625_M_VDAC_SM_SFT, 1, 1), }; -struct _coeff_div_voice { - unsigned int mclk; +static int rt5625_dac_func_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_REG: + snd_soc_update_bits(codec, RT5625_PD_CTRL, + RT5625_PWR_PR1, RT5625_PWR_PR1); + break; + + case SND_SOC_DAPM_POST_REG: + snd_soc_update_bits(codec, RT5625_PD_CTRL, + RT5625_PWR_PR1, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5625_hpmix_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5625_PWR_ADD2, + RT5625_P_HM_L | RT5625_P_HM_R, 0); + break; + + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5625_PWR_ADD2, + RT5625_P_HM_L | RT5625_P_HM_R, + RT5625_P_HM_L | RT5625_P_HM_R); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5625_vodsp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + //pr_info("%s(): PMD\n", __func__); + snd_soc_update_bits(codec, RT5625_VODSP_CTL, + RT5625_DSP_PD_MASK, RT5625_DSP_PD_EN); + snd_soc_update_bits(codec, RT5625_PWR_ADD3, + RT5625_P_DSP_IF | RT5625_P_DSP_I2C, 0); + snd_soc_update_bits(codec, RT5625_LDO_CTRL, + RT5625_LDO_MASK, RT5625_LDO_DIS); + break; + + case SND_SOC_DAPM_POST_PMU: + //pr_info("%s(): PMU\n", __func__); + if(rt5625->vodsp_fun == RT5625_AEC_EN) + rt5625_init_vodsp_aec(codec); + //pr_info("[DSP poweron] 0x%04x: 0x%04x\n", 0x230C, rt5625_dsp_read(codec, 0x230C)); + break; + + default: + return 0; + } + + return 0; +} + + +static void hp_depop_mode2(struct snd_soc_codec *codec) +{ + snd_soc_update_bits(codec, RT5625_PWR_ADD1, + RT5625_P_SG_EN, RT5625_P_SG_EN); + snd_soc_update_bits(codec, RT5625_PWR_ADD3, + RT5625_P_HPL_VOL | RT5625_P_HPR_VOL, + RT5625_P_HPL_VOL | RT5625_P_HPR_VOL); + snd_soc_write(codec, RT5625_MISC_CTRL, RT5625_HP_DEPOP_M2); + schedule_timeout_uninterruptible(msecs_to_jiffies(500)); + snd_soc_update_bits(codec, RT5625_PWR_ADD1, + RT5625_P_HPO_AMP | RT5625_P_HPO_ENH, + RT5625_P_HPO_AMP | RT5625_P_HPO_ENH); +} + +/* enable depop function for mute/unmute */ +static void hp_mute_unmute_depop(struct snd_soc_codec *codec,int mute) +{ + if(mute) { + snd_soc_update_bits(codec, RT5625_PWR_ADD1, + RT5625_P_SG_EN, RT5625_P_SG_EN); + snd_soc_write(codec, RT5625_MISC_CTRL, RT5625_MUM_DEPOP | + RT5625_HPR_MUM_DEPOP | RT5625_HPL_MUM_DEPOP); + snd_soc_update_bits(codec, RT5625_HP_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, + RT5625_L_MUTE | RT5625_R_MUTE); + mdelay(50); + snd_soc_update_bits(codec, RT5625_PWR_ADD1, RT5625_P_SG_EN, 0); + } else { + snd_soc_update_bits(codec, RT5625_PWR_ADD1, + RT5625_P_SG_EN, RT5625_P_SG_EN); + snd_soc_write(codec, RT5625_MISC_CTRL, RT5625_MUM_DEPOP | + RT5625_HPR_MUM_DEPOP | RT5625_HPL_MUM_DEPOP); + snd_soc_update_bits(codec,RT5625_HP_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, 0); + mdelay(50); + } +} + +static int rt5625_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = w->codec; + + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + hp_mute_unmute_depop(codec,1); + snd_soc_update_bits(codec, RT5625_PWR_ADD1, + RT5625_P_HPO_AMP | RT5625_P_HPO_ENH, 0); + snd_soc_update_bits(codec, RT5625_PWR_ADD3, + RT5625_P_HPL_VOL | RT5625_P_HPR_VOL, 0); + break; + + case SND_SOC_DAPM_POST_PMU: + hp_depop_mode2(codec); + hp_mute_unmute_depop(codec,0); + break; + + default: + return 0; + } + + return 0; +} + +/* DAC function select MUX */ +static const char *dac_fun_sel[] = { + "Stereo DAC", "SRC2 Out", "TxDP", "TxDC"}; + +static const struct soc_enum dac_fun_sel_enum = + SOC_ENUM_SINGLE(RT5625_F_DAC_ADC_VDAC, RT5625_DAC_F_SFT, + ARRAY_SIZE(dac_fun_sel), dac_fun_sel); + +static const struct snd_kcontrol_new dac_fun_sel_mux = + SOC_DAPM_ENUM("DAC Function Select Mux", dac_fun_sel_enum); + +/* Voice DAC source select MUX */ +static const char *vdac_src_sel[] = { + "Voice PCM", "SRC2 Out", "TxDP", "TxDC"}; + +static const struct soc_enum vdac_src_sel_enum = + SOC_ENUM_SINGLE(RT5625_F_DAC_ADC_VDAC, RT5625_VDAC_S_SFT, + ARRAY_SIZE(vdac_src_sel), vdac_src_sel); + +static const struct snd_kcontrol_new vdac_src_sel_mux = + SOC_DAPM_ENUM("Voice DAC Source Mux", vdac_src_sel_enum); + +/* SRC1 power switch */ +static const struct snd_kcontrol_new src1_pwr_sw_control = + SOC_DAPM_SINGLE("Switch", RT5625_VODSP_PDM_CTL, + RT5625_SRC1_PWR_SFT, 1, 0); + +/* SRC2 power switch */ +static const struct snd_kcontrol_new src2_pwr_sw_control = + SOC_DAPM_SINGLE("Switch", RT5625_VODSP_PDM_CTL, + RT5625_SRC2_PWR_SFT, 1, 0); + +/* SRC2 source select MUX */ +static const char *src2_src_sel[] = {"TxDP", "TxDC"}; + +static const struct soc_enum src2_src_sel_enum = + SOC_ENUM_SINGLE(RT5625_VODSP_PDM_CTL, RT5625_SRC2_S_SFT, + ARRAY_SIZE(src2_src_sel), src2_src_sel); + +static const struct snd_kcontrol_new src2_src_sel_mux = + SOC_DAPM_ENUM("SRC2 Source Mux", src2_src_sel_enum); + +/* VoDSP RxDP power switch */ +static const struct snd_kcontrol_new rxdp_pwr_sw_control = + SOC_DAPM_SINGLE("Switch", RT5625_VODSP_PDM_CTL, + RT5625_RXDP_PWR_SFT, 1, 0); +/* VoDSP RxDC power switch */ +static const struct snd_kcontrol_new rxdc_pwr_sw_control = + SOC_DAPM_SINGLE("Switch", RT5625_VODSP_PDM_CTL, + RT5625_RXDC_PWR_SFT, 1, 0); + +/* VoDSP RxDP source select MUX */ +static const char *rxdp_src_sel[] = {"SRC1 Output", "ADCL to VoDSP", + "Voice to Stereo", "ADCR to VoDSP"}; + +static const struct soc_enum rxdp_src_sel_enum = + SOC_ENUM_SINGLE(RT5625_VODSP_PDM_CTL, RT5625_RXDP_S_SFT, + ARRAY_SIZE(rxdp_src_sel), rxdp_src_sel); + +static const struct snd_kcontrol_new rxdp_src_sel_mux = + SOC_DAPM_ENUM("RxDP Source Mux", rxdp_src_sel_enum); + +/* PCM source select MUX */ +static const char *pcm_src_sel[] = {"ADCR", "TxDP"}; + +static const struct soc_enum pcm_src_sel_enum = + SOC_ENUM_SINGLE(RT5625_VODSP_PDM_CTL, RT5625_PCM_S_SFT, + ARRAY_SIZE(pcm_src_sel), pcm_src_sel); + +static const struct snd_kcontrol_new pcm_src_sel_mux = + SOC_DAPM_ENUM("PCM Source Mux", pcm_src_sel_enum); + +/* Main stereo record I2S source select MUX */ +static const char *rec_iis_src_sel[] = {"ADC", "Voice to Stereo", "SRC2 Output"}; + +static const struct soc_enum rec_iis_src_enum = + SOC_ENUM_SINGLE(RT5625_VODSP_PDM_CTL, RT5625_REC_IIS_S_SFT, + ARRAY_SIZE(rec_iis_src_sel), rec_iis_src_sel); + +static const struct snd_kcontrol_new rec_iis_src_mux = + SOC_DAPM_ENUM("REC I2S Source Mux", rec_iis_src_enum); + +/* SPK volume input select MUX */ +static const char *spkvol_input_sel[] = {"VMID", "HP Mixer", "SPK Mixer", "Mono Mixer"}; + +static const struct soc_enum spkvol_input_enum = + SOC_ENUM_SINGLE(RT5625_OUTMIX_CTRL, RT5625_SPKVOL_S_SFT, + ARRAY_SIZE(spkvol_input_sel), spkvol_input_sel); + +static const struct snd_kcontrol_new spkvol_input_mux = + SOC_DAPM_ENUM("SPK Vol Input Mux", spkvol_input_enum); + +/* HP volume input select MUX */ +static const char *hpvol_input_sel[] = {"VMID", "HP Mixer"}; + +static const struct soc_enum hplvol_input_enum = + SOC_ENUM_SINGLE(RT5625_OUTMIX_CTRL, RT5625_HPVOL_L_S_SFT, + ARRAY_SIZE(hpvol_input_sel), hpvol_input_sel); + +static const struct snd_kcontrol_new hplvol_input_mux = + SOC_DAPM_ENUM("HPL Vol Input Mux", hplvol_input_enum); + +static const struct soc_enum hprvol_input_enum = + SOC_ENUM_SINGLE(RT5625_OUTMIX_CTRL, RT5625_HPVOL_R_S_SFT, + ARRAY_SIZE(hpvol_input_sel), hpvol_input_sel); + +static const struct snd_kcontrol_new hprvol_input_mux = + SOC_DAPM_ENUM("HPR Vol Input Mux", hprvol_input_enum); + +/* AUX volume input select MUX */ +static const struct soc_enum auxvol_input_enum = + SOC_ENUM_SINGLE(RT5625_OUTMIX_CTRL, RT5625_AUXVOL_S_SFT, + ARRAY_SIZE(spkvol_input_sel), spkvol_input_sel); + +static const struct snd_kcontrol_new auxvol_input_mux = + SOC_DAPM_ENUM("AUX Vol Input Mux", auxvol_input_enum); + +static const struct snd_soc_dapm_widget rt5625_dapm_widgets[] = { + /* supply */ + SND_SOC_DAPM_SUPPLY("IIS Interface", RT5625_PWR_ADD1, + RT5625_P_I2S_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL1", RT5625_PWR_ADD2, + RT5625_P_PLL1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL2", RT5625_PWR_ADD2, + RT5625_P_PLL2_BIT, 0, NULL, 0), + SND_SOC_DAPM_VMID("VMID"), + SND_SOC_DAPM_SUPPLY("DAC Ref", RT5625_PWR_ADD1, + RT5625_P_DAC_REF_BIT, 0, NULL, 0), + /* microphone bias */ + SND_SOC_DAPM_MICBIAS("Mic1 Bias", RT5625_PWR_ADD1, + RT5625_P_MB1_BIT, 0), + SND_SOC_DAPM_MICBIAS("Mic2 Bias", RT5625_PWR_ADD1, + RT5625_P_MB2_BIT, 0), + + /* Input */ + 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", RT5625_PWR_ADD3, + RT5625_P_MIC1_BST_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Boost", RT5625_PWR_ADD3, + RT5625_P_MIC2_BST_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Phone Rec Mixer", RT5625_PWR_ADD3, + RT5625_P_PH_ADMIX_BIT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("Left Rec Mixer", RT5625_PWR_ADD2, + RT5625_P_ADCL_RM_BIT, 0, rt5625_adcl_rec_mixer, + ARRAY_SIZE(rt5625_adcl_rec_mixer)), + SND_SOC_DAPM_MIXER("Right Rec Mixer", RT5625_PWR_ADD2, + RT5625_P_ADCR_RM_BIT, 0, rt5625_adcr_rec_mixer, + ARRAY_SIZE(rt5625_adcr_rec_mixer)), + + SND_SOC_DAPM_ADC("Left ADC", NULL, RT5625_PWR_ADD2, + RT5625_P_ADCL_BIT, 0), + SND_SOC_DAPM_ADC("Right ADC", NULL, RT5625_PWR_ADD2, + RT5625_P_ADCR_BIT, 0), + SND_SOC_DAPM_MUX("PCM src select Mux", SND_SOC_NOPM, 0, 0, + &pcm_src_sel_mux), + SND_SOC_DAPM_MUX("IIS src select Mux", SND_SOC_NOPM, 0, 0, + &rec_iis_src_mux), + + /* Input Stream Audio Interface */ + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 HiFi Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Voice Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Voice DSP */ + SND_SOC_DAPM_MUX("SRC2 src select Mux", SND_SOC_NOPM, 0, 0, + &src2_src_sel_mux), + SND_SOC_DAPM_SWITCH("SRC1 Enable", SND_SOC_NOPM, 0, 0, + &src1_pwr_sw_control), + SND_SOC_DAPM_SWITCH("SRC2 Enable", SND_SOC_NOPM, 0, 0, + &src2_pwr_sw_control), + SND_SOC_DAPM_SWITCH("RxDP Enable", SND_SOC_NOPM, 0, 0, + &rxdp_pwr_sw_control), + SND_SOC_DAPM_SWITCH("RxDC Enable", SND_SOC_NOPM, 0, 0, + &rxdc_pwr_sw_control), + + SND_SOC_DAPM_MUX("RxDP src select Mux", SND_SOC_NOPM, 0, 0, + &rxdp_src_sel_mux), + + SND_SOC_DAPM_PGA("TxDP", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("TxDC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("PDM", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("RxDP", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("RxDC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("Voice DSP", SND_SOC_NOPM, + 0, 0, NULL, 0, rt5625_vodsp_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + + /* Output */ + /* Output Stream Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 HiFi Playback", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Voice Playback", + 0, SND_SOC_NOPM, 0, 0), + + /* DAC function select Mux */ + SND_SOC_DAPM_MUX_E("DAC fun Mux", SND_SOC_NOPM, 0, 0, + &dac_fun_sel_mux, rt5625_dac_func_event, + SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG), + /* VDAC source select Mux */ + SND_SOC_DAPM_MUX_E("VDAC src Mux", SND_SOC_NOPM, 0, 0, + &vdac_src_sel_mux, rt5625_dac_func_event, + SND_SOC_DAPM_PRE_REG | SND_SOC_DAPM_POST_REG), + + SND_SOC_DAPM_DAC("Left DAC", NULL, RT5625_PWR_ADD2, + RT5625_P_DACL_BIT, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, RT5625_PWR_ADD2, + RT5625_P_DACR_BIT, 0), + SND_SOC_DAPM_DAC("Voice DAC", NULL, RT5625_PWR_ADD2, + RT5625_P_VDAC_BIT, 0), + + SND_SOC_DAPM_PGA("Mic1 Volume", RT5625_PWR_ADD3, + RT5625_P_MIC1_VOL_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Volume", RT5625_PWR_ADD3, + RT5625_P_MIC2_VOL_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left LineIn Volume", RT5625_PWR_ADD3, + RT5625_P_LV_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right LineIn Volume", RT5625_PWR_ADD3, + RT5625_P_LV_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Phone Volume", RT5625_PWR_ADD3, + RT5625_P_PH_VOL_BIT, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Left DAC To Mixer", RT5625_PWR_ADD1, + RT5625_P_DACL_MIX_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right DAC To Mixer", RT5625_PWR_ADD1, + RT5625_P_DACR_MIX_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("Voice DAC To Mixer", RT5625_PWR_ADD1, + RT5625_P_VDAC_MIX_BIT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("SPK Mixer", RT5625_PWR_ADD2, + RT5625_P_SM_BIT, 0, rt5625_spk_mixer, + ARRAY_SIZE(rt5625_spk_mixer)), + SND_SOC_DAPM_MIXER("Mono HP Mixer", SND_SOC_NOPM, 0, 0, + rt5625_hp_mixer, ARRAY_SIZE(rt5625_hp_mixer)), + SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0, + rt5625_hpl_mixer, ARRAY_SIZE(rt5625_hpl_mixer)), + SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0, + rt5625_hpr_mixer, ARRAY_SIZE(rt5625_hpr_mixer)), + SND_SOC_DAPM_MIXER("Mono Mixer", RT5625_PWR_ADD2, + RT5625_P_MM_BIT, 0, rt5625_mono_mixer, + ARRAY_SIZE(rt5625_mono_mixer)), + + SND_SOC_DAPM_MIXER_E("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0, + rt5625_hpmix_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + 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("SPK Vol Input Mux", SND_SOC_NOPM, + 0, 0, &spkvol_input_mux), + SND_SOC_DAPM_SUPPLY("SPKL Vol", RT5625_PWR_ADD3, + RT5625_P_SPKL_VOL_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("SPKR Vol", RT5625_PWR_ADD3, + RT5625_P_SPKR_VOL_BIT, 0, NULL, 0), + SND_SOC_DAPM_MUX("HPL Vol Input Mux", RT5625_PWR_ADD3, + RT5625_P_HPL_VOL_BIT, 0, &hplvol_input_mux), + SND_SOC_DAPM_MUX("HPR Vol Input Mux", RT5625_PWR_ADD3, + RT5625_P_HPR_VOL_BIT, 0, &hprvol_input_mux), + SND_SOC_DAPM_MUX("AUX Vol Input Mux", RT5625_PWR_ADD3, + RT5625_P_AUX_VOL_BIT, 0, &auxvol_input_mux), + + SND_SOC_DAPM_SUPPLY("SPK Amp", RT5625_PWR_ADD1, + RT5625_P_SPK_AMP_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA_E("HP Amp", SND_SOC_NOPM, 0, 0, NULL, 0, + rt5625_hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + + 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"), +}; + +static const struct snd_soc_dapm_route rt5625_dapm_routes[] = { + {"DAC Ref", NULL, "IIS Interface"}, + {"DAC Ref", NULL, "PLL1"}, + {"DAC Ref", NULL, "PLL2"}, + + /* Input */ + {"Phone Rec Mixer", NULL, "Phone"}, + {"Mic1 Boost", NULL, "Mic1"}, + {"Mic2 Boost", NULL, "Mic2"}, + + {"Left Rec Mixer", "LineIn Capture Switch", "Left LineIn"}, + {"Left Rec Mixer", "Phone Capture Switch", "Phone Rec Mixer"}, + {"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 Rec Mixer", "LineIn Capture Switch", "Right LineIn"}, + {"Right Rec Mixer", "Phone Capture Switch", "Phone Rec Mixer"}, + {"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"}, + + {"Left ADC", NULL, "DAC Ref"}, + {"Left ADC", NULL, "Left Rec Mixer"}, + {"Right ADC", NULL, "DAC Ref"}, + {"Right ADC", NULL, "Right Rec Mixer"}, + + {"PCM src select Mux", "TxDP", "TxDP"}, + {"PCM src select Mux", "ADCR", "Right ADC"}, + + {"IIS src select Mux", "ADC", "Left ADC"}, + {"IIS src select Mux", "ADC", "Right ADC"}, + {"IIS src select Mux", "Voice to Stereo", "AIF2RX"}, + {"IIS src select Mux", "SRC2 Output", "SRC2 Enable"}, + + {"AIF2TX", NULL, "IIS Interface"}, + {"AIF2TX", NULL, "PCM src select Mux"}, + {"AIF1TX", NULL, "IIS Interface"}, + {"AIF1TX", NULL, "IIS src select Mux"}, + + /* Output */ + {"AIF1RX", NULL, "IIS Interface"}, + {"AIF2RX", NULL, "IIS Interface"}, + + {"DAC fun Mux", "SRC2 Out", "SRC2 Enable"}, + {"DAC fun Mux", "TxDP", "TxDP"}, + {"DAC fun Mux", "TxDC", "TxDC"}, + {"DAC fun Mux", "Stereo DAC", "AIF1RX"}, + + {"VDAC src Mux", "SRC2 Out", "SRC2 Enable"}, + {"VDAC src Mux", "TxDP", "TxDP"}, + {"VDAC src Mux", "TxDC", "TxDC"}, + {"VDAC src Mux", "Voice PCM", "AIF2RX"}, + + {"Left DAC", NULL, "DAC Ref"}, + {"Left DAC", NULL, "DAC fun Mux"}, + {"Right DAC", NULL, "DAC Ref"}, + {"Right DAC", NULL, "DAC fun Mux"}, + {"Voice DAC", NULL, "DAC Ref"}, + {"Voice DAC", NULL, "VDAC src Mux"}, + + {"Left LineIn Volume", NULL, "Left LineIn"}, + {"Right LineIn Volume", NULL, "Right LineIn"}, + {"Phone Volume", NULL, "Phone"}, + {"Mic1 Volume", NULL, "Mic1 Boost"}, + {"Mic2 Volume", NULL, "Mic2 Boost"}, + + {"Left DAC To Mixer", NULL, "Left DAC"}, + {"Right DAC To Mixer", NULL, "Right DAC"}, + {"Voice DAC To Mixer", NULL, "Voice DAC"}, + + {"DAC Mixer", NULL, "Left DAC To Mixer"}, + {"DAC Mixer", NULL, "Right DAC To Mixer"}, + {"Line Mixer", NULL, "Left LineIn Volume"}, + {"Line Mixer", NULL, "Right LineIn Volume"}, + + {"Mono HP Mixer", "LineIn Playback Switch", "Line Mixer"}, + {"Mono HP Mixer", "Phone Playback Switch", "Phone Volume"}, + {"Mono HP Mixer", "Mic1 Playback Switch", "Mic1 Volume"}, + {"Mono HP Mixer", "Mic2 Playback Switch", "Mic2 Volume"}, + {"Mono HP Mixer", "Voice DAC Playback Switch", "Voice DAC To Mixer"}, + {"Left HP Mixer", "ADC Playback Switch", "Left Rec Mixer"}, + {"Left HP Mixer", "DAC Playback Switch", "Left DAC To Mixer"}, + {"Right HP Mixer", "ADC Playback Switch", "Right Rec Mixer"}, + {"Right HP Mixer", "DAC Playback Switch", "Right DAC To Mixer"}, + + {"SPK Mixer", "Line Mixer Playback Switch", "Line Mixer"}, + {"SPK Mixer", "Phone Playback Switch", "Phone Volume"}, + {"SPK Mixer", "Mic1 Playback Switch", "Mic1 Volume"}, + {"SPK Mixer", "Mic2 Playback Switch", "Mic2 Volume"}, + {"SPK Mixer", "DAC Mixer Playback Switch", "DAC Mixer"}, + {"SPK Mixer", "Voice DAC Playback Switch", "Voice DAC To 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 Volume"}, + {"Mono Mixer", "Mic2 Playback Switch", "Mic2 Volume"}, + {"Mono Mixer", "DAC Mixer Playback Switch", "DAC Mixer"}, + {"Mono Mixer", "Voice DAC Playback Switch", "Voice DAC To Mixer"}, + + {"HP Mixer", NULL, "Mono HP Mixer"}, + {"HP Mixer", NULL, "Left HP Mixer"}, + {"HP Mixer", NULL, "Right HP Mixer"}, + + {"SPK Vol Input Mux", "VMID", "VMID"}, + {"SPK Vol Input Mux", "HP Mixer", "HP Mixer"}, + {"SPK Vol Input Mux", "SPK Mixer", "SPK Mixer"}, + {"SPK Vol Input Mux", "Mono Mixer", "Mono Mixer"}, + {"SPK Vol Input Mux", NULL, "SPKL Vol"}, + {"SPK Vol Input Mux", NULL, "SPKR Vol"}, + + {"HPL Vol Input Mux", "HP Mixer", "HP Mixer"}, + {"HPL Vol Input Mux", "VMID", "VMID"}, + {"HP Amp", NULL, "HPL Vol Input Mux"}, + {"HPR Vol Input Mux", "HP Mixer", "HP Mixer"}, + {"HPR Vol Input Mux", "VMID", "VMID"}, + {"HP Amp", NULL, "HPR Vol Input Mux"}, + + {"AUX Vol Input Mux", "VMID", "VMID"}, + {"AUX Vol Input Mux", "HP Mixer", "HP Mixer"}, + {"AUX Vol Input Mux", "SPK Mixer", "SPK Mixer"}, + {"AUX Vol Input Mux", "Mono Mixer", "Mono Mixer"}, + + {"SPKL", NULL, "SPK Amp"}, + {"SPKL", NULL, "SPK Vol Input Mux"}, + {"SPKR", NULL, "SPK Amp"}, + {"SPKR", NULL, "SPK Vol Input Mux"}, + {"HPL", NULL, "HP Amp"}, + {"HPR", NULL, "HP Amp"}, + {"AUX", NULL, "AUX Vol Input Mux"}, + + /* Voice DSP */ + {"SRC1 Enable", "Switch", "AIF1RX"}, + + {"RxDP src select Mux", "Voice to Stereo", "AIF2RX"}, + {"RxDP src select Mux", "ADCL to VoDSP", "Left ADC"}, + {"RxDP src select Mux", "SRC1 Output", "SRC1 Enable"}, + {"RxDP src select Mux", "ADCR to VoDSP", "Right ADC"}, + + {"RxDP Enable", "Switch", "RxDP src select Mux"}, + {"RxDC Enable", "Switch", "Left ADC"}, + + {"RxDP", NULL, "RxDP Enable"}, + {"RxDC", NULL, "RxDC Enable"}, + {"PDM", NULL, "Right ADC"}, + + {"Voice DSP", NULL, "RxDP"}, + {"Voice DSP", NULL, "RxDC"}, + {"Voice DSP", NULL, "PDM"}, + + {"TxDP", NULL, "Voice DSP"}, + {"TxDC", NULL, "Voice DSP"}, + + {"SRC2 src select Mux", "TxDP", "TxDP"}, + {"SRC2 src select Mux", "TxDC", "TxDC"}, + {"SRC2 Enable", "Switch", "SRC2 src select Mux"}, +}; + +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}, + { 11289600, 24576000, 0x950F}, + { 12000000, 24576000, 0x2915}, + { 12288000, 24576000, 0x0600}, + { 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}, + { 2822400, 11289600, 0x1ee0}, + { 3072000, 12288000, 0x1ee0}, +}; + +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; }; +/* bclk is config to 32fs, if codec is choose to be slave mode, +input bclk should be 32*fs */ 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}, + {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}, + {12288000, 8000, 0xB174, 0x2222}, + {11289600, 44100, 0X3072, 0x0000}, }; +/* bclk is config to 32fs, if codec is choose to be slave mode, +input bclk should be 32*fs */ 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}, + {24576000, 16000, 0x2622}, + {24576000, 8000, 0x2824}, + {2048000,8000,0x3000}, }; static int get_coeff(unsigned int mclk, unsigned int rate, int mode) { int i; - DBG("get_coeff mclk = %d, rate = %d, mode = %d\n", mclk, rate, mode); + pr_info("mclk = %d, rate = %d, mode = %d\n", mclk, rate, mode); - if (!mode) { + 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)) + if ((coeff_div_stereo[i].rate == rate) && + (coeff_div_stereo[i].mclk == mclk)) return i; } - } else { + else for (i = 0; i< ARRAY_SIZE(coeff_div_voice); i++) { - if ((coeff_div_voice[i].rate == rate) && (coeff_div_voice[i].mclk == mclk)) + if ((coeff_div_voice[i].rate == rate) && + (coeff_div_voice[i].mclk == mclk)) return i; } - } - printk("can't find a matched mclk and rate in %s\n", + pr_err("can't find a matched mclk and rate in %s\n", (mode ? "coeff_div_voice[]" : "coeff_div_audio[]")); return -EINVAL; } -static int rt5625_codec_set_dai_pll(struct snd_soc_dai *codec_dai, - int pll_id, unsigned int freq_in, unsigned int freq_out) +static int rt5625_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) { - int i; - int ret = -EINVAL; - struct snd_soc_codec *codec = codec_dai->codec; - - DBG("enter %s pll_id = %d freq_in = %d freq_out = %d\n", - __func__, pll_id, freq_in, freq_out); + struct snd_soc_codec *codec = dai->codec; + int i, ret = -EINVAL; - if (pll_id < RT5625_PLL1_FROM_MCLK || pll_id > RT5625_PLL1_FROM_VBCLK) + if (pll_id < RT5625_PLL_MCLK || pll_id > RT5625_PLL_VBCLK) return -EINVAL; - if (!freq_in || !freq_out) + if (!freq_in || !freq_out) { + dev_info(dai->dev, "PLL is closed\n"); + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_MASK, RT5625_SCLK_MCLK); return 0; + } - if (RT5625_PLL1_FROM_MCLK == pll_id) { - + if (RT5625_PLL_MCLK == pll_id) { + for (i = 0; i < ARRAY_SIZE(codec_master_pll1_div); i ++) + if ((freq_in == codec_master_pll1_div[i].pll_in) && + (freq_out == codec_master_pll1_div[i].pll_out)) { + snd_soc_write(codec, RT5625_GEN_CTRL2, + RT5625_PLL1_S_MCLK); + snd_soc_write(codec, RT5625_PLL_CTRL, + codec_master_pll1_div[i].regvalue); + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_MASK, RT5625_SCLK_PLL1); + ret = 0; + break; + } + } else if (RT5625_PLL_MCLK_TO_VSYSCLK == pll_id) { for (i = 0; i < ARRAY_SIZE(codec_master_pll1_div); i ++) { if ((freq_in == codec_master_pll1_div[i].pll_in) && (freq_out == codec_master_pll1_div[i].pll_out)) { - rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x0000); /*PLL source from MCLK*/ - rt5625_write(codec, RT5625_PLL_CTRL, codec_master_pll1_div[i].regvalue); /*set pll code*/ - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/ - rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000); + snd_soc_write(codec, RT5625_GEN_CTRL2, 0x0000); /*PLL source from MCLK*/ + snd_soc_write(codec, RT5625_PLL_CTRL, codec_master_pll1_div[i].regvalue); /*set pll code*/ + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, 0x0030, 0x0030); /* Voice SYSCLK source from FLL1 */ ret = 0; } } - } else if (RT5625_PLL1_FROM_BCLK == pll_id) { - + }else if (RT5625_PLL_BCLK == pll_id) { for (i = 0; i < ARRAY_SIZE(codec_bclk_pll1_div); i ++) - { - if ((freq_in == codec_bclk_pll1_div[i].pll_in) && (freq_out == codec_bclk_pll1_div[i].pll_out)) - { - rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x2000); /*PLL source from BCLK*/ - rt5625_write(codec, RT5625_PLL_CTRL, codec_bclk_pll1_div[i].regvalue); /*set pll1 code*/ - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/ - rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000); + if ((freq_in == codec_bclk_pll1_div[i].pll_in) && + (freq_out == codec_bclk_pll1_div[i].pll_out)) { + snd_soc_write(codec, RT5625_GEN_CTRL2, + RT5625_PLL1_S_BCLK); + snd_soc_write(codec, RT5625_PLL_CTRL, + codec_bclk_pll1_div[i].regvalue); + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_MASK, RT5625_SCLK_PLL1); ret = 0; + break; } - } - } else if (RT5625_PLL1_FROM_VBCLK == pll_id) { - + } else if (RT5625_PLL_VBCLK == pll_id) { for (i = 0; i < ARRAY_SIZE(codec_vbclk_pll1_div); i ++) - { - if ((freq_in == codec_vbclk_pll1_div[i].pll_in) && (freq_out == codec_vbclk_pll1_div[i].pll_out)) - { - rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x3000); /*PLL source from VBCLK*/ - rt5625_write(codec, RT5625_PLL_CTRL, codec_vbclk_pll1_div[i].regvalue); /*set pll1 code*/ - rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/ - rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000); + if ((freq_in == codec_vbclk_pll1_div[i].pll_in) && + (freq_out == codec_vbclk_pll1_div[i].pll_out)) { + snd_soc_write(codec, RT5625_GEN_CTRL2, + RT5625_PLL1_S_VBCLK); + snd_soc_write(codec, RT5625_PLL_CTRL, + codec_vbclk_pll1_div[i].regvalue); + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_MASK, RT5625_SCLK_PLL1); ret = 0; + break; } - } } - return 0; + + return ret; } -static int rt5625_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai, +static int rt5625_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - struct snd_soc_codec *codec = codec_dai->codec; - struct rt5625_priv * rt5625 = codec->private_data; + struct snd_soc_codec *codec = dai->codec; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; - DBG("sysclk freq %u for audio i2s\n", freq); - - if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { + switch (dai->id) { + case RT5625_AIF1: + if (freq == rt5625->stereo_sysclk) + return 0; rt5625->stereo_sysclk = freq; - return 0; + break; + + case RT5625_AIF2: + if (freq == rt5625->voice_sysclk) + return 0; + rt5625->voice_sysclk = freq; + break; + + default: + return -EINVAL; } - - printk("unsupported sysclk freq %u for audio i2s\n", freq); - rt5625->stereo_sysclk=24576000; - - return 0; -} -static int rt5625_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 rt5625_priv * rt5625 = codec->private_data; + switch (clk_id) { + case RT5625_SCLK_S_MCLK: + break; - DBG("sysclk freq %u for voice pcm\n", freq); + case RT5625_SCLK_S_PLL: + val |= RT5625_SCLK_PLL1; + break; - if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) { - rt5625->voice_sysclk = freq; - return 0; - } + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5625_GEN_CTRL1, + RT5625_SCLK_MASK, val); - printk("unsupported sysclk freq %u for voice pcm\n", freq); - rt5625->voice_sysclk = 24576000; + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); return 0; } - -static int rt5625_hifi_pcm_hw_params(struct snd_pcm_substream *substream, +static int rt5625_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - struct rt5625_priv *rt5625 = codec->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + unsigned int iface = 0, rate = params_rate(params), coeff; - unsigned int iface = rt5625_read(codec, RT5625_MAIN_SDP_CTRL) & 0xfff3; - int rate = params_rate(params); - int coeff = get_coeff(rt5625->stereo_sysclk, rate, 0); - - DBG("enter %s rate = %d \n", __func__, rate); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; - switch (params_format(params)) - { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - iface |= 0x0004; - case SNDRV_PCM_FORMAT_S24_LE: - iface |= 0x0008; - case SNDRV_PCM_FORMAT_S8: - iface |= 0x000c; - } - - rt5625_write(codec, RT5625_MAIN_SDP_CTRL, iface); - rt5625_write_mask(codec, 0x3a, 0xc801, 0xc801); /*power i2s and dac ref*/ - if (coeff >= 0) { - rt5625_write(codec, RT5625_STEREO_DAC_CLK_CTRL1, coeff_div_stereo[coeff].reg60); - rt5625_write(codec, RT5625_STEREO_DAC_CLK_CTRL2, coeff_div_stereo[coeff].reg62); + case SNDRV_PCM_FORMAT_S20_3LE: + iface |= RT5625_I2S_DL_20; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + iface |= RT5625_I2S_DL_24; + break; + + case SNDRV_PCM_FORMAT_S8: + iface |= RT5625_I2S_DL_8; + break; + + default: + return -EINVAL; } - - return 0; -} -static int rt5625_voice_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_device *socdev = rtd->socdev; - struct snd_soc_codec *codec = socdev->card->codec; - struct rt5625_priv *rt5625 = codec->private_data; - struct snd_soc_dapm_widget *w; - unsigned int iface = rt5625_read(codec, RT5625_EXTEND_SDP_CTRL) & 0xfff3; - int rate = params_rate(params); - int coeff = get_coeff(rt5625->voice_sysclk, rate, 1); + switch (dai->id) { + case RT5625_AIF1: + coeff = get_coeff(rt5625->stereo_sysclk, rate, 0); + if (coeff < 0) { + dev_err(codec->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + snd_soc_write(codec, RT5625_DAC_CLK_CTRL1, + coeff_div_stereo[coeff].reg60); + snd_soc_write(codec, RT5625_DAC_CLK_CTRL2, + coeff_div_stereo[coeff].reg62); + snd_soc_update_bits(codec, RT5625_SDP_CTRL, + RT5625_I2S_DL_MASK, iface); + break; - DBG("enter %s rate = %d \n", __func__, rate); + case RT5625_AIF2: + rate = 8000; + coeff = get_coeff(rt5625->voice_sysclk, rate, 1); + if (coeff < 0) { + dev_err(codec->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + snd_soc_write(codec, RT5625_VDAC_CLK_CTRL1, + coeff_div_voice[coeff].reg64); + iface |= 0x0100; //Voice SYSCLK source from FLL1 + snd_soc_update_bits(codec, RT5625_EXT_SDP_CTRL, + RT5625_I2S_DL_MASK, iface); + break; - list_for_each_entry(w, &codec->dapm_widgets, list) - { - if (!w->sname) - continue; - if (!strcmp(w->name, "Right ADC")) - strcpy(w->sname, "Right ADC Voice Capture"); + default: + return -EINVAL; } - - switch (params_format(params)) - { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - iface |= 0x0004; - case SNDRV_PCM_FORMAT_S24_LE: - iface |= 0x0008; - case SNDRV_PCM_FORMAT_S8: - iface |= 0x000c; - } - rt5625_write_mask(codec, 0x3a, 0x0801, 0x0801); /*power i2s and dac ref*/ - rt5625_write(codec, RT5625_EXTEND_SDP_CTRL, iface); - if (coeff >= 0) - rt5625_write(codec, RT5625_VOICE_DAC_PCMCLK_CTRL1, coeff_div_voice[coeff].reg64); + +#ifdef RT5625_F_SMT_PHO + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + rt5625->app_bmp |= RT5625_PLY_MASK; + else + rt5625->app_bmp |= RT5625_REC_MASK; +#endif return 0; } - -static int rt5625_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +static int rt5625_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { + struct snd_soc_codec *codec = dai->codec; + unsigned int iface = 0; + bool slave; - struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = 0; + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + slave = false; + break; - DBG("enter %s fmt = %d\n", __func__, fmt); + case SND_SOC_DAIFMT_CBS_CFS: + slave = true; + break; - /*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; + default: + return -EINVAL; } - /*interface format*/ - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) - { - case SND_SOC_DAIFMT_I2S: - iface |= 0x0000; - 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: - iface |= 0x0000; - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= 0x0080; - break; - default: - return -EINVAL; - } + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; - rt5625_write(codec, RT5625_MAIN_SDP_CTRL, iface); - return 0; -} + case SND_SOC_DAIFMT_LEFT_J: + iface |= RT5625_I2S_DF_LEFT; + break; -static int rt5625_voice_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) -{ - struct snd_soc_codec *codec = codec_dai->codec; - int iface; + case SND_SOC_DAIFMT_DSP_A: + iface |= RT5625_I2S_DF_PCM_A; + break; - DBG("enter %s\n", __func__); - /*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; - } + case SND_SOC_DAIFMT_DSP_B: + iface |= RT5625_I2S_DF_PCM_B; + break; - switch(fmt & SND_SOC_DAIFMT_FORMAT_MASK) - { - case SND_SOC_DAIFMT_I2S: - iface |= 0x0000; - 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: - iface |= 0x0000; - break; - case SND_SOC_DAIFMT_IB_NF: - iface |= 0x0080; - break; - default: - return -EINVAL; + default: + return -EINVAL; } - iface |= 0x8000; /*enable vopcm*/ - rt5625_write(codec, RT5625_EXTEND_SDP_CTRL, iface); - return 0; -} + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= RT5625_I2S_BP_INV; + break; -static int rt5625_hifi_codec_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; + default: + return -EINVAL; + } + iface |= 0x8000; /*enable vopcm*/ + + switch (dai->id) { + case RT5625_AIF1: + if (slave) + iface |= RT5625_I2S_M_SLV; + snd_soc_update_bits(codec, RT5625_SDP_CTRL, + RT5625_I2S_M_MASK | RT5625_I2S_BP_MASK | + RT5625_I2S_DF_MASK, iface); + break; - if (mute) - rt5625_write_mask(codec, RT5625_STEREO_DAC_VOL, 0x8080, 0x8080); - else - rt5625_write_mask(codec, RT5625_STEREO_DAC_VOL, 0x0000, 0x8080); + case RT5625_AIF2: + if (slave) + iface |= RT5625_PCM_M_SLV; + snd_soc_update_bits(codec, RT5625_EXT_SDP_CTRL, + RT5625_PCM_M_MASK | RT5625_I2S_BP_MASK | + RT5625_I2S_DF_MASK, iface); + break; + + default: + return -EINVAL; + } return 0; } -static int rt5625_voice_codec_mute(struct snd_soc_dai *dai, int mute) +#ifdef RT5625_F_SMT_PHO +static int rt5625_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct rt5625_priv *rt5625 = snd_soc_codec_get_drvdata(codec); + int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (capture) + rt5625->app_bmp |= RT5625_REC_MASK; + else + rt5625->app_bmp |= RT5625_PLY_MASK; + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (capture) + rt5625->app_bmp &= ~RT5625_REC_MASK; + else + rt5625->app_bmp &= ~RT5625_PLY_MASK; + rt5625->app_bmp &= ~RT5625_VOIP_MASK; + break; + + default: + break; + } - if (mute) - rt5625_write_mask(codec, RT5625_VOICE_DAC_OUT_VOL, 0x1000, 0x1000); - else - rt5625_write_mask(codec, RT5625_VOICE_DAC_OUT_VOL, 0x0000, 0x1000); return 0; } - +#endif static int rt5625_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { switch(level) { case SND_SOC_BIAS_ON: +#ifdef RT5625_DEMO + snd_soc_update_bits(codec, RT5625_HP_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, 0); + snd_soc_update_bits(codec, RT5625_SPK_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, 0); +#endif break; + case SND_SOC_BIAS_PREPARE: - rt5625_write(codec, 0x26, 0x0000); - rt5625_write_mask(codec, 0x3c, 0x2000, 0x2000); - rt5625_write_mask(codec, 0x3a, 0x000e, 0x000e); + snd_soc_write(codec, RT5625_PD_CTRL, 0x0000); + snd_soc_update_bits(codec, RT5625_PWR_ADD1, + RT5625_P_MB1 | RT5625_P_MB2, + RT5625_P_MB1 | RT5625_P_MB2); break; + case SND_SOC_BIAS_STANDBY: +#ifdef RT5625_DEMO + snd_soc_update_bits(codec, RT5625_HP_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, + RT5625_L_MUTE | RT5625_R_MUTE); + snd_soc_update_bits(codec, RT5625_SPK_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, + RT5625_L_MUTE | RT5625_R_MUTE); + snd_soc_update_bits(codec, RT5625_PWR_ADD1, + RT5625_P_MB1 | RT5625_P_MB2, 0); +#endif + if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { + snd_soc_write(codec, RT5625_PD_CTRL, 0); + snd_soc_write(codec, RT5625_PWR_ADD1, + RT5625_P_MAIN_BIAS); + snd_soc_write(codec, RT5625_PWR_ADD2, RT5625_P_VREF); + codec->cache_only = false; + snd_soc_cache_sync(codec); + } break; + case SND_SOC_BIAS_OFF: - rt5625_write_mask(codec, 0x04, 0x8080, 0x8080); /*mute hp*/ - rt5625_write_mask(codec, 0x02, 0x8080, 0x8080); /*mute spk*/ - rt5625_write(codec, 0x3e, 0x0000); //power off all bit - rt5625_write(codec, 0x3a, 0x0000); //power off all bit - rt5625_write(codec, 0x3c, 0x0000); //power off all bit +#ifdef RT5625_DEMO + snd_soc_update_bits(codec, RT5625_HP_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, + RT5625_L_MUTE | RT5625_R_MUTE); + snd_soc_update_bits(codec, RT5625_SPK_OUT_VOL, + RT5625_L_MUTE | RT5625_R_MUTE, + RT5625_L_MUTE | RT5625_R_MUTE); +#endif + snd_soc_write(codec, RT5625_PWR_ADD1, 0x0000); + snd_soc_write(codec, RT5625_PWR_ADD2, 0x0000); + snd_soc_write(codec, RT5625_PWR_ADD3, 0x0000); break; } - codec->bias_level = level; + codec->dapm.bias_level = level; + + return 0; +} + +#ifdef RT5625_PROC +static int rt5625_proc_init(void); +#endif + +static int rt5625_probe(struct snd_soc_codec *codec) +{ + int ret; + + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } + + #ifdef RT5625_PROC + rt5625_proc_init(); + #endif + + rt5625_reset(codec); + snd_soc_write(codec, RT5625_PD_CTRL, 0); + snd_soc_write(codec, RT5625_PWR_ADD1, RT5625_P_MAIN_BIAS); + snd_soc_write(codec, RT5625_PWR_ADD2, RT5625_P_VREF); +#ifdef RT5625_DEMO + rt5625_reg_init(codec); +#endif + codec->dapm.bias_level = SND_SOC_BIAS_STANDBY; + rt5625_codec = codec; return 0; } +static int rt5625_remove(struct snd_soc_codec *codec) +{ + rt5625_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} -#define RT5625_STEREO_RATES SNDRV_PCM_RATE_8000_48000 +#ifdef CONFIG_PM +static int rt5625_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + rt5625_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} -#define RT5626_VOICE_RATES SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000 +static int rt5625_resume(struct snd_soc_codec *codec) +{ + rt5625_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} +#else +#define rt5625_suspend NULL +#define rt5625_resume NULL +#endif +#define RT5625_STEREO_RATES SNDRV_PCM_RATE_8000_48000 +#define RT5625_VOICE_RATES SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000 #define RT5625_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 rt5625_dai_ops_hifi = { - - .hw_params = rt5625_hifi_pcm_hw_params, -// .digital_mute = rt5625_hifi_codec_mute, - .set_fmt = rt5625_hifi_codec_set_dai_fmt, - .set_pll = rt5625_codec_set_dai_pll, - .set_sysclk = rt5625_hifi_codec_set_dai_sysclk, - -}; - - -static struct snd_soc_dai_ops rt5625_dai_ops_voice = { - - .hw_params = rt5625_voice_pcm_hw_params, -// .digital_mute = rt5625_voice_codec_mute, - .set_fmt = rt5625_voice_codec_set_dai_fmt, - .set_pll = rt5625_codec_set_dai_pll, - .set_sysclk = rt5625_voice_codec_set_dai_sysclk, - +struct snd_soc_dai_ops rt5625_aif_dai_ops = { +#ifdef RT5625_F_SMT_PHO + .trigger = rt5625_trigger, +#endif + .hw_params = rt5625_hw_params, + .set_fmt = rt5625_set_dai_fmt, + .set_sysclk = rt5625_set_dai_sysclk, + .set_pll = rt5625_set_dai_pll, }; - - -struct snd_soc_dai rt5625_dai[] = { - /*hifi codec dai*/ +struct snd_soc_dai_driver rt5625_dai[] = { { - .name = "RT5625 HiFi", - .id = 1, + .name = "rt5625-aif1", + .id = RT5625_AIF1, .playback = { .stream_name = "HiFi Playback", .channels_min = 1, @@ -1971,489 +2814,226 @@ struct snd_soc_dai rt5625_dai[] = { .rates = RT5625_STEREO_RATES, .formats = RT5625_FORMATS, }, - - .ops = &rt5625_dai_ops_hifi, + .ops = &rt5625_aif_dai_ops, }, - - /*voice codec dai*/ { - .name = "RT5625 Voice", - .id = 2, + .name = "rt5625-aif2", + .id = RT5625_AIF2, .playback = { .stream_name = "Voice Playback", .channels_min = 1, - .channels_max = 1, - .rates = RT5626_VOICE_RATES, + .channels_max = 2, + .rates = RT5625_VOICE_RATES, .formats = RT5625_FORMATS, }, .capture = { .stream_name = "Voice Capture", .channels_min = 1, - .channels_max = 1, - .rates = RT5626_VOICE_RATES, + .channels_max = 2, + .rates = RT5625_VOICE_RATES, .formats = RT5625_FORMATS, }, - - .ops = &rt5625_dai_ops_voice, - + .ops = &rt5625_aif_dai_ops, }, }; -EXPORT_SYMBOL_GPL(rt5625_dai); - - -static void rt5625_work(struct work_struct *work) -{ - struct snd_soc_codec *codec = - container_of(work, struct snd_soc_codec, delayed_work.work); - rt5625_set_bias_level(codec, codec->bias_level); -} - - -#if defined(CONFIG_SND_HWDEP) - -#if REALTEK_HWDEP - -#define RT_CE_CODEC_HWDEP_NAME "rt56xx hwdep " - - -static int rt56xx_hwdep_open(struct snd_hwdep *hw, struct file *file) -{ - DBG("enter %s\n", __func__); - return 0; -} - -static int rt56xx_hwdep_release(struct snd_hwdep *hw, struct file *file) -{ - DBG("enter %s\n", __func__); - return 0; -} - - -static int rt56xx_hwdep_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct rt56xx_cmd rt56xx; - struct rt56xx_cmd __user *_rt56xx = arg; - struct rt56xx_reg_state *buf; - struct rt56xx_reg_state *p; - struct snd_soc_codec *codec = hw->private_data; - - if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx))) - return -EFAULT; - buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number)) { - goto err; - } - switch (cmd) { - case RT_READ_CODEC_REG_IOCTL: - for (p = buf; p < buf + rt56xx.number; p++) - { - p->reg_value = codec->read(codec, p->reg_index); - } - if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number)) - goto err; - - break; - case RT_WRITE_CODEC_REG_IOCTL: - for (p = buf; p < buf + rt56xx.number; p++) - codec->write(codec, p->reg_index, p->reg_value); - break; - } - - kfree(buf); - return 0; +static struct snd_soc_codec_driver soc_codec_dev_rt5625 = { + .probe = rt5625_probe, + .remove = rt5625_remove, + .suspend = rt5625_suspend, + .resume = rt5625_resume, + .set_bias_level = rt5625_set_bias_level, + .reg_cache_size = 0x80, + .reg_word_size = sizeof(u16), + .reg_cache_default = rt5625_reg, + .volatile_register = rt5625_volatile_register, + .readable_register = rt5625_readable_register, + .reg_cache_step = 1, + .controls = rt5625_snd_controls, + .num_controls = ARRAY_SIZE(rt5625_snd_controls), + .dapm_widgets = rt5625_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5625_dapm_widgets), + .dapm_routes = rt5625_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5625_dapm_routes), +}; -err: - kfree(buf); - return -EFAULT; - -} +static const struct i2c_device_id rt5625_i2c_id[] = { + { "rt5625", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5625_i2c_id); -static int rt56xx_codec_dump_reg(struct snd_hwdep *hw, struct file *file, unsigned long arg) +static int rt5625_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct rt56xx_cmd rt56xx; - struct rt56xx_cmd __user *_rt56xx = arg; - struct rt56xx_reg_state *buf; - struct snd_soc_codec *codec = hw->private_data; - int number = codec->reg_cache_size; - int i; + struct rt5625_priv *rt5625; + int ret; - DBG("enter %s, number = %d\n", __func__, number); - if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx))) - return -EFAULT; - - buf = kmalloc(sizeof(*buf) * number, GFP_KERNEL); - if (buf == NULL) + rt5625 = kzalloc(sizeof(struct rt5625_priv), GFP_KERNEL); + if (NULL == rt5625) return -ENOMEM; - for (i = 0; i < number; i++) - { - buf[i].reg_index = i << 1; - buf[i].reg_value = codec->read(codec, buf[i].reg_index); - } - if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * i)) - goto err; - rt56xx.number = number; - if (copy_to_user(_rt56xx, &rt56xx, sizeof(rt56xx))) - goto err; - kfree(buf); - return 0; -err: - kfree(buf); - return -EFAULT; - -} - -static int rt56xx_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg) -{ - if (cmd == RT_READ_ALL_CODEC_REG_IOCTL) - { - return rt56xx_codec_dump_reg(hw, file, arg); - } - else - { - return rt56xx_hwdep_ioctl_common(hw, file, cmd, arg); - } -} - -int realtek_ce_init_hwdep(struct snd_soc_codec *codec) -{ - struct snd_hwdep *hw; - struct snd_card *card = codec->card; - int err; - - if ((err = snd_hwdep_new(card, RT_CE_CODEC_HWDEP_NAME, 0, &hw)) < 0) - return err; - - strcpy(hw->name, RT_CE_CODEC_HWDEP_NAME); - hw->private_data = codec; - hw->ops.open = rt56xx_hwdep_open; - hw->ops.release = rt56xx_hwdep_release; - hw->ops.ioctl = rt56xx_hwdep_ioctl; - return 0; -} - -#endif - -#endif + i2c_set_clientdata(i2c, rt5625); -static int rt5625_init(struct snd_soc_device *socdev) -{ - - struct snd_soc_codec *codec = socdev->card->codec; - int ret = 0; - - codec->name = "RT5625"; - codec->owner = THIS_MODULE; - codec->read = rt5625_read; - codec->write = rt5625_write; - codec->set_bias_level = rt5625_set_bias_level; - codec->dai= rt5625_dai; - codec->num_dai = 2; - codec->reg_cache_step = 2; - codec->reg_cache_size = ARRAY_SIZE(rt5625_reg)*2; - codec->reg_cache = kmemdup(rt5625_reg, sizeof(rt5625_reg), GFP_KERNEL); - if (codec->reg_cache == NULL) - return -ENOMEM; - - rt5625_reset(codec); - - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0 ) - { - printk(KERN_ERR "rt5625: failed to create pcms\n"); - goto pcm_err; - } - - rt5625_write(codec, RT5625_PD_CTRL_STAT, 0); - rt5625_write(codec, RT5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS); - rt5625_write(codec, RT5625_PWR_MANAG_ADD2, PWR_MIXER_VREF); - rt5625_reg_init(codec); - rt5625_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_STANDBY; - schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(80)); - -#if (RT5625_EQ_FUNC_ENA==1) - rt5625_update_eqmode(codec,POP); -#endif - - rt5625_add_controls(codec); - rt5625_add_widgets(codec); - - #if defined(CONFIG_SND_HWDEP) - - #if REALTEK_HWDEP - - realtek_ce_init_hwdep(codec); - - #endif - - #endif - - ret = snd_soc_init_card(socdev); - - if (ret < 0) - { - printk(KERN_ERR "rt5625: failed to register card\n"); - goto card_err; - } - DBG("rt5625: initial ok\n"); - return 0; - - card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - - pcm_err: - kfree(codec->reg_cache); - return ret; - - -} - - -static int rt5625_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) -{ - struct snd_soc_device *socdev = rt5625_socdev; - struct snd_soc_codec *codec = socdev->card->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = rt5625_init(socdev); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5625, + rt5625_dai, ARRAY_SIZE(rt5625_dai)); if (ret < 0) - pr_err("failed to initialise rt5625\n"); + kfree(rt5625); return ret; } -static int rt5625_i2c_remove(struct i2c_client *client) +static __devexit int rt5625_i2c_remove(struct i2c_client *i2c) { - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); + snd_soc_unregister_codec(&i2c->dev); + kfree(i2c_get_clientdata(i2c)); return 0; } -static const struct i2c_device_id rt5625_i2c_id[] = { - {"rt5625", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, rt5625_i2c_id); -static struct i2c_driver rt5625_i2c_driver = { +struct i2c_driver rt5625_i2c_driver = { .driver = { - .name = "RT5625 I2C Codec", + .name = "rt5625", .owner = THIS_MODULE, }, - .probe = rt5625_i2c_probe, - .remove = rt5625_i2c_remove, + .probe = rt5625_i2c_probe, + .remove = __devexit_p(rt5625_i2c_remove), .id_table = rt5625_i2c_id, }; - -static int rt5625_add_i2c_device(struct platform_device *pdev, - const struct rt5625_setup_data *setup) +static int __init rt5625_modinit(void) { -#if 0 - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; -#endif - int ret; - - ret = i2c_add_driver(&rt5625_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } -#if 0 - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "rt5625", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } + return i2c_add_driver(&rt5625_i2c_driver); +} +module_init(rt5625_modinit); - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } -#endif - return 0; -#if 0 -err_driver: +static void __exit rt5625_modexit(void) +{ i2c_del_driver(&rt5625_i2c_driver); - return -ENODEV; -#endif } +module_exit(rt5625_modexit); +MODULE_DESCRIPTION("ASoC RT5625 driver"); +MODULE_AUTHOR("Johnny Hsu "); +MODULE_LICENSE("GPL"); -static int rt5625_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct rt5625_setup_data *setup; - struct snd_soc_codec *codec; - struct rt5625_priv *rt5625; - int ret; - pr_info("RT5625 Audio Codec %s", RT5625_VERSION); +#ifdef RT5625_PROC - if(socdev->codec_data) +static ssize_t rt5625_proc_write(struct file *file, const char __user *buffer, + unsigned long len, void *data) +{ + char *cookie_pot; + char *p; + int reg; + int value; + + cookie_pot = (char *)vmalloc( len ); + if (!cookie_pot) { - setup = socdev->codec_data; - } - - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - rt5625 = kzalloc(sizeof(struct rt5625_priv), GFP_KERNEL); - if (rt5625 == NULL) { - kfree(codec); return -ENOMEM; - } - codec->private_data = rt5625; - socdev->card->codec = codec; - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - rt5625_socdev = socdev; - INIT_DELAYED_WORK(&codec->delayed_work, rt5625_work); - - ret = -ENODEV; -// if (setup->i2c_address) + } + else { - codec->hw_write = (hw_write_t)i2c_master_send; - //codec->hw_read = (hw_read_t)i2c_master_recv; - ret = rt5625_add_i2c_device(pdev, setup); + if (copy_from_user( cookie_pot, buffer, len )) + return -EFAULT; } - if (ret != 0) { - kfree(codec->private_data); - kfree(codec); - socdev->card->codec = NULL; - } - return ret; -} - -static int run_delayed_work(struct delayed_work *dwork) -{ - int ret; + switch(cookie_pot[0]) + { + case 'd': + case 'D': + debug_write_read ++; + debug_write_read %= 2; + if(debug_write_read != 0) + printk("Debug read and write reg on\n"); + else + printk("Debug read and write reg off\n"); + break; + case 'r': + case 'R': + printk("Read reg debug\n"); + if(cookie_pot[1] ==':') + { + debug_write_read = 1; + strsep(&cookie_pot,":"); + while((p=strsep(&cookie_pot,","))) + { + reg = simple_strtol(p,NULL,16); + value = rt5625_read(rt5625_codec,reg); + printk("rt5625_read:0x%04x = 0x%04x\n",reg,value); + } + debug_write_read = 0; + printk("\n"); + } + else + { + printk("Error Read reg debug.\n"); + printk("For example: echo r:22,23,24,25>rt5625_ts\n"); + } + break; + case 'w': + case 'W': + printk("Write reg debug\n"); + if(cookie_pot[1] ==':') + { + debug_write_read = 1; + strsep(&cookie_pot,":"); + while((p=strsep(&cookie_pot,"="))) + { + reg = simple_strtol(p,NULL,16); + p=strsep(&cookie_pot,","); + value = simple_strtol(p,NULL,16); + rt5625_write(rt5625_codec,reg,value); + printk("rt5625_write:0x%04x = 0x%04x\n",reg,value); + } + debug_write_read = 0; + printk("\n"); + } + else + { + printk("Error Write reg debug.\n"); + printk("For example: w:22=0,23=0,24=0,25=0>rt5625_ts\n"); + } + break; + case 'a': + printk("Dump reg \n"); - /* cancel any work waiting to be queued. */ - ret = cancel_delayed_work(dwork); + for(reg = 0; reg < 0x6e; reg+=2) + { + value = rt5625_read(rt5625_codec,reg); + printk("rt5625_read:0x%04x = 0x%04x\n",reg,value); + } - /* 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(); + break; + default: + printk("Help for rt5625_ts .\n-->The Cmd list: \n"); + printk("-->'d&&D' Open or Off the debug\n"); + printk("-->'r&&R' Read reg debug,Example: echo 'r:22,23,24,25'>rt5625_ts\n"); + printk("-->'w&&W' Write reg debug,Example: echo 'w:22=0,23=0,24=0,25=0'>rt5625_ts\n"); + break; } - return ret; -} - - -static int rt5625_remove(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - if (codec->control_data) - rt5625_set_bias_level(codec, SND_SOC_BIAS_OFF); - run_delayed_work(&codec->delayed_work); - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); - i2c_unregister_device(codec->control_data); - i2c_del_driver(&rt5625_i2c_driver); - kfree(codec->private_data); - kfree(codec); - - return 0; + return len; } +static const struct file_operations rt5625_proc_fops = { + .owner = THIS_MODULE, +}; -static int rt5625_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - rt5625_set_bias_level(codec, SND_SOC_BIAS_OFF); - - return 0; -} - -static int rt5625_resume(struct platform_device *pdev) +static int rt5625_proc_init(void) { - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - - -// int i; -// u8 data[3]; -// u16 *cache = codec->reg_cache; - -#if 1 - rt5625_reset(codec); - rt5625_write(codec, RT5625_PD_CTRL_STAT, 0); - rt5625_write(codec, RT5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS); - rt5625_write(codec, RT5625_PWR_MANAG_ADD2, PWR_MIXER_VREF); - rt5625_reg_init(codec); -#else - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(rt5625_reg); i++) { - if (i == RT5625_RESET) - continue; - data[0] = i << 1; - data[1] = (0xff00 & cache[i]) >> 8; - data[2] = 0x00ff & cache[i]; - codec->hw_write(codec->control_data, data, 3); + struct proc_dir_entry *rt5625_proc_entry; + rt5625_proc_entry = create_proc_entry("driver/rt5625_ts", 0777, NULL); + if(rt5625_proc_entry != NULL) + { + rt5625_proc_entry->write_proc = rt5625_proc_write; + return 0; } - - rt5625_set_bias_level(codec, SND_SOC_BIAS_STANDBY); -#endif - - /* charge rt5625 caps */ - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { - rt5625_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_ON; - schedule_delayed_work(&codec->delayed_work, - msecs_to_jiffies(100)); + else + { + printk("create proc error !\n"); + return -1; } - - return 0; } - - -struct snd_soc_codec_device soc_codec_dev_rt5625 = { - .probe = rt5625_probe, - .remove = rt5625_remove, - .suspend = rt5625_suspend, - .resume = rt5625_resume, -}; - -EXPORT_SYMBOL_GPL(soc_codec_dev_rt5625); - -static int __init rt5625_modinit(void) -{ - return snd_soc_register_dais(rt5625_dai, ARRAY_SIZE(rt5625_dai)); -} - -static void __exit rt5625_exit(void) -{ - snd_soc_unregister_dais(rt5625_dai, ARRAY_SIZE(rt5625_dai)); -} - -module_init(rt5625_modinit); -module_exit(rt5625_exit); -MODULE_LICENSE("GPL"); +#endif diff --git a/sound/soc/codecs/rt5625.h b/sound/soc/codecs/rt5625.h index cb4f73e8bcca..f61e439426dc 100644 --- a/sound/soc/codecs/rt5625.h +++ b/sound/soc/codecs/rt5625.h @@ -1,742 +1,823 @@ -#ifndef _RT5625_H -#define _RT5625_H - -#define RT5625_RESET 0X00 //RESET CODEC TO DEFAULT -#define RT5625_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME -#define RT5625_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME -#define RT5625_AUX_OUT_VOL 0X06 //AUXOUT VOLUME -#define RT5625_PHONEIN_VOL 0X08 //PHONE INPUT VOLUME -#define RT5625_LINE_IN_VOL 0X0A //LINE IN VOLUME -#define RT5625_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME -#define RT5625_MIC_VOL 0X0E //MICROPHONE VOLUME -#define RT5625_DAC_AND_MIC_CTRL 0X10 //STEREO DAC AND MIC ROUTING CONTROL -#define RT5625_ADC_REC_GAIN 0X12 //ADC RECORD GAIN -#define RT5625_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL -#define RT5625_VOICE_DAC_OUT_VOL 0X18 //VOICE DAC OUTPUT VOLUME -#define RT5625_VODSP_PDM_CTL 0X1A //VODSP & PDM CONTROL -#define RT5625_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL -#define RT5625_VODSP_CTL 0X1E //VODSP CONTROL -#define RT5625_MIC_CTRL 0X22 //MICROPHONE CONTROL -#define RT5625_DMIC_CTRL 0x24 -#define RT5625_PD_CTRL_STAT 0X26 //POWER DOWN CONTROL/STATUS -#define RT5625_DAC_ADC_VODAC_FUN_SEL 0X2E //STEREO DAC,VOICE DAC,STEREO ADC FUNCTION SELECT -#define RT5625_MAIN_SDP_CTRL 0X34 //MAIN SERIAL DATA PORT CONTROL(STEREO I2S) -#define RT5625_EXTEND_SDP_CTRL 0X36 //EXTEND SERIAL DATA PORT CONTROL(VOICE I2S/PCM) -#define RT5625_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1 -#define RT5625_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2 -#define RT5625_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3 -#define RT5625_GEN_CTRL_REG1 0X40 //GENERAL PURPOSE CONTROL REGISTER 1 -#define RT5625_GEN_CTRL_REG2 0X42 //GENERAL PURPOSE CONTROL REGISTER 2 -#define RT5625_PLL_CTRL 0X44 //PLL1 CONTROL -#define RT5625_PLL2_CTRL 0X46 //PLL2 CONTROL -#define RT5625_LDO_CTRL 0X48 //LDO CONTROL -#define RT5625_GPIO_PIN_CONFIG 0X4C //GPIO PIN CONFIGURATION -#define RT5625_GPIO_PIN_POLARITY 0X4E //GPIO PIN POLARITY -#define RT5625_GPIO_PIN_STICKY 0X50 //GPIO PIN STICKY -#define RT5625_GPIO_PIN_WAKEUP 0X52 //GPIO PIN WAKE UP -#define RT5625_GPIO_PIN_STATUS 0X54 //GPIO PIN STATUS -#define RT5625_GPIO_PIN_SHARING 0X56 //GPIO PIN SHARING -#define RT5625_OVER_TEMP_CURR_STATUS 0X58 //OVER TEMPERATURE AND CURRENT STATUS -#define RT5625_SOFT_VOL_CTRL 0X5A //SOFT VOLUME CONTROL SETTING -#define RT5625_GPIO_OUT_CTRL 0X5C //GPIO OUTPUT PIN CONTRL -#define RT5625_MISC_CTRL 0X5E //MISC CONTROL -#define RT5625_STEREO_DAC_CLK_CTRL1 0X60 //STEREO DAC CLOCK CONTROL 1 -#define RT5625_STEREO_DAC_CLK_CTRL2 0X62 //STEREO DAC CLOCK CONTROL 2 -#define RT5625_VOICE_DAC_PCMCLK_CTRL1 0X64 //VOICE/PCM DAC CLOCK CONTROL 1 -#define RT5625_PSEDUEO_SPATIAL_CTRL 0X68 //PSEDUEO STEREO /SPATIAL EFFECT BLOCK CONTROL -#define RT5625_PRIV_ADDR 0X6A //PRIVATE ADDRESS -#define RT5625_PRIV_DATA 0X6C //PRIVATE DATA -#define RT5625_EQ_CTRL_ADC_HPF 0X6E //EQ CONTROL AND STATUS /ADC HPF CONTROL -#define RT5625_VODSP_REG_ADDR 0x70 //VODSP REGISTER ADDRESS -#define RT5625_VODSP_REG_DATA 0x72 //VODSP REGISTER DATA -#define RT5625_VODSP_REG_CMD 0x74 //VODSP REGISTER COMMAND - - -/************************************************************************************************** - *Bit define of Codec Register - *************************************************************************************************/ -//global definition -#define RT_L_MUTE (0x1<<15) //Mute Left Control -#define RT_L_ZC (0x1<<14) //Mute Left Zero-Cross Detector Control -#define RT_R_MUTE (0x1<<7) //Mute Right Control -#define RT_R_ZC (0x1<<6) //Mute Right Zero-Cross Detector Control -#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer -#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer -#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer - -//Phone Input Volume(0x08) -#define M_PHONEIN_TO_HP_MIXER (0x1<<15) //Mute Phone In volume to HP mixer -#define M_PHONEIN_TO_SPK_MIXER (0x1<<14) //Mute Phone In volume to speaker mixer - - -//Mic Routing Control(0x10) -#define M_MIC1_TO_HP_MIXER (0x1<<15) //Mute MIC1 to HP mixer -#define M_MIC1_TO_SPK_MIXER (0x1<<14) //Mute MiC1 to SPK mixer -#define M_MIC1_TO_MONO_MIXER (0x1<<13) //Mute MIC1 to MONO mixer -#define M_MIC2_TO_HP_MIXER (0x1<<11) //Mute MIC2 to HP mixer -#define M_MIC2_TO_SPK_MIXER (0x1<<10) //Mute MiC2 to SPK mixer -#define M_MIC2_TO_MONO_MIXER (0x1<<9) //Mute MIC2 to MONO mixer -#define M_DAC_TO_HPL_MIXER (0x1<<3) //Mute DAC to HP left mixer -#define M_DAC_TO_HPR_MIXER (0x1<<2) //Mute DAC to HP right mixer -#define M_DAC_TO_SPK_MIXER (0x1<<1) //Mute DAC to SPK mixer -#define M_DAC_TO_MONO_MIXER (0x1<<0) //Mute DAC to MONO mixer - - - -//ADC Record Gain(0x12) -#define M_ADC_L_TO_HP_MIXER (0x1<<15) //Mute left of ADC to HP Mixer -#define M_ADC_L_TO_MONO_MIXER (0x1<<14) //Mute left of ADC to MONO Mixer -#define ADC_L_ZC_DET (0x1<<13) //ADC Zero-Cross Detector Control -#define ADC_L_GAIN_MASK (0x1f<<8) //ADC Record Gain Left channel Mask -#define M_ADC_R_TO_HP_MIXER (0x1<<7) //Mute right of ADC to HP Mixer -#define M_ADC_R_TO_MONO_MIXER (0x1<<6) //Mute right of ADC to MONO Mixer -#define ADC_R_ZC_DET (0x1<<5) //ADC Zero-Cross Detector Control -#define ADC_R_GAIN_MASK (0x1f<<0) //ADC Record Gain Right channel Mask - -//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) -#define VODSP_SRC2_S_SEL_TXDP (0x0<<12) //SRC2 source select AEC_TXDP -#define VODSP_SRC2_S_SEL_TXDC (0x1<<12) //SRC2 source select AEC_TXDC - -#define VODSP_RXDP_PWR (0x1<<11) //Enable AEC RXDP Power - -#define VODSP_RXDP_S_SEL_MASK (0x3<<9) -#define VODSP_RXDP_S_SEL_SRC1 (0x0<<9) //AEC RxDP source select SRC1 Output -#define VODSP_RXDP_S_SEL_ADCL (0x1<<9) //AEC RxDP source select ADC Left to AEC Digital Path -#define VODSP_RXDP_S_SEL_VOICE (0x2<<9) //AEC RxDP source select Voice to Stereo Digital Path -#define VODSP_RXDP_S_SEL_ADCR (0x3<<9) //AEC RxDP source select ADC Right to AEC Digital Path - -#define VODSP_RXDC_PWR (0x1<<8) //Enable AEC RXDC Power - -#define VOICE_PCM_S_SEL_MASK (0x1<<7) -#define VOICE_PCM_S_SEL_ADC_R (0x0<<7) //VSADC PCM interface source select ADC R -#define VOICE_PCM_S_SEL_AEC_TXDP (0x1<<7) //VSADC PCM interface source select AEC_TXDP - -#define REC_S_SEL_MASK (0x3<<4) -#define REC_S_SEL_ADC (0x0<<4) //Main Stereo Record I2S source select ADC L/R -#define REC_S_SEL_VOICE (0x1<<4) //Main Stereo Record I2S source select Voice to Stereo Digital Path -#define REC_S_SEL_SRC2 (0x2<<4) //Main Stereo Record I2S source select SRC2 - - -//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 -#define RT_PWR_PR7 (0x1<<15) //write this bit to power down the Speaker Amplifier -#define RT_PWR_PR6 (0x1<<14) //write this bit to power down the Headphone Out and MonoOut -#define RT_PWR_PR5 (0x1<<13) //write this bit to power down the internal clock(without PLL) -#define RT_PWR_PR3 (0x1<<11) //write this bit to power down the mixer(vref/vrefout out off) -#define RT_PWR_PR2 (0x1<<10) //write this bit to power down the mixer(vref/vrefout still on) -#define RT_PWR_PR1 (0x1<<9) //write this bit to power down the dac -#define RT_PWR_PR0 (0x1<<8) //write this bit to power down the adc -#define RT_PWR_REF (0x1<<3) //read only -#define RT_PWR_ANL (0x1<<2) //read only -#define RT_PWR_DAC (0x1<<1) //read only -#define RT_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) -#define MAIN_I2S_MODE_SEL (0x1<<15) //0:Master mode 1:Slave mode -#define MAIN_I2S_SADLRCK_CTRL (0x1<<14) //0:Disable,ADC and DAC use the same fs,1:Enable - -#define MAIN_I2S_PCM_MODE (0x1<<6) //0:Normal SADLRCK/SDALRCK,1:Invert SADLRCK/SDALRCK -//Data Length Slection -#define MAIN_I2S_DL_MASK (0x3<<2) //main i2s Data Length mask -#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 -#define MAIN_I2S_DF_MASK (0x3) //main i2s Data Format mask -#define MAIN_I2S_DF_I2S (0x0) //I2S FORMAT -#define MAIN_I2S_DF_LEFT (0x1) //LEFT JUSTIFIED format -#define MAIN_I2S_DF_PCM_A (0x2) //PCM Mode A -#define MAIN_I2S_DF_PCM_B (0x3) //PCM Mode B - -//Extend Serial Data Port Control(0x36) -#define EXT_I2S_FUNC_ENABLE (0x1<<15) //Enable PCM interface on GPIO 1,3,4,5 0:GPIO function,1:Voice PCM interface -#define EXT_I2S_MODE_SEL (0x1<<14) //0:Master ,1:Slave -#define EXT_I2S_AUTO_CLK_CTRL (0x1<<13) //0:Disable,1:Enable -#define EXT_I2S_BCLK_POLARITY (0x1<<7) //0:Normal 1:Invert -#define EXT_I2S_PCM_MODE (0x1<<6) //0:Normal VSLRCK,1:Invert VSLRCK -//Data Length Slection -#define EXT_I2S_DL_MASK (0x3<<2) //Extend i2s Data Length mask -#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 -#define EXT_I2S_DF_MASK (0x3) //Extend i2s Data Format mask -#define EXT_I2S_DF_I2S (0x0) //I2S FORMAT -#define EXT_I2S_DF_LEFT (0x1) //LEFT JUSTIFIED format -#define EXT_I2S_DF_PCM_A (0x2) //PCM Mode A -#define EXT_I2S_DF_PCM_B (0x3) //PCM Mode B - -//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) - -#define GP_DAC_HI_PA_ENA (0x1<<10) //Enable DAC High Pass Filter - -#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) -#define EN_HW_EQ_BLK (0x1<<15) //HW EQ block control - -#define EQ_SOUR_SEL_DAC (0x0<<14) -#define EQ_SOUR_SEL_ADC (0x1<<14) - -#define EQ_CHANGE_EN (0x1<<7) //EQ parameter update control -#define EN_HW_EQ_HPF (0x1<<4) //EQ High Pass Filter Control -#define EN_HW_EQ_BP3 (0x1<<3) //EQ Band-3 Control -#define EN_HW_EQ_BP2 (0x1<<2) //EQ Band-2 Control -#define EN_HW_EQ_BP1 (0x1<<1) //EQ Band-1 Control -#define EN_HW_EQ_LPF (0x1<<0) //EQ Low Pass Filter Control - - -//AEC register command(0x74) - -#define VODSP_BUSY (0x1<<15) //VODSP I2C busy flag - -#define VODSP_S_FROM_VODSP_RD (0x0<<14) -#define VODSP_S_FROM_MX72 (0x1<<14) - -#define VODSP_CLK_SEL_MASK (0x3<<12) //VODSP CLK select Mask -#define VODSP_CLK_SEL_12_288M (0x0<<12) //VODSP CLK select 12.288Mhz -#define VODSP_CLK_SEL_6_144M (0x1<<12) //VODSP CLK select 6.144Mhz -#define VODSP_CLK_SEL_3_072M (0x2<<12) //VODSP CLK select 3.072Mhz -#define VODSP_CLK_SEL_2_048M (0x3<<12) //VODSP CLK select 2.0488Mhz - -#define VODSP_READ_ENABLE (0x1<<9) //VODSP Read Enable -#define VODSP_WRITE_ENABLE (0x1<<8) //VODSP Write Enable - -#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 REALTEK_HWDEP 0 - -#if REALTEK_HWDEP - -struct rt56xx_reg_state -{ - unsigned int reg_index; - unsigned int reg_value; +/* + * rt5625.h -- RT5625 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu + * + * 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 __RT5625_H__ +#define __RT5625_H__ + +#define RT5625_RESET 0x00 +#define RT5625_SPK_OUT_VOL 0x02 +#define RT5625_HP_OUT_VOL 0x04 +#define RT5625_AUX_OUT_VOL 0x06 +#define RT5625_PHONEIN_VOL 0x08 +#define RT5625_LINE_IN_VOL 0x0a +#define RT5625_DAC_VOL 0x0c +#define RT5625_MIC_VOL 0x0e +#define RT5625_DAC_MIC_CTRL 0x10 +#define RT5625_ADC_REC_GAIN 0x12 +#define RT5625_ADC_REC_MIXER 0x14 +#define RT5625_VDAC_OUT_VOL 0x18 +#define RT5625_VODSP_PDM_CTL 0x1a +#define RT5625_OUTMIX_CTRL 0x1c +#define RT5625_VODSP_CTL 0x1e +#define RT5625_MIC_CTRL 0x22 +#define RT5625_DMIC_CTRL 0x24 +#define RT5625_PD_CTRL 0x26 +#define RT5625_F_DAC_ADC_VDAC 0x2e +#define RT5625_SDP_CTRL 0x34 +#define RT5625_EXT_SDP_CTRL 0x36 +#define RT5625_PWR_ADD1 0x3a +#define RT5625_PWR_ADD2 0x3c +#define RT5625_PWR_ADD3 0x3e +#define RT5625_GEN_CTRL1 0x40 +#define RT5625_GEN_CTRL2 0x42 +#define RT5625_PLL_CTRL 0x44 +#define RT5625_PLL2_CTRL 0x46 +#define RT5625_LDO_CTRL 0x48 +#define RT5625_GPIO_CONFIG 0x4c +#define RT5625_GPIO_POLAR 0x4e +#define RT5625_GPIO_STICKY 0x50 +#define RT5625_GPIO_WAKEUP 0x52 +#define RT5625_GPIO_STATUS 0x54 +#define RT5625_GPIO_SHARING 0x56 +#define RT5625_OTC_STATUS 0x58 +#define RT5625_SOFT_VOL_CTRL 0x5a +#define RT5625_GPIO_OUT_CTRL 0x5c +#define RT5625_MISC_CTRL 0x5e +#define RT5625_DAC_CLK_CTRL1 0x60 +#define RT5625_DAC_CLK_CTRL2 0x62 +#define RT5625_VDAC_CLK_CTRL1 0x64 +#define RT5625_PS_CTRL 0x68 +#define RT5625_PRIV_INDEX 0x6a +#define RT5625_PRIV_DATA 0x6c +#define RT5625_EQ_CTRL 0x6e +#define RT5625_DSP_ADDR 0x70 +#define RT5625_DSP_DATA 0x72 +#define RT5625_DSP_CMD 0x74 +#define RT5625_VENDOR_ID1 0x7c +#define RT5625_VENDOR_ID2 0x7e + +/* global definition */ +#define RT5625_L_MUTE (0x1 << 15) +#define RT5625_L_MUTE_SFT 15 +#define RT5625_L_ZC (0x1 << 14) +#define RT5625_L_VOL_MASK (0x1f << 8) +#define RT5625_L_HVOL_MASK (0x3f << 8) +#define RT5625_L_VOL_SFT 8 +#define RT5625_R_MUTE (0x1 << 7) +#define RT5625_R_MUTE_SFT 7 +#define RT5625_R_ZC (0x1 << 6) +#define RT5625_R_VOL_MASK (0x1f) +#define RT5625_R_HVOL_MASK (0x3f) +#define RT5625_R_VOL_SFT 0 +#define RT5625_M_HPMIX (0x1 << 15) +#define RT5625_M_SPKMIX (0x1 << 14) +#define RT5625_M_MONOMIX (0x1 << 13) + +/* Phone Input (0x08) */ +#define RT5625_M_PHO_HM (0x1 << 15) +#define RT5625_M_PHO_HM_SFT 15 +#define RT5625_M_PHO_SM (0x1 << 14) +#define RT5625_M_PHO_SM_SFT 14 +#define RT5625_PHO_DIFF (0x1 << 13) +#define RT5625_PHO_DIFF_SFT 13 +#define RT5625_PHO_DIFF_DIS (0x0 << 13) +#define RT5625_PHO_DIFF_EN (0x1 << 13) + +/* Linein Volume (0x0a) */ +#define RT5625_M_LI_HM (0x1 << 15) +#define RT5625_M_LI_HM_SFT 15 +#define RT5625_M_LI_SM (0x1 << 14) +#define RT5625_M_LI_SM_SFT 14 +#define RT5625_M_LI_MM (0x1 << 13) +#define RT5625_M_LI_MM_SFT 13 + +/* MIC Input Volume (0x0e) */ +#define RT5625_MIC1_DIFF_MASK (0x1 << 15) +#define RT5625_MIC1_DIFF_SFT 15 +#define RT5625_MIC1_DIFF_DIS (0x0 << 15) +#define RT5625_MIC1_DIFF_EN (0x1 << 15) +#define RT5625_MIC2_DIFF_MASK (0x1 << 7) +#define RT5625_MIC2_DIFF_SFT 7 +#define RT5625_MIC2_DIFF_DIS (0x0 << 7) +#define RT5625_MIC2_DIFF_EN (0x1 << 7) + +/* Stereo DAC and MIC Routing Control (0x10) */ +#define RT5625_M_MIC1_HM (0x1 << 15) +#define RT5625_M_MIC1_HM_SFT 15 +#define RT5625_M_MIC1_SM (0x1 << 14) +#define RT5625_M_MIC1_SM_SFT 14 +#define RT5625_M_MIC1_MM (0x1 << 13) +#define RT5625_M_MIC1_MM_SFT 13 +#define RT5625_M_MIC2_HM (0x1 << 11) +#define RT5625_M_MIC2_HM_SFT 11 +#define RT5625_M_MIC2_SM (0x1 << 10) +#define RT5625_M_MIC2_SM_SFT 10 +#define RT5625_M_MIC2_MM (0x1 << 9) +#define RT5625_M_MIC2_MM_SFT 9 +#define RT5625_M_DACL_HM (0x1 << 3) +#define RT5625_M_DACL_HM_SFT 3 +#define RT5625_M_DACR_HM (0x1 << 2) +#define RT5625_M_DACR_HM_SFT 2 +#define RT5625_M_DAC_SM (0x1 << 1) +#define RT5625_M_DAC_SM_SFT 1 +#define RT5625_M_DAC_MM (0x1) +#define RT5625_M_DAC_MM_SFT 0 + +/* ADC Record Gain (0x12) */ +#define RT5625_M_ADCL_HM (0x1 << 15) +#define RT5625_M_ADCL_HM_SFT 15 +#define RT5625_M_ADCL_MM (0x1 << 14) +#define RT5625_M_ADCL_MM_SFT 14 +#define RT5625_ADCL_ZCD (0x1 << 13) +#define RT5625_G_ADCL_MASK (0x1f << 8) +#define RT5625_M_ADCR_HM (0x1 << 7) +#define RT5625_M_ADCR_HM_SFT 7 +#define RT5625_M_ADCR_MM (0x1 << 6) +#define RT5625_M_ADCR_MM_SFT 6 +#define RT5625_ADCR_ZCD (0x1 << 5) +#define RT5625_G_ADCR_MASK (0x1f) + +/* ADC Record Mixer Control (0x14) */ +#define RT5625_M_RM_L_MIC1 (0x1 << 14) +#define RT5625_M_RM_L_MIC1_SFT 14 +#define RT5625_M_RM_L_MIC2 (0x1 << 13) +#define RT5625_M_RM_L_MIC2_SFT 13 +#define RT5625_M_RM_L_LINE (0x1 << 12) +#define RT5625_M_RM_L_LINE_SFT 12 +#define RT5625_M_RM_L_PHO (0x1 << 11) +#define RT5625_M_RM_L_PHO_SFT 11 +#define RT5625_M_RM_L_HM (0x1 << 10) +#define RT5625_M_RM_L_HM_SFT 10 +#define RT5625_M_RM_L_SM (0x1 << 9) +#define RT5625_M_RM_L_SM_SFT 9 +#define RT5625_M_RM_L_MM (0x1 << 8) +#define RT5625_M_RM_L_MM_SFT 8 +#define RT5625_M_RM_R_MIC1 (0x1 << 6) +#define RT5625_M_RM_R_MIC1_SFT 6 +#define RT5625_M_RM_R_MIC2 (0x1 << 5) +#define RT5625_M_RM_R_MIC2_SFT 5 +#define RT5625_M_RM_R_LINE (0x1 << 4) +#define RT5625_M_RM_R_LINE_SFT 4 +#define RT5625_M_RM_R_PHO (0x1 << 3) +#define RT5625_M_RM_R_PHO_SFT 3 +#define RT5625_M_RM_R_HM (0x1 << 2) +#define RT5625_M_RM_R_HM_SFT 2 +#define RT5625_M_RM_R_SM (0x1 << 1) +#define RT5625_M_RM_R_SM_SFT 1 +#define RT5625_M_RM_R_MM (0x1) +#define RT5625_M_RM_R_MM_SFT 0 + +/* Voice DAC Volume (0x18) */ +#define RT5625_M_VDAC_HM (0x1 << 15) +#define RT5625_M_VDAC_HM_SFT 15 +#define RT5625_M_VDAC_SM (0x1 << 14) +#define RT5625_M_VDAC_SM_SFT 14 +#define RT5625_M_VDAC_MM (0x1 << 13) +#define RT5625_M_VDAC_MM_SFT 13 + +/* AEC & PDM Control (0x1a) */ +#define RT5625_SRC1_PWR (0x1 << 15) +#define RT5625_SRC1_PWR_SFT 15 +#define RT5625_SRC2_PWR (0x1 << 13) +#define RT5625_SRC2_PWR_SFT 13 +#define RT5625_SRC2_S_MASK (0x1 << 12) +#define RT5625_SRC2_S_SFT 12 +#define RT5625_SRC2_S_TXDP (0x0 << 12) +#define RT5625_SRC2_S_TXDC (0x1 << 12) +#define RT5625_RXDP_PWR (0x1 << 11) +#define RT5625_RXDP_PWR_SFT 11 +#define RT5625_RXDP_S_MASK (0x3 << 9) +#define RT5625_RXDP_S_SFT 9 +#define RT5625_RXDP_S_SRC1 (0x0 << 9) +#define RT5625_RXDP_S_ADCL (0x1 << 9) +#define RT5625_RXDP_S_VOICE (0x2 << 9) +#define RT5625_RXDP_S_ADCR (0x3 << 9) +#define RT5625_RXDC_PWR (0x1 << 8) +#define RT5625_RXDC_PWR_SFT 8 +#define RT5625_PCM_S_MASK (0x1 << 7) +#define RT5625_PCM_S_SFT 7 +#define RT5625_PCM_S_ADCR (0x0 << 7) +#define RT5625_PCM_S_TXDP (0x1 << 7) +#define RT5625_REC_IIS_S_MASK (0x3 << 4) +#define RT5625_REC_IIS_S_SFT 4 +#define RT5625_REC_IIS_S_ADC (0x0 << 4) +#define RT5625_REC_IIS_S_VOICE (0x1 << 4) +#define RT5625_REC_IIS_S_SRC2 (0x2 << 4) + +/* Output Mixer Control (0x1c) */ +#define RT5625_SPKN_S_MASK (0x3 << 14) +#define RT5625_SPKN_S_SFT 14 +#define RT5625_SPKN_S_LN (0x2 << 14) +#define RT5625_SPKN_S_RP (0x1 << 14) +#define RT5625_SPKN_S_RN (0x0 << 14) +#define RT5625_SPK_T_MASK (0x1 << 13) +#define RT5625_SPK_T_SFT 13 +#define RT5625_SPK_T_CLS_D (0x1 << 13) +#define RT5625_SPK_T_CLS_AB (0x0 << 13) +#define RT5625_CLS_AB_MASK (0x1 << 12) +#define RT5625_CLS_AB_SFT 12 +#define RT5625_CLS_AB_S_AMP (0x0 << 12) +#define RT5625_CLS_AB_W_AMP (0x1 << 12) +#define RT5625_SPKVOL_S_MASK (0x3 << 10) +#define RT5625_SPKVOL_S_SFT 10 +#define RT5625_SPKVOL_S_MM (0x3 << 10) +#define RT5625_SPKVOL_S_SM (0x2 << 10) +#define RT5625_SPKVOL_S_HM (0x1 << 10) +#define RT5625_SPKVOL_S_VMID (0x0 << 10) +#define RT5625_HPVOL_L_S_MASK (0x1 << 9) +#define RT5625_HPVOL_L_S_SFT 9 +#define RT5625_HPVOL_L_S_HM (0x1 << 9) +#define RT5625_HPVOL_L_S_VMID (0x0 << 9) +#define RT5625_HPVOL_R_S_MASK (0x1 << 8) +#define RT5625_HPVOL_R_S_SFT 8 +#define RT5625_HPVOL_R_S_HM (0x1 << 8) +#define RT5625_HPVOL_R_S_VMID (0x0 << 8) +#define RT5625_AUXVOL_S_MASK (0x3 << 6) +#define RT5625_AUXVOL_S_SFT 6 +#define RT5625_AUXVOL_S_MM (0x3 << 6) +#define RT5625_AUXVOL_S_SM (0x2 << 6) +#define RT5625_AUXVOL_S_HM (0x1 << 6) +#define RT5625_AUXVOL_S_VMID (0x0 << 6) +#define RT5625_AUXOUT_MODE (0x1 << 4) +#define RT5625_AUXOUT_MODE_SFT 4 +#define RT5625_DACL_HP_MASK (0x1 << 1) +#define RT5625_DACL_HP_SFT 1 +#define RT5625_DACL_HP_MUTE (0x0 << 1) +#define RT5625_DACL_HP_ON (0x1 << 1) +#define RT5625_DACR_HP_MASK (0x1) +#define RT5625_DACR_HP_SFT 0 +#define RT5625_DACR_HP_MUTE (0x0) +#define RT5625_DACR_HP_ON (0x1) + +/* VoDSP Control (0x1e) */ +#define RT5625_DSP_SCLK_S_MASK (0x1 << 15) +#define RT5625_DSP_SCLK_S_SFT 15 +#define RT5625_DSP_SCLK_S_MCLK (0x0 << 15) +#define RT5625_DSP_SCLK_S_VCLK (0x1 << 15) +#define RT5625_DSP_LRCK_MASK (0x1 << 13) +#define RT5625_DSP_LRCK_SFT 13 +#define RT5625_DSP_LRCK_8K (0x0 << 13) +#define RT5625_DSP_LRCK_16K (0x1 << 13) +#define RT5625_DSP_TP_MASK (0x1 << 3) +#define RT5625_DSP_TP_SFT 3 +#define RT5625_DSP_TP_NOR (0x0 << 3) +#define RT5625_DSP_TP_TEST (0x1 << 3) +#define RT5625_DSP_BP_MASK (0x1 << 2) +#define RT5625_DSP_BP_SFT 2 +#define RT5625_DSP_BP_EN (0x0 << 2) +#define RT5625_DSP_BP_NOR (0x1 << 2) +#define RT5625_DSP_PD_MASK (0x1 << 1) +#define RT5625_DSP_PD_SFT 1 +#define RT5625_DSP_PD_EN (0x0 << 1) +#define RT5625_DSP_PD_NOR (0x1 << 1) +#define RT5625_DSP_RST_MASK (0x1) +#define RT5625_DSP_RST_SFT 0 +#define RT5625_DSP_RST_EN (0x0) +#define RT5625_DSP_RST_NOR (0x1) + +/* Microphone Control (0x22) */ +#define RT5625_MIC1_BST_MASK (0x3 << 10) +#define RT5625_MIC1_BST_SFT 10 +#define RT5625_MIC1_BST_BYPASS (0x0 << 10) +#define RT5625_MIC1_BST_20DB (0x1 << 10) +#define RT5625_MIC1_BST_30DB (0x2 << 10) +#define RT5625_MIC1_BST_40DB (0x3 << 10) +#define RT5625_MIC2_BST_MASK (0x3 << 8) +#define RT5625_MIC2_BST_SFT 8 +#define RT5625_MIC2_BST_BYPASS (0x0 << 8) +#define RT5625_MIC2_BST_20DB (0x1 << 8) +#define RT5625_MIC2_BST_30DB (0x2 << 8) +#define RT5625_MIC2_BST_40DB (0x3 << 8) +#define RT5625_MB1_OV_MASK (0x1 << 5) +#define RT5625_MB1_OV_90P (0x0 << 5) +#define RT5625_MB1_OV_75P (0x1 << 5) +#define RT5625_MB2_OV_MASK (0x1 << 4) +#define RT5625_MB2_OV_90P (0x0 << 4) +#define RT5625_MB2_OV_75P (0x1 << 4) +#define RT5625_SCD_THD_MASK (0x3) +#define RT5625_SCD_THD_600UA (0x0) +#define RT5625_SCD_THD_1500UA (0x1) +#define RT5625_SCD_THD_2000UA (0x2) + +/* Digital Boost Control (0x24) */ +#define RT5625_DIG_BST_MASK (0x7) +#define RT5625_DIG_BST_SFT 0 + +/* Power Down Control/Status (0x26) */ +#define RT5625_PWR_PR7 (0x1 << 15) +#define RT5625_PWR_PR6 (0x1 << 14) +#define RT5625_PWR_PR5 (0x1 << 13) +#define RT5625_PWR_PR3 (0x1 << 11) +#define RT5625_PWR_PR2 (0x1 << 10) +#define RT5625_PWR_PR1 (0x1 << 9) +#define RT5625_PWR_PR0 (0x1 << 8) +#define RT5625_PWR_REF_ST (0x1 << 3) +#define RT5625_PWR_AM_ST (0x1 << 2) +#define RT5625_PWR_DAC_ST (0x1 << 1) +#define RT5625_PWR_ADC_ST (0x1) + +/* Stereo DAC/Voice DAC/Stereo ADC Function Select (0x2e) */ +#define RT5625_DAC_F_MASK (0x3 << 12) +#define RT5625_DAC_F_SFT 12 +#define RT5625_DAC_F_DAC (0x0 << 12) +#define RT5625_DAC_F_SRC2 (0x1 << 12) +#define RT5625_DAC_F_TXDP (0x2 << 12) +#define RT5625_DAC_F_TXDC (0x3 << 12) +#define RT5625_VDAC_S_MASK (0x7 << 8) +#define RT5625_VDAC_S_SFT 8 +#define RT5625_VDAC_S_VOICE (0x0 << 8) +#define RT5625_VDAC_S_SRC2 (0x1 << 8) +#define RT5625_VDAC_S_TXDP (0x2 << 8) +#define RT5625_VDAC_S_TXDC (0x3 << 8) +#define RT5625_ADCR_F_MASK (0x3 << 4) +#define RT5625_ADCR_F_SFT 4 +#define RT5625_ADCR_F_ADC (0x0 << 4) +#define RT5625_ADCR_F_VADC (0x1 << 4) +#define RT5625_ADCR_F_DSP (0x2 << 4) +#define RT5625_ADCR_F_PDM (0x3 << 4) +#define RT5625_ADCL_F_MASK (0x1) +#define RT5625_ADCL_F_SFT 0 +#define RT5625_ADCL_F_ADC (0x0) +#define RT5625_ADCL_F_DSP (0x1) + +/* Main Serial Data Port Control (Stereo IIS) (0x34) */ +#define RT5625_I2S_M_MASK (0x1 << 15) +#define RT5625_I2S_M_SFT 15 +#define RT5625_I2S_M_MST (0x0 << 15) +#define RT5625_I2S_M_SLV (0x1 << 15) +#define RT5625_I2S_SAD_MASK (0x1 << 14) +#define RT5625_I2S_SAD_SFT 14 +#define RT5625_I2S_SAD_DIS (0x0 << 14) +#define RT5625_I2S_SAD_EN (0x1 << 14) +#define RT5625_I2S_S_MASK (0x1 << 8) +#define RT5625_I2S_S_SFT 8 +#define RT5625_I2S_S_MSCLK (0x0 << 8) +#define RT5625_I2S_S_VSCLK (0x1 << 8) +#define RT5625_I2S_BP_MASK (0x1 << 7) +#define RT5625_I2S_BP_SFT 7 +#define RT5625_I2S_BP_NOR (0x0 << 7) +#define RT5625_I2S_BP_INV (0x1 << 7) +#define RT5625_I2S_LRCK_MASK (0x1 << 6) +#define RT5625_I2S_LRCK_SFT 6 +#define RT5625_I2S_LRCK_NOR (0x0 << 6) +#define RT5625_I2S_LRCK_INV (0x1 << 6) +#define RT5625_I2S_DL_MASK (0x3 << 2) +#define RT5625_I2S_DL_SFT 2 +#define RT5625_I2S_DL_16 (0x0 << 2) +#define RT5625_I2S_DL_20 (0x1 << 2) +#define RT5625_I2S_DL_24 (0x2 << 2) +#define RT5625_I2S_DL_8 (0x3 << 2) +#define RT5625_I2S_DF_MASK (0x3) +#define RT5625_I2S_DF_SFT 0 +#define RT5625_I2S_DF_I2S (0x0) +#define RT5625_I2S_DF_LEFT (0x1) +#define RT5625_I2S_DF_PCM_A (0x2) +#define RT5625_I2S_DF_PCM_B (0x3) + +/* Extend Serial Data Port Control (0x36) */ +#define RT5625_PCM_F_MASK (0x1 << 15) +#define RT5625_PCM_F_SFT 15 +#define RT5625_PCM_F_GPIO (0x0 << 15) +#define RT5625_PCM_F_PCM (0x1 << 15) +#define RT5625_PCM_M_MASK (0x1 << 14) +#define RT5625_PCM_M_SFT 14 +#define RT5625_PCM_M_MST (0x0 << 14) +#define RT5625_PCM_M_SLV (0x1 << 14) +#define RT5625_PCM_CS_MASK (0x1 << 8) +#define RT5625_PCM_CS_SFT 8 +#define RT5625_PCM_CS_SCLK (0x0 << 8) +#define RT5625_PCM_CS_VSCLK (0x1 << 8) + +/* Power Management Addition 1 (0x3a) */ +#define RT5625_P_DACL_MIX (0x1 << 15) +#define RT5625_P_DACL_MIX_BIT 15 +#define RT5625_P_DACR_MIX (0x1 << 14) +#define RT5625_P_DACR_MIX_BIT 14 +#define RT5625_P_ZCD (0x1 << 13) +#define RT5625_P_ZCD_BIT 13 +#define RT5625_P_I2S (0x1 << 11) +#define RT5625_P_I2S_BIT 11 +#define RT5625_P_SPK_AMP (0x1 << 10) +#define RT5625_P_SPK_AMP_BIT 10 +#define RT5625_P_HPO_AMP (0x1 << 9) +#define RT5625_P_HPO_AMP_BIT 9 +#define RT5625_P_HPO_ENH (0x1 << 8) +#define RT5625_P_HPO_ENH_BIT 8 +#define RT5625_P_VDAC_MIX (0x1 << 7) +#define RT5625_P_VDAC_MIX_BIT 7 +#define RT5625_P_SG_EN (0x1 << 6) +#define RT5625_P_SG_EN_BIT 6 +#define RT5625_P_MB1_SCD (0x1 << 5) +#define RT5625_P_MB1_SCD_BIT 5 +#define RT5625_P_MB2_SCD (0x1 << 4) +#define RT5625_P_MB2_SCD_BIT 4 +#define RT5625_P_MB1 (0x1 << 3) +#define RT5625_P_MB1_BIT 3 +#define RT5625_P_MB2 (0x1 << 2) +#define RT5625_P_MB2_BIT 2 +#define RT5625_P_MAIN_BIAS (0x1 << 1) +#define RT5625_P_MAIN_BIAS_BIT 1 +#define RT5625_P_DAC_REF (0x1) +#define RT5625_P_DAC_REF_BIT 0 + +/* Power Management Addition 2 (0x3c) */ +#define RT5625_P_PLL1 (0x1 << 15) +#define RT5625_P_PLL1_BIT 15 +#define RT5625_P_PLL2 (0x1 << 14) +#define RT5625_P_PLL2_BIT 14 +#define RT5625_P_VREF (0x1 << 13) +#define RT5625_P_VREF_BIT 13 +#define RT5625_P_OVT (0x1 << 12) +#define RT5625_P_OVT_BIT 12 +#define RT5625_P_AUX_ADC (0x1 << 11) +#define RT5625_P_AUX_ADC_BIT 11 +#define RT5625_P_VDAC (0x1 << 10) +#define RT5625_P_VDAC_BIT 10 +#define RT5625_P_DACL (0x1 << 9) +#define RT5625_P_DACL_BIT 9 +#define RT5625_P_DACR (0x1 << 8) +#define RT5625_P_DACR_BIT 8 +#define RT5625_P_ADCL (0x1 << 7) +#define RT5625_P_ADCL_BIT 7 +#define RT5625_P_ADCR (0x1 << 6) +#define RT5625_P_ADCR_BIT 6 +#define RT5625_P_HM_L (0x1 << 5) +#define RT5625_P_HM_L_BIT 5 +#define RT5625_P_HM_R (0x1 << 4) +#define RT5625_P_HM_R_BIT 4 +#define RT5625_P_SM (0x1 << 3) +#define RT5625_P_SM_BIT 3 +#define RT5625_P_MM (0x1 << 2) +#define RT5625_P_MM_BIT 2 +#define RT5625_P_ADCL_RM (0x1 << 1) +#define RT5625_P_ADCL_RM_BIT 1 +#define RT5625_P_ADCR_RM (0x1) +#define RT5625_P_ADCR_RM_BIT 0 + +/* Power Management Addition 3 (0x3e) */ +#define RT5625_P_OSC_EN (0x1 << 15) +#define RT5625_P_OSC_EN_BIT 15 +#define RT5625_P_AUX_VOL (0x1 << 14) +#define RT5625_P_AUX_VOL_BIT 14 +#define RT5625_P_SPKL_VOL (0x1 << 13) +#define RT5625_P_SPKL_VOL_BIT 13 +#define RT5625_P_SPKR_VOL (0x1 << 12) +#define RT5625_P_SPKR_VOL_BIT 12 +#define RT5625_P_HPL_VOL (0x1 << 11) +#define RT5625_P_HPL_VOL_BIT 11 +#define RT5625_P_HPR_VOL (0x1 << 10) +#define RT5625_P_HPR_VOL_BIT 10 +#define RT5625_P_DSP_IF (0x1 << 9) +#define RT5625_P_DSP_IF_BIT 9 +#define RT5625_P_DSP_I2C (0x1 << 8) +#define RT5625_P_DSP_I2C_BIT 8 +#define RT5625_P_LV_L (0x1 << 7) +#define RT5625_P_LV_L_BIT 7 +#define RT5625_P_LV_R (0x1 << 6) +#define RT5625_P_LV_R_BIT 6 +#define RT5625_P_PH_VOL (0x1 << 5) +#define RT5625_P_PH_VOL_BIT 5 +#define RT5625_P_PH_ADMIX (0x1 << 4) +#define RT5625_P_PH_ADMIX_BIT 4 +#define RT5625_P_MIC1_VOL (0x1 << 3) +#define RT5625_P_MIC1_VOL_BIT 3 +#define RT5625_P_MIC2_VOL (0x1 << 2) +#define RT5625_P_MIC2_VOL_BIT 2 +#define RT5625_P_MIC1_BST (0x1 << 1) +#define RT5625_P_MIC1_BST_BIT 1 +#define RT5625_P_MIC2_BST (0x1) +#define RT5625_P_MIC2_BST_BIT 0 + +/* General Purpose Control Register 1 (0x40) */ +#define RT5625_SCLK_MASK (0x1 << 15) +#define RT5625_SCLK_SFT 15 +#define RT5625_SCLK_MCLK (0x0 << 15) +#define RT5625_SCLK_PLL1 (0x1 << 15) +#define RT5625_VSCLK_MASK (0x1 << 4) +#define RT5625_VSCLK_SFT 4 +#define RT5625_VSCLK_PLL2 (0x0<<4) +#define RT5625_VSCLK_EXTCLK (0x1<<4) +#define RT5625_SPK_R_MASK (0x7 << 1) +#define RT5625_SPK_R_SFT 1 +#define RT5625_SPK_R_225V (0x0 << 1) +#define RT5625_SPK_R_200V (0x1 << 1) +#define RT5625_SPK_R_175V (0x2 << 1) +#define RT5625_SPK_R_150V (0x3 << 1) +#define RT5625_SPK_R_125V (0x4 << 1) +#define RT5625_SPK_R_100V (0x5 << 1) + +/* General Purpose Control Register 2 (0x42) */ +#define RT5625_PLL1_S_MASK (0x3 << 12) +#define RT5625_PLL1_S_SFT 12 +#define RT5625_PLL1_S_MCLK (0x0 << 12) +#define RT5625_PLL1_S_BCLK (0x2 << 12) +#define RT5625_PLL1_S_VBCLK (0x3 << 12) + +/* PLL2 Control (0x46) */ +#define RT5625_PLL2_MASK (0x1 << 15) +#define RT5625_PLL2_DIS (0x0 << 15) +#define RT5625_PLL2_EN (0x1 << 15) +#define RT5625_PLL2_R_MASK (0x1) +#define RT5625_PLL2_R_8X (0x0) +#define RT5625_PLL2_R_16X (0x1) + +/* LDO Control (0x48) */ +#define RT5625_LDO_MASK (0x1 << 15) +#define RT5625_LDO_DIS (0x0 << 15) +#define RT5625_LDO_EN (0x1 << 15) +#define RT5625_LDO_VC_MASK (0xf) +#define RT5625_LDO_VC_1_55V (0xf<<0) +#define RT5625_LDO_VC_1_50V (0xe<<0) +#define RT5625_LDO_VC_1_45V (0xd<<0) +#define RT5625_LDO_VC_1_40V (0xc<<0) +#define RT5625_LDO_VC_1_35V (0xb<<0) +#define RT5625_LDO_VC_1_30V (0xa<<0) +#define RT5625_LDO_VC_1_25V (0x9<<0) +#define RT5625_LDO_VC_1_20V (0x8<<0) +#define RT5625_LDO_VC_1_15V (0x7<<0) +#define RT5625_LDO_VC_1_05V (0x6<<0) +#define RT5625_LDO_VC_1_00V (0x5<<0) +#define RT5625_LDO_VC_0_95V (0x4<<0) +#define RT5625_LDO_VC_0_90V (0x3<<0) +#define RT5625_LDO_VC_0_85V (0x2<<0) +#define RT5625_LDO_VC_0_80V (0x1<<0) +#define RT5625_LDO_VC_0_75V (0x0<<0) + +/* GPIO Pin Configuration (0x4c) */ +#define RT5625_GPIO_5 (0x1 << 5) +#define RT5625_GPIO_4 (0x1 << 4) +#define RT5625_GPIO_3 (0x1 << 3) +#define RT5625_GPIO_2 (0x1 << 2) +#define RT5625_GPIO_1 (0x1 << 1) + +/* MISC Control (0x5e) */ +#define RT5625_FAST_VREF_MASK (0x1 << 15) +#define RT5625_FAST_VREF_EN (0x0 << 15) +#define RT5625_FAST_VREF_DIS (0x1 << 15) +#define RT5625_HP_DEPOP_M2 (0x1 << 8) +#define RT5625_HP_DEPOP_M1 (0x1 << 9) +#define RT5625_HPL_MUM_DEPOP (0x1 << 7) +#define RT5625_HPR_MUM_DEPOP (0x1 << 6) +#define RT5625_MUM_DEPOP (0x1 << 5) + +/* Stereo DAC Clock Control 1 (0x60) */ +#define RT5625_BCLK_DIV1_MASK (0xf << 12) +#define RT5625_BCLK_DIV1_1 (0x0 << 12) +#define RT5625_BCLK_DIV1_2 (0x1 << 12) +#define RT5625_BCLK_DIV1_3 (0x2 << 12) +#define RT5625_BCLK_DIV1_4 (0x3 << 12) +#define RT5625_BCLK_DIV1_5 (0x4 << 12) +#define RT5625_BCLK_DIV1_6 (0x5 << 12) +#define RT5625_BCLK_DIV1_7 (0x6 << 12) +#define RT5625_BCLK_DIV1_8 (0x7 << 12) +#define RT5625_BCLK_DIV1_9 (0x8 << 12) +#define RT5625_BCLK_DIV1_10 (0x9 << 12) +#define RT5625_BCLK_DIV1_11 (0xa << 12) +#define RT5625_BCLK_DIV1_12 (0xb << 12) +#define RT5625_BCLK_DIV1_13 (0xc << 12) +#define RT5625_BCLK_DIV1_14 (0xd << 12) +#define RT5625_BCLK_DIV1_15 (0xe << 12) +#define RT5625_BCLK_DIV1_16 (0xf << 12) +#define RT5625_BCLK_DIV2_MASK (0x7 << 8) +#define RT5625_BCLK_DIV2_2 (0x0 << 8) +#define RT5625_BCLK_DIV2_4 (0x1 << 8) +#define RT5625_BCLK_DIV2_8 (0x2 << 8) +#define RT5625_BCLK_DIV2_16 (0x3 << 8) +#define RT5625_BCLK_DIV2_32 (0x4 << 8) +#define RT5625_AD_LRCK_DIV1_MASK (0xf << 4) +#define RT5625_AD_LRCK_DIV1_1 (0x0 << 4) +#define RT5625_AD_LRCK_DIV1_2 (0x1 << 4) +#define RT5625_AD_LRCK_DIV1_3 (0x2 << 4) +#define RT5625_AD_LRCK_DIV1_4 (0x3 << 4) +#define RT5625_AD_LRCK_DIV1_5 (0x4 << 4) +#define RT5625_AD_LRCK_DIV1_6 (0x5 << 4) +#define RT5625_AD_LRCK_DIV1_7 (0x6 << 4) +#define RT5625_AD_LRCK_DIV1_8 (0x7 << 4) +#define RT5625_AD_LRCK_DIV1_9 (0x8 << 4) +#define RT5625_AD_LRCK_DIV1_10 (0x9 << 4) +#define RT5625_AD_LRCK_DIV1_11 (0xa << 4) +#define RT5625_AD_LRCK_DIV1_12 (0xb << 4) +#define RT5625_AD_LRCK_DIV1_13 (0xc << 4) +#define RT5625_AD_LRCK_DIV1_14 (0xd << 4) +#define RT5625_AD_LRCK_DIV1_15 (0xe << 4) +#define RT5625_AD_LRCK_DIV1_16 (0xf << 4) +#define RT5625_AD_LRCK_DIV2_MASK (0x7 << 1) +#define RT5625_AD_LRCK_DIV2_2 (0x0 << 1) +#define RT5625_AD_LRCK_DIV2_4 (0x1 << 1) +#define RT5625_AD_LRCK_DIV2_8 (0x2 << 1) +#define RT5625_AD_LRCK_DIV2_16 (0x3 << 1) +#define RT5625_AD_LRCK_DIV2_32 (0x4 << 1) +#define RT5625_DA_LRCK_DIV_MASK (1) +#define RT5625_DA_LRCK_DIV_32 (0) +#define RT5625_DA_LRCK_DIV_64 (1) + +/* Stereo DAC Clock Control 2 (0x62) */ +#define RT5625_DF_DIV1_MASK (0xF << 12) +#define RT5625_DF_DIV1_1 (0x0 << 12) +#define RT5625_DF_DIV1_2 (0x1 << 12) +#define RT5625_DF_DIV1_3 (0x2 << 12) +#define RT5625_DF_DIV1_4 (0x3 << 12) +#define RT5625_DF_DIV1_5 (0x4 << 12) +#define RT5625_DF_DIV1_6 (0x5 << 12) +#define RT5625_DF_DIV1_7 (0x6 << 12) +#define RT5625_DF_DIV1_8 (0x7 << 12) +#define RT5625_DF_DIV1_9 (0x8 << 12) +#define RT5625_DF_DIV1_10 (0x9 << 12) +#define RT5625_DF_DIV1_11 (0xA << 12) +#define RT5625_DF_DIV1_12 (0xB << 12) +#define RT5625_DF_DIV1_13 (0xC << 12) +#define RT5625_DF_DIV1_14 (0xD << 12) +#define RT5625_DF_DIV1_15 (0xE << 12) +#define RT5625_DF_DIV1_16 (0xF << 12) +#define RT5625_DF_DIV2_MASK (0x7 << 9) +#define RT5625_DF_DIV2_2 (0x0 << 9) +#define RT5625_DF_DIV2_4 (0x1 << 9) +#define RT5625_DF_DIV2_8 (0x2 << 9) +#define RT5625_DF_DIV2_16 (0x3 << 9) +#define RT5625_DF_DIV2_32 (0x4 << 9) +#define RT5625_AF_DIV1_MASK (0xF << 4) +#define RT5625_AF_DIV1_1 (0x0 << 4) +#define RT5625_AF_DIV1_2 (0x1 << 4) +#define RT5625_AF_DIV1_3 (0x2 << 4) +#define RT5625_AF_DIV1_4 (0x3 << 4) +#define RT5625_AF_DIV1_5 (0x4 << 4) +#define RT5625_AF_DIV1_6 (0x5 << 4) +#define RT5625_AF_DIV1_7 (0x6 << 4) +#define RT5625_AF_DIV1_8 (0x7 << 4) +#define RT5625_AF_DIV1_9 (0x8 << 4) +#define RT5625_AF_DIV1_10 (0x9 << 4) +#define RT5625_AF_DIV1_11 (0xA << 4) +#define RT5625_AF_DIV1_12 (0xB << 4) +#define RT5625_AF_DIV1_13 (0xC << 4) +#define RT5625_AF_DIV1_14 (0xD << 4) +#define RT5625_AF_DIV1_15 (0xE << 4) +#define RT5625_AF_DIV1_16 (0xF << 4) +#define RT5625_AF_DIV2_MASK (0x7 << 1) +#define RT5625_AF_DIV2_1 (0x0 << 1) +#define RT5625_AF_DIV2_2 (0x1 << 1) +#define RT5625_AF_DIV2_4 (0x2 << 1) +#define RT5625_AF_DIV2_8 (0x3 << 1) +#define RT5625_AF_DIV2_16 (0x4 << 1) +#define RT5625_AF_DIV2_32 (0x5 << 1) + +/* Voice DAC PCM Clock Control 1 (0x64) */ +#define RT5625_VBCLK_DIV1_MASK (0xF << 12) +#define RT5625_VBCLK_DIV1_1 (0x0 << 12) +#define RT5625_VBCLK_DIV1_2 (0x1 << 12) +#define RT5625_VBCLK_DIV1_3 (0x2 << 12) +#define RT5625_VBCLK_DIV1_4 (0x3 << 12) +#define RT5625_VBCLK_DIV1_5 (0x4 << 12) +#define RT5625_VBCLK_DIV1_6 (0x5 << 12) +#define RT5625_VBCLK_DIV1_7 (0x6 << 12) +#define RT5625_VBCLK_DIV1_8 (0x7 << 12) +#define RT5625_VBCLK_DIV1_9 (0x8 << 12) +#define RT5625_VBCLK_DIV1_10 (0x9 << 12) +#define RT5625_VBCLK_DIV1_11 (0xA << 12) +#define RT5625_VBCLK_DIV1_12 (0xB << 12) +#define RT5625_VBCLK_DIV1_13 (0xC << 12) +#define RT5625_VBCLK_DIV1_14 (0xD << 12) +#define RT5625_VBCLK_DIV1_15 (0xE << 12) +#define RT5625_VBCLK_DIV1_16 (0xF << 12) +#define RT5625_VBCLK_DIV2_MASK (0x7 << 8) +#define RT5625_VBCLK_DIV2_2 (0x0 << 8) +#define RT5625_VBCLK_DIV2_4 (0x1 << 8) +#define RT5625_VBCLK_DIV2_8 (0x2 << 8) +#define RT5625_VBCLK_DIV2_16 (0x3 << 8) +#define RT5625_VBCLK_DIV2_32 (0x4 << 8) +#define RT5625_AD_VLRCK_DIV1_MASK (0xF << 4) +#define RT5625_AD_VLRCK_DIV1_1 (0x0 << 4) +#define RT5625_AD_VLRCK_DIV1_2 (0x1 << 4) +#define RT5625_AD_VLRCK_DIV1_3 (0x2 << 4) +#define RT5625_AD_VLRCK_DIV1_4 (0x3 << 4) +#define RT5625_AD_VLRCK_DIV1_5 (0x4 << 4) +#define RT5625_AD_VLRCK_DIV1_6 (0x5 << 4) +#define RT5625_AD_VLRCK_DIV1_7 (0x6 << 4) +#define RT5625_AD_VLRCK_DIV1_8 (0x7 << 4) +#define RT5625_AD_VLRCK_DIV1_9 (0x8 << 4) +#define RT5625_AD_VLRCK_DIV1_10 (0x9 << 4) +#define RT5625_AD_VLRCK_DIV1_11 (0xA << 4) +#define RT5625_AD_VLRCK_DIV1_12 (0xB << 4) +#define RT5625_AD_VLRCK_DIV1_13 (0xC << 4) +#define RT5625_AD_VLRCK_DIV1_14 (0xD << 4) +#define RT5625_AD_VLRCK_DIV1_15 (0xE << 4) +#define RT5625_AD_VLRCK_DIV1_16 (0xF << 4) +#define RT5625_AD_VLRCK_DIV2_MASK (0x7 << 1) +#define RT5625_AD_VLRCK_DIV2_2 (0x0 << 1) +#define RT5625_AD_VLRCK_DIV2_4 (0x1 << 1) +#define RT5625_AD_VLRCK_DIV2_8 (0x2 << 1) +#define RT5625_AD_VLRCK_DIV2_16 (0x3 << 1) +#define RT5625_AD_VLRCK_DIV2_32 (0x4 << 1) +#define RT5625_DA_VLRCK_DIV_MASK (1) +#define RT5625_DA_VLRCK_DIV_32 (0) +#define RT5625_DA_VLRCK_DIV_64 (1) + +/* Psedueo Stereo & Spatial Effect Block Control (0x68) */ +#define RT5625_SP_CTRL_EN (0x1 << 15) +#define RT5625_APF_EN (0x1 << 14) +#define RT5625_PS_EN (0x1 << 13) +#define RT5625_STO_EXP_EN (0x1 << 12) +#define RT5625_SP_3D_G1_MASK (0x3 << 10) +#define RT5625_SP_3D_G1_1_0 (0x0 << 10) +#define RT5625_SP_3D_G1_1_5 (0x1 << 10) +#define RT5625_SP_3D_G1_2_0 (0x2 << 10) +#define RT5625_SP_3D_R1_MASK (0x3 << 8) +#define RT5625_SP_3D_R1_0_0 (0x0 << 8) +#define RT5625_SP_3D_R1_0_66 (0x1 << 8) +#define RT5625_SP_3D_R1_1_0 (0x2 << 8) +#define RT5625_SP_3D_G2_MASK (0x3 << 6) +#define RT5625_SP_3D_G2_1_0 (0x0 << 6) +#define RT5625_SP_3D_G2_1_5 (0x1 << 6) +#define RT5625_SP_3D_G2_2_0 (0x2 << 6) +#define RT5625_SP_3D_R2_MASK (0x3 << 4) +#define RT5625_SP_3D_R2_0_0 (0x0 << 4) +#define RT5625_SP_3D_R2_0_66 (0x1 << 4) +#define RT5625_SP_3D_R2_1_0 (0x2 << 4) +#define RT5625_APF_MASK (0x3) +#define RT5625_APF_48K (0x3) +#define RT5625_APF_44_1K (0x2) +#define RT5625_APF_32K (0x1) + +/* EQ Control and Status /ADC HPF Control (0x6E) */ +#define RT5625_EN_HW_EQ_BLK (0x1 << 15) +#define RT5625_EQ_SRC_DAC (0x0 << 14) +#define RT5625_EQ_SRC_ADC (0x1 << 14) +#define RT5625_EQ_CHG_EN (0x1 << 7) +#define RT5625_EN_HW_EQ_HPF (0x1 << 4) +#define RT5625_EN_HW_EQ_BP3 (0x1 << 3) +#define RT5625_EN_HW_EQ_BP2 (0x1 << 2) +#define RT5625_EN_HW_EQ_BP1 (0x1 << 1) +#define RT5625_EN_HW_EQ_LPF (0x1 << 0) + +/* VoDSP Register Command (0x74) */ +#define RT5625_DSP_BUSY_MASK (0x1 << 15) +#define RT5625_DSP_DS_MASK (0x1 << 14) +#define RT5625_DSP_DS_VODSP (0x0 << 14) +#define RT5625_DSP_DS_REG72 (0x1 << 14) +#define RT5625_DSP_CLK_MASK (0x3 << 12) +#define RT5625_DSP_CLK_12_288M (0x0 << 12) +#define RT5625_DSP_CLK_6_144M (0x1 << 12) +#define RT5625_DSP_CLK_3_072M (0x2 << 12) +#define RT5625_DSP_CLK_2_048M (0x3 << 12) +#define RT5625_DSP_R_EN (0x1 << 9) +#define RT5625_DSP_W_EN (0x1 << 8) +#define RT5625_DSP_CMD_MASK (0xff) +#define RT5625_DSP_CMD_SFT 0 +#define RT5625_DSP_CMD_MW (0x3B) /* Memory Write */ +#define RT5625_DSP_CMD_MR (0x37) /* Memory Read */ +#define RT5625_DSP_CMD_RR (0x60) /* Register Read */ +#define RT5625_DSP_CMD_RW (0x68) /* Register Write */ + + +/* Index(0x20) for Auto Volume Control */ +#define RT5625_AVC_CH_MASK (0x1 << 7) +#define RT5625_AVC_CH_L_CH (0x0 << 7) +#define RT5625_AVC_CH_R_CH (0x1 << 7) +#define RT5625_AVC_GAIN_EN (0x1 << 15) + + + +enum { + RT5625_AIF1, + RT5625_AIF2, }; -struct rt56xx_cmd -{ - size_t number; - struct rt56xx_reg_state __user *buf; +/* System Clock Source */ +enum { + RT5625_SCLK_S_MCLK, + RT5625_SCLK_S_PLL, }; - -enum -{ - RT_READ_CODEC_REG_IOCTL = _IOR('R', 0x01, struct rt56xx_cmd), - RT_READ_ALL_CODEC_REG_IOCTL = _IOR('R', 0x02, struct rt56xx_cmd), - RT_WRITE_CODEC_REG_IOCTL = _IOW('R', 0x03, struct rt56xx_cmd), -}; - -#endif - - -enum pll_sel -{ - RT5625_PLL1_FROM_MCLK = 0, - RT5625_PLL1_FROM_BCLK, - RT5625_PLL1_FROM_VBCLK, +enum pll_sel { + RT5625_PLL_MCLK = 0, + RT5625_PLL_MCLK_TO_VSYSCLK, + RT5625_PLL_BCLK, + RT5625_PLL_VBCLK, }; -enum AEC_MODE -{ - PCM_IN_PCM_OUT = 0, - ANALOG_IN_ANALOG_OUT, - DAC_IN_ADC_OUT, - VODSP_AEC_DISABLE +enum { + RT5625_AEC_DIS, + RT5625_AEC_EN, }; -enum -{ - PCM_MASTER_MODE_A=0, - PCM_MASTER_MODE_B, - PCM_SLAVE_MODE_A, - PCM_SLAVE_MODE_B, +//#ifdef RT5625_F_SMT_PHO +enum { + RT5625_PLL_DIS, + RT5625_PLL_112896_225792, + RT5625_PLL_112896_24576, }; +//#endif - -enum RT5625_FUNC_SEL -{ - RT5625_AEC_DISABLE =0, - RT5625_AEC_PCM_IN_OUT, - RT5625_AEC_IIS_IN_OUT, - RT5625_AEC_ANALOG_IN_OUT, - -}; - - -struct rt5625_setup_data { - int i2c_bus; - int i2c_address; -}; - -typedef struct -{ - unsigned short int VoiceDSPIndex; - unsigned short int VoiceDSPValue; - -}Voice_DSP_Reg; - -extern struct snd_soc_dai rt5625_dai[]; -extern struct snd_soc_codec_device soc_codec_dev_rt5625; +typedef struct { + unsigned short index; + unsigned short value; +} rt5625_dsp_reg; #endif diff --git a/sound/soc/rk29/rk29_rt5625.c b/sound/soc/rk29/rk29_rt5625.c index fda7169c582e..9a72e440ceb4 100644 --- a/sound/soc/rk29/rk29_rt5625.c +++ b/sound/soc/rk29/rk29_rt5625.c @@ -1,291 +1,247 @@ -/* - * rk29_rt5625.c -- SoC audio for rockchip - * - * Driver for rockchip rt5625 audio - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include "../codecs/rt5625.h" -#include "rk29_pcm.h" -#include "rk29_i2s.h" - -#if 0 -#define DBG(x...) printk(KERN_INFO x) -#else -#define DBG(x...) -#endif - -static int rk29_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 *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int pll_out = 0; - int ret; - - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - /*by Vincent Hsiung for EQ Vol Change*/ - #define HW_PARAMS_FLAG_EQVOL_ON 0x21 - #define HW_PARAMS_FLAG_EQVOL_OFF 0x22 - if (codec_dai->ops->hw_params && ((params->flags == HW_PARAMS_FLAG_EQVOL_ON) || (params->flags == HW_PARAMS_FLAG_EQVOL_OFF))) - { - ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - } else { - - /* set codec DAI configuration */ - #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - #endif - #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); - #endif - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - #endif - #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - #endif - if (ret < 0) - return ret; - } - - switch(params_rate(params)) { - case 8000: - case 16000: - case 24000: - case 32000: - case 48000: - pll_out = 12288000; - break; - case 11025: - case 22050: - case 44100: - pll_out = 11289600; - break; - default: - DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); - return -EINVAL; - break; - } - - DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); - - /*Set the system clk for codec*/ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN); - if (ret < 0) - { - DBG("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n"); - return ret; - } - - snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); - snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1); - snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3); - - DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params)); - - return 0; -} - -static const struct snd_soc_dapm_widget rt5625_dapm_widgets[] = { - - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - -}; - -static const struct snd_soc_dapm_route audio_map[]={ - - /* Mic Jack --> MIC_IN*/ - {"Mic1 Bias", NULL, "Mic Jack"}, - {"Mic1", NULL, "Mic1 Bias"}, - /* HP_OUT --> Headphone Jack */ - {"Headphone Jack", NULL, "HPL"}, - {"Headphone Jack", NULL, "HPR"}, - /* LINE_OUT --> Ext Speaker */ - {"Ext Spk", NULL, "SPKL"}, - {"Ext Spk", NULL, "SPKR"}, -} ; - -/* - * Logic for a rt5625 as connected on a rockchip board. - */ -static int rk29_rt5625_init(struct snd_soc_codec *codec) -{ - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - - /* Add specific widgets */ - snd_soc_dapm_new_controls(codec, rt5625_dapm_widgets, - ARRAY_SIZE(rt5625_dapm_widgets)); - - /* Set up specific audio path audio_mapnects */ - snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - //snd_soc_dapm_nc_pin(codec, "HP_L"); - //snd_soc_dapm_nc_pin(codec, "HP_R"); - snd_soc_dapm_sync(codec); - - return 0; -} - -static int rt5625_voice_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 *codec_dai = rtd->dai->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; - unsigned int pll_out = 0; - int ret; - - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - - /* set codec DAI configuration */ - /*#if defined (CONFIG_SND_CODEC_SOC_SLAVE) - DBG("Enter::%s----codec slave\n",__FUNCTION__); - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - #endif*/ - //#if defined (CONFIG_SND_CODEC_SOC_MASTER) - DBG("Enter::%s----codec master\n",__FUNCTION__); - - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM ); - //#endif - - switch(params_rate(params)) { - case 8000: - case 16000: - case 24000: - case 32000: - case 48000: - pll_out = 12288000; - break; - case 11025: - case 22050: - case 44100: - pll_out = 11289600; - break; - default: - DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); - return -EINVAL; - break; - } - - snd_soc_dai_set_pll(codec_dai, RT5625_PLL1_FROM_MCLK, pll_out, 24576000); - - /*Set the system clk for codec*/ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN); - - if (ret < 0) { - printk("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n"); - return ret; - } - - ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); - - return 0; -} - -static struct snd_soc_ops rk29_ops = { - .hw_params = rk29_hw_params, -}; - -static struct snd_soc_ops rt5625_voice_ops = { - .hw_params = rt5625_voice_hw_params, -}; - -static struct snd_soc_dai_link rk29_dai[] = { - { - .name = "RT5625-1", - .stream_name = "RT5625 PCM-1", - .cpu_dai = &rk29_i2s_dai, - .codec_dai = &rt5625_dai[0], - .init = rk29_rt5625_init, - .ops = &rk29_ops, - }, - { - .name = "RT5625-2", - .stream_name = "RT5625 PCM-2", - .cpu_dai = &rk29_i2s_dai, - .codec_dai = &rt5625_dai[1], - .init = rk29_rt5625_init, - .ops = &rt5625_voice_ops, - } -}; - -static struct snd_soc_card snd_soc_card_rk29 = { - .name = "RK29_RT5625", - .platform = &rk29_soc_platform, - .dai_link = &rk29_dai, - .num_links = 1, -}; - - -static struct snd_soc_device rk29_snd_devdata = { - .card = &snd_soc_card_rk29, - .codec_dev = &soc_codec_dev_rt5625, -}; - -static struct platform_device *rk29_snd_device; - -static int __init audio_card_init(void) -{ - int ret =0; - - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - - rk29_snd_device = platform_device_alloc("soc-audio", -1); - if (!rk29_snd_device) { - DBG("platform device allocation failed\n"); - ret = -ENOMEM; - return ret; - } - platform_set_drvdata(rk29_snd_device, &rk29_snd_devdata); - rk29_snd_devdata.dev = &rk29_snd_device->dev; - ret = platform_device_add(rk29_snd_device); - if (ret) { - DBG("platform device add failed\n"); - platform_device_put(rk29_snd_device); - } - return ret; -} - -static void __exit audio_card_exit(void) -{ - platform_device_unregister(rk29_snd_device); -} - -module_init(audio_card_init); -module_exit(audio_card_exit); -/* Module information */ -MODULE_AUTHOR("rockchip"); -MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface"); -MODULE_LICENSE("GPL"); +/* + * rk29_rt5625.c -- SoC audio for rockchip + * + * Driver for rockchip rt5625 audio + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "../codecs/rt5625.h" +#include "rk29_pcm.h" +#include "rk29_i2s.h" + +#if 1 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) +#endif + +static int rk29_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 *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int pll_out = 0; + int ret; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + /*by Vincent Hsiung for EQ Vol Change*/ + #define HW_PARAMS_FLAG_EQVOL_ON 0x21 + #define HW_PARAMS_FLAG_EQVOL_OFF 0x22 + if (codec_dai->driver->ops->hw_params && ((params->flags == HW_PARAMS_FLAG_EQVOL_ON) || (params->flags == HW_PARAMS_FLAG_EQVOL_OFF))) + { + ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + } else { + + /* set codec DAI configuration */ + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + #endif + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); + #endif + if (ret < 0) + return ret; + + /* set cpu DAI configuration */ + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + #endif + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + #endif + if (ret < 0) + return ret; + } + + switch(params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + pll_out = 12288000; + break; + case 11025: + case 22050: + case 44100: + pll_out = 11289600; + break; + default: + DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); + return -EINVAL; + break; + } + + DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); + + /*Set the system clk for codec*/ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN); + if (ret < 0) + { + DBG("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n"); + return ret; + } + + snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3); + + DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params)); + + return 0; +} + +static int rt5625_voice_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 *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int pll_out = 0; + int ret; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + /* set codec DAI configuration */ + //#if defined (CONFIG_SND_CODEC_SOC_SLAVE) + DBG("Enter::%s----codec slave\n",__FUNCTION__); + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS); + /*#endif + //#if defined (CONFIG_SND_CODEC_SOC_MASTER) + DBG("Enter::%s----codec master\n",__FUNCTION__); + + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM ); + #endif*/ + + switch(params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + pll_out = 12288000; + break; + case 11025: + case 22050: + case 44100: + pll_out = 11289600; + break; + default: + DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params)); + return -EINVAL; + break; + } + + snd_soc_dai_set_pll(codec_dai, RT5625_PLL_MCLK_TO_VSYSCLK, 0, pll_out, 24576000); + + /*Set the system clk for codec*/ + ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN); + + if (ret < 0) { + printk("rk29_hw_params_rt5625:failed to set the sysclk for codec side\n"); + return ret; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + + return 0; +} + +static struct snd_soc_ops rk29_ops = { + .hw_params = rk29_hw_params, +}; + +static struct snd_soc_ops rt5625_voice_ops = { + .hw_params = rt5625_voice_hw_params, +}; + +static struct snd_soc_dai_link rk29_dai[] = { + { + .name = "RT5625 I2S1", + .stream_name = "RT5625 PCM", + .codec_name = "rt5625.0-001f", + .platform_name = "rockchip-audio", + .cpu_dai_name = "rk29_i2s.0", + .codec_dai_name = "rt5625-aif1", + .ops = &rk29_ops, + }, + { + .name = "RT5625 I2S2", + .stream_name = "RT5625 PCM", + .codec_name = "rt5625.0-001f", + .platform_name = "rockchip-audio", + .cpu_dai_name = "rk29_i2s.0", + .codec_dai_name = "rt5625-aif2", + .ops = &rt5625_voice_ops, + }, +}; + +static struct snd_soc_card snd_soc_card_rk29 = { + .name = "RK29_RT5625", + .dai_link = rk29_dai, + .num_links = 2, +}; + +static struct platform_device *rk29_snd_device; + +static int __init audio_card_init(void) +{ + int ret =0; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + rk29_snd_device = platform_device_alloc("soc-audio", -1); + if (!rk29_snd_device) { + printk("platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29); + ret = platform_device_add(rk29_snd_device); + if (ret) { + printk("platform device add failed\n"); + + platform_device_put(rk29_snd_device); + return ret; + } + + return ret; +} + +static void __exit audio_card_exit(void) +{ + platform_device_unregister(rk29_snd_device); +} + +module_init(audio_card_init); +module_exit(audio_card_exit); +/* Module information */ +MODULE_AUTHOR("rockchip"); +MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface"); +MODULE_LICENSE("GPL"); -- 2.34.1