CONFIG_SND_RK29_SOC_I2S_8CH=y
# CONFIG_SND_RK29_SOC_WM8988 is not set
CONFIG_SND_RK29_SOC_WM8900=y
+# CONFIG_SND_RK29_SOC_alc5621 is not set
+# CONFIG_SND_RK29_SOC_alc5631 is not set
# CONFIG_SND_RK29_SOC_WM8994 is not set
# CONFIG_SND_RK29_CODEC_SOC_MASTER is not set
CONFIG_SND_RK29_CODEC_SOC_SLAVE=y
.flags = 0,
},
#endif
+#if defined (CONFIG_SND_SOC_alc5621)
+ {
+ .type = "ALC5621",
+ .addr = 0x1a,
+ .flags = 0,
+ },
+#endif
+#if defined (CONFIG_SND_SOC_alc5631)
+ {
+ .type = "rt5631",
+ .addr = 0x1a,
+ .flags = 0,
+ },
+#endif
#if defined (CONFIG_SND_SOC_RK1000)
{
.type = "rk1000_i2c_codec",
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8900 if I2C
+ select SND_SOC_alc5621 if I2C
+ select SND_SOC_alc5631 if I2C
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8940 if I2C
select SND_SOC_WM8960 if I2C
be selected separately.
If unsure select "N".
-
+select SND_SOC_ALC5623_RT if I2C
+config SND_SOC_ALC5623
+ tristate
config SND_SOC_WM_HUBS
tristate
- default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
- default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
+ default y if SND_SOC_WM8993=y
+ default m if SND_SOC_WM8993=m
config SND_SOC_AC97_CODEC
tristate
config SND_SOC_WM8900
tristate
+config SND_SOC_alc5621
+ tristate
+
+config SND_SOC_alc5631
+ tristate
+
config SND_SOC_WM8903
tristate
snd-soc-wm8753-objs := wm8753.o
snd-soc-wm8776-objs := wm8776.o
snd-soc-wm8900-objs := wm8900.o
+snd-soc-alc5621-objs := alc5621.o
+snd-soc-alc5631-objs := rt5631.o
snd-soc-wm8903-objs := wm8903.o
snd-soc-wm8940-objs := wm8940.o
snd-soc-wm8960-objs := wm8960.o
# Amp
snd-soc-max9877-objs := max9877.o
+snd-soc-alc5623-objs := alc5623_tuning.o
+obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
+obj-$(CONFIG_SND_SOC_alc5621) += snd-soc-alc5621.o
+obj-$(CONFIG_SND_SOC_alc5631) += snd-soc-alc5631.o
obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o
--- /dev/null
+#include <linux/module.h>\r
+#include <linux/moduleparam.h>\r
+#include <linux/version.h>\r
+#include <linux/kernel.h>\r
+#include <linux/init.h>\r
+#include <linux/delay.h>\r
+#include <linux/pm.h>\r
+#include <linux/i2c.h>\r
+#include <linux/platform_device.h>\r
+\r
+#include <sound/core.h>\r
+#include <sound/pcm.h>\r
+#include <sound/pcm_params.h>\r
+#include <sound/soc.h>\r
+#include <sound/soc-dapm.h>\r
+#include <sound/initval.h>\r
+#include <asm/div64.h>\r
+#include "alc5621.h"\r
+\r
+#if REALTEK_HWDEP\r
+\r
+#include <linux/ioctl.h>\r
+#include <linux/types.h>\r
+\r
+#endif\r
+\r
+#define AUDIO_NAME "rt5621"\r
+#define RT5621_VERSION "alsa 1.0.21 0.05"\r
+\r
+#ifdef RT5621_DEBUG\r
+#define dbg(format, arg...) \\r
+ printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)\r
+#else\r
+#define dbg(format, arg...) do {} while (0)\r
+#endif\r
+#define err(format, arg...) \\r
+ printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)\r
+#define info(format, arg...) \\r
+ printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)\r
+#define warn(format, arg...) \\r
+ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)\r
+ \r
+static int caps_charge = 500;\r
+module_param(caps_charge, int, 0);\r
+MODULE_PARM_DESC(caps_charge, "RT5621 cap charge time (msecs)");\r
+\r
+/* codec private data */\r
+struct rt5621_priv {\r
+ unsigned int sysclk;\r
+};\r
+\r
+static struct snd_soc_device *rt5621_socdev;\r
+\r
+struct rt5621_reg{\r
+\r
+ u8 reg_index;\r
+ u16 reg_value;\r
+};\r
+\r
+static struct rt5621_reg init_data[] = {\r
+ {RT5621_AUDIO_INTERFACE, 0x8000}, //set I2S codec to slave mode\r
+ {RT5621_STEREO_DAC_VOL, 0x0808}, //default stereo DAC volume to 0db\r
+ {RT5621_OUTPUT_MIXER_CTRL, 0x0740}, //default output mixer control \r
+ {RT5621_ADC_REC_MIXER, 0x3f3f}, //set record source is Mic1 by default\r
+ {RT5621_MIC_CTRL, 0x0500}, //set Mic1,Mic2 boost 20db \r
+ {RT5621_SPK_OUT_VOL, 0x8080}, //default speaker volume to 0db \r
+ {RT5621_HP_OUT_VOL, 0x8888}, //default HP volume to -12db \r
+ {RT5621_ADD_CTRL_REG, 0x5f00}, //Class AB/D speaker ratio is 1VDD\r
+ {RT5621_STEREO_AD_DA_CLK_CTRL, 0x066d}, //set Dac filter to 256fs\r
+ {RT5621_HID_CTRL_INDEX, 0x46}, //Class D setting\r
+ {RT5621_HID_CTRL_DATA, 0xFFFF}, //power on Class D Internal register\r
+};\r
+\r
+#define RT5621_INIT_REG_NUM ARRAY_SIZE(init_data)\r
+\r
+/*\r
+ * rt5621 register cache\r
+ * We can't read the RT5621 register space when we\r
+ * are using 2 wire for device control, so we cache them instead.\r
+ */\r
+static const u16 rt5621_reg[0x80/2];\r
+\r
+\r
+/* virtual HP mixers regs */\r
+#define HPL_MIXER 0x80\r
+#define HPR_MIXER 0x82\r
+/*reg84*/\r
+/*bit0,1:for hp pga power control\r
+ *bit2,3:for aux pga power control\r
+ */\r
+#define MISC_FUNC_REG 0x84\r
+static u16 reg80=0,reg82=0, reg84 = 0;\r
+\r
+\r
+/*\r
+ * read rt5621 register cache\r
+ */\r
+static inline unsigned int rt5621_read_reg_cache(struct snd_soc_codec *codec,\r
+ unsigned int reg)\r
+{\r
+ u16 *cache = codec->reg_cache;\r
+ if (reg < 1 || reg > (ARRAY_SIZE(rt5621_reg) + 1))\r
+ return -1;\r
+ return cache[reg/2];\r
+}\r
+\r
+\r
+/*\r
+ * write rt5621 register cache\r
+ */\r
+\r
+static inline void rt5621_write_reg_cache(struct snd_soc_codec *codec,\r
+ unsigned int reg, unsigned int value)\r
+{\r
+ u16 *cache = codec->reg_cache;\r
+ if (reg < 0 || reg > 0x7e)\r
+ return;\r
+ cache[reg/2] = value;\r
+}\r
+\r
+\r
+\r
+static int rt5621_write(struct snd_soc_codec *codec, unsigned int reg,\r
+ unsigned int value)\r
+{\r
+ u8 data[3];\r
+\r
+ if(reg>0x7E)\r
+ {\r
+ if(reg==HPL_MIXER)\r
+ reg80=value;\r
+ else if(reg==HPR_MIXER)\r
+ reg82=value;\r
+ else if (reg == MISC_FUNC_REG)\r
+ reg84 = value;\r
+ else\r
+ return -EIO;\r
+ \r
+ return 0; \r
+ } \r
+\r
+\r
+ printk("rt5621 write reg=%x,value=%x\n",reg,value);\r
+ data[0] = reg;\r
+ data[1] = (0xFF00 & value) >> 8;\r
+ data[2] = 0x00FF & value;\r
+\r
+ if (codec->hw_write(codec->control_data, data, 3) == 3)\r
+ {\r
+ rt5621_write_reg_cache (codec, reg, value); \r
+ printk(KERN_INFO "rt5621 write reg=%x,value=%x\n",reg,value);\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ printk(KERN_ERR "rt5621 write faile\n");\r
+ return -EIO;\r
+ }\r
+}\r
+\r
+\r
+static unsigned int rt5621_read(struct snd_soc_codec *codec, unsigned int reg)\r
+{\r
+ u8 data[2]={0};\r
+ unsigned int value=0x0;\r
+\r
+ if(reg>0x7E)\r
+ {\r
+ if(reg==HPL_MIXER)\r
+ return reg80;\r
+ else if(reg==HPR_MIXER)\r
+ return reg82;\r
+ else if (reg == MISC_FUNC_REG)\r
+ return reg84;\r
+ else\r
+ return -EIO;\r
+ \r
+ return -EIO; \r
+ }\r
+\r
+\r
+ data[0] = reg;\r
+//flove031811_S\r
+#if 0\r
+ i2c_master_recv(codec->control_data, data, 2);\r
+ \r
+ value = (data[0]<<8) | data[1]; \r
+ printk("rt5621_read reg%x=%x\n",reg,value);\r
+#elif 1\r
+\r
+ i2c_master_reg8_recv(codec->control_data,reg,data, 2,100 * 1000);\r
+\r
+ value = (data[0]<<8) | data[1]; \r
+ printk("rt5621_read reg%x=%x\n",reg,value);\r
+ return value;\r
+\r
+#else \r
+ if(codec->hw_write(codec->control_data, data, 1) ==1)\r
+ {\r
+ i2c_master_recv(codec->control_data, data, 2);\r
+\r
+ value = (data[0]<<8) | data[1]; \r
+ printk(KERN_DEBUG "rt5621 read reg%x=%x\n",reg,value);\r
+ \r
+ return value;\r
+ }\r
+ else\r
+ {\r
+ printk(KERN_ERR "rt5621 read faile\n");\r
+ return -EIO; \r
+ } \r
+#endif\r
+//flove031811_E \r
+}\r
+\r
+#define rt5621_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value)\r
+\r
+\r
+#define rt5621_reset(c) rt5621_write(c, 0x0, 0)\r
+\r
+static unsigned int rt5621_read_index(struct snd_soc_codec *codec, unsigned int index)\r
+{\r
+ unsigned int value;\r
+\r
+ rt5621_write(codec, 0x6a, index);\r
+ mdelay(1);\r
+ value = rt5621_read(codec, 0x6c);\r
+ return value;\r
+}\r
+\r
+static int rt5621_init_reg(struct snd_soc_codec *codec)\r
+{\r
+ int i;\r
+\r
+ for (i = 0; i < RT5621_INIT_REG_NUM; i++)\r
+ {\r
+ rt5621_write(codec, init_data[i].reg_index, init_data[i].reg_value);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+#if !USE_DAPM_CONTROL\r
+//*****************************************************************************\r
+//\r
+//function:Change audio codec power status\r
+//\r
+//*****************************************************************************\r
+static int rt5621_ChangeCodecPowerStatus(struct snd_soc_codec *codec,int power_state)\r
+{\r
+ unsigned short int PowerDownState=0;\r
+\r
+ switch(power_state)\r
+ {\r
+ case POWER_STATE_D0: //FULL ON-----power on all power\r
+ \r
+ rt5621_write(codec,RT5621_PWR_MANAG_ADD1,~PowerDownState);\r
+ rt5621_write(codec,RT5621_PWR_MANAG_ADD2,~PowerDownState);\r
+ rt5621_write(codec,RT5621_PWR_MANAG_ADD3,~PowerDownState);\r
+\r
+ break; \r
+\r
+ case POWER_STATE_D1: //LOW ON-----\r
+\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,PWR_VREF |PWR_DAC_REF_CIR |PWR_L_DAC_CLK |PWR_R_DAC_CLK |PWR_L_HP_MIXER |PWR_R_HP_MIXER|\r
+ PWR_L_ADC_CLK_GAIN |PWR_R_ADC_CLK_GAIN |PWR_L_ADC_REC_MIXER |PWR_R_ADC_REC_MIXER|PWR_CLASS_AB\r
+ ,PWR_VREF |PWR_DAC_REF_CIR |PWR_L_DAC_CLK |PWR_R_DAC_CLK |PWR_L_HP_MIXER |PWR_R_HP_MIXER|\r
+ PWR_L_ADC_CLK_GAIN |PWR_R_ADC_CLK_GAIN |PWR_L_ADC_REC_MIXER |PWR_R_ADC_REC_MIXER|PWR_CLASS_AB);\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT|\r
+ PWR_MIC1_FUN_CTRL|PWR_MIC1_BOOST_MIXER\r
+ ,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT|\r
+ PWR_MIC1_FUN_CTRL|PWR_MIC1_BOOST_MIXER); \r
+\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP|PWR_MIC1_BIAS_EN\r
+ ,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP|PWR_MIC1_BIAS_EN);\r
+ \r
+ break;\r
+\r
+ case POWER_STATE_D1_PLAYBACK: //Low on of Playback\r
+\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2,PWR_VREF|PWR_DAC_REF_CIR|PWR_L_DAC_CLK|PWR_R_DAC_CLK|PWR_L_HP_MIXER|PWR_R_HP_MIXER|PWR_CLASS_AB|PWR_CLASS_D\r
+ ,PWR_VREF|PWR_DAC_REF_CIR|PWR_L_DAC_CLK|PWR_R_DAC_CLK|PWR_L_HP_MIXER|PWR_R_HP_MIXER|PWR_CLASS_AB|PWR_CLASS_D);\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT \r
+ ,PWR_MAIN_BIAS|PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT); \r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP\r
+ ,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP);\r
+ \r
+\r
+ break;\r
+\r
+ case POWER_STATE_D1_RECORD: //Low on of Record\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,PWR_MAIN_I2S_EN|PWR_MIC1_BIAS_EN\r
+ ,PWR_MAIN_I2S_EN|PWR_MIC1_BIAS_EN); \r
+ \r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,PWR_VREF|PWR_L_ADC_CLK_GAIN|PWR_R_ADC_CLK_GAIN|PWR_L_ADC_REC_MIXER|PWR_R_ADC_REC_MIXER\r
+ ,PWR_VREF|PWR_L_ADC_CLK_GAIN|PWR_R_ADC_CLK_GAIN|PWR_L_ADC_REC_MIXER|PWR_R_ADC_REC_MIXER);\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,PWR_MAIN_BIAS|PWR_MIC2_BOOST_MIXER|PWR_MIC1_BOOST_MIXER\r
+ ,PWR_MAIN_BIAS|PWR_MIC2_BOOST_MIXER|PWR_MIC1_BOOST_MIXER); \r
+ \r
+ break;\r
+\r
+ case POWER_STATE_D2: //STANDBY----\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_MAIN_I2S_EN|PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP|PWR_MIC1_BIAS_EN); \r
+\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,0,PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|PWR_SPK_OUT|PWR_MIC1_FUN_CTRL|PWR_MIC1_BOOST_MIXER);\r
+\r
+ \r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,0,PWR_DAC_REF_CIR |PWR_L_DAC_CLK |PWR_R_DAC_CLK |PWR_L_HP_MIXER |PWR_R_HP_MIXER|\r
+ PWR_L_ADC_CLK_GAIN |PWR_R_ADC_CLK_GAIN |PWR_L_ADC_REC_MIXER |PWR_R_ADC_REC_MIXER|PWR_CLASS_AB|PWR_CLASS_D);\r
+\r
+ \r
+ break;\r
+\r
+ case POWER_STATE_D2_PLAYBACK: //STANDBY of playback\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,0,/*PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL|*/PWR_SPK_OUT);\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP); \r
+ \r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,0,PWR_DAC_REF_CIR|PWR_L_DAC_CLK|PWR_R_DAC_CLK|PWR_L_HP_MIXER|PWR_R_HP_MIXER|PWR_CLASS_AB|PWR_CLASS_D);\r
+\r
+ break;\r
+\r
+ case POWER_STATE_D2_RECORD: //STANDBY of record\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_MIC1_BIAS_EN); \r
+ \r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2 ,0,PWR_L_ADC_CLK_GAIN|PWR_R_ADC_CLK_GAIN|PWR_L_ADC_REC_MIXER|PWR_R_ADC_REC_MIXER);\r
+\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD3 ,0,PWR_MIC2_BOOST_MIXER|PWR_MIC1_BOOST_MIXER); \r
+\r
+ break; \r
+\r
+ case POWER_STATE_D3: //SLEEP\r
+ case POWER_STATE_D4: //OFF----power off all power\r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD1 ,0,PWR_HP_OUT_ENH_AMP|PWR_HP_OUT_AMP); \r
+ rt5621_write(codec,RT5621_PWR_MANAG_ADD3,0);\r
+ rt5621_write(codec,RT5621_PWR_MANAG_ADD1,0);\r
+ rt5621_write(codec,RT5621_PWR_MANAG_ADD2,0);\r
+ \r
+ break; \r
+\r
+ default:\r
+\r
+ break;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+//*****************************************************************************\r
+//\r
+//function AudioOutEnable:Mute/Unmute audio out channel\r
+// WavOutPath:output channel\r
+// Mute :Mute/Unmute output channel \r
+//\r
+//*****************************************************************************\r
+static int rt5621_AudioOutEnable(struct snd_soc_codec *codec,unsigned short int WavOutPath,int Mute)\r
+{\r
+ int RetVal=0; \r
+\r
+ if(Mute)\r
+ {\r
+ switch(WavOutPath)\r
+ {\r
+ case RT_WAVOUT_ALL_ON:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute Speaker right/left channel\r
+ RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel\r
+ RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute Aux/Mono right/left channel\r
+ RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER\r
+ ,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer\r
+ \r
+ break;\r
+ \r
+ case RT_WAVOUT_HP:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel\r
+ \r
+ break;\r
+\r
+ case RT_WAVOUT_SPK:\r
+ \r
+ RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute Speaker right/left channel \r
+\r
+ break;\r
+ \r
+ case RT_WAVOUT_AUXOUT:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE); //Mute AuxOut right/left channel\r
+\r
+ break;\r
+\r
+ case RT_WAVOUT_MONO:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,RT_L_MUTE,RT_L_MUTE); //Mute MonoOut channel \r
+\r
+ break;\r
+\r
+ case RT_WAVOUT_DAC:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER\r
+ ,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer \r
+ break;\r
+\r
+ default:\r
+\r
+ return 0;\r
+\r
+ }\r
+ }\r
+ else\r
+ {\r
+ switch(WavOutPath)\r
+ {\r
+\r
+ case RT_WAVOUT_ALL_ON:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL ,0,RT_L_MUTE|RT_R_MUTE); //Mute Speaker right/left channel\r
+ RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL ,0,RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel\r
+ RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL ,0,RT_L_MUTE|RT_R_MUTE); //Mute Aux/Mono right/left channel\r
+ RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL ,0,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //Mute DAC to HP,Speaker,Mono Mixer\r
+ \r
+ break;\r
+ \r
+ case RT_WAVOUT_HP:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_HP_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); //UnMute headphone right/left channel \r
+ \r
+ break;\r
+\r
+ case RT_WAVOUT_SPK:\r
+ \r
+ RetVal=rt5621_write_mask(codec,RT5621_SPK_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE); //unMute Speaker right/left channel \r
+\r
+ break;\r
+ \r
+ case RT_WAVOUT_AUXOUT:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE);//unMute AuxOut right/left channel\r
+\r
+ break;\r
+\r
+ case RT_WAVOUT_MONO:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_MONO_AUX_OUT_VOL,0,RT_L_MUTE); //unMute MonoOut channel \r
+\r
+ break;\r
+\r
+ case RT_WAVOUT_DAC:\r
+\r
+ RetVal=rt5621_write_mask(codec,RT5621_STEREO_DAC_VOL,0,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); //unMute DAC to HP,Speaker,Mono Mixer\r
+\r
+ default:\r
+ return 0;\r
+ }\r
+\r
+ }\r
+ \r
+ return RetVal;\r
+}\r
+\r
+\r
+//*****************************************************************************\r
+//\r
+//function:Enable/Disable ADC input source control\r
+//\r
+//*****************************************************************************\r
+static int Enable_ADC_Input_Source(struct snd_soc_codec *codec,unsigned short int ADC_Input_Sour,int Enable)\r
+{\r
+ int bRetVal=0;\r
+ \r
+ if(Enable)\r
+ {\r
+ //Enable ADC source \r
+ bRetVal=rt5621_write_mask(codec,RT5621_ADC_REC_MIXER,0,ADC_Input_Sour);\r
+ }\r
+ else\r
+ {\r
+ //Disable ADC source \r
+ bRetVal=rt5621_write_mask(codec,RT5621_ADC_REC_MIXER,ADC_Input_Sour,ADC_Input_Sour);\r
+ }\r
+\r
+ return bRetVal;\r
+}\r
+#endif\r
+\r
+\r
+//static const char *rt5621_spkl_pga[] = {"Vmid","HPL mixer","SPK mixer","Mono Mixer"};\r
+static const char *rt5621_spkn_source_sel[] = {"RN", "RP", "LN"};\r
+static const char *rt5621_spk_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"};\r
+static const char *rt5621_hpl_pga[] = {"Vmid","HPL mixer"};\r
+static const char *rt5621_hpr_pga[] = {"Vmid","HPR mixer"};\r
+static const char *rt5621_mono_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"};\r
+static const char *rt5621_amp_type_sel[] = {"Class AB","Class D"};\r
+static const char *rt5621_mic_boost_sel[] = {"Bypass","20db","30db","40db"};\r
+\r
+static const struct soc_enum rt5621_enum[] = {\r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 14, 3, rt5621_spkn_source_sel), /* spkn source from hp mixer */ \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 10, 4, rt5621_spk_pga), /* spk input sel 1 */ \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 9, 2, rt5621_hpl_pga), /* hp left input sel 2 */ \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 8, 2, rt5621_hpr_pga), /* hp right input sel 3 */ \r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL, 6, 4, rt5621_mono_pga), /* mono input sel 4 */\r
+SOC_ENUM_SINGLE(RT5621_MIC_CTRL , 10,4, rt5621_mic_boost_sel), /*Mic1 boost sel 5 */\r
+SOC_ENUM_SINGLE(RT5621_MIC_CTRL , 8,4,rt5621_mic_boost_sel), /*Mic2 boost sel 6 */\r
+SOC_ENUM_SINGLE(RT5621_OUTPUT_MIXER_CTRL,13,2,rt5621_amp_type_sel), /*Speaker AMP sel 7 */\r
+};\r
+\r
+static int rt5621_amp_sel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)\r
+{\r
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);\r
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;\r
+ unsigned short val;\r
+ unsigned short mask, bitmask;\r
+\r
+ for (bitmask = 1; bitmask < e->max; bitmask <<= 1)\r
+ ;\r
+ if (ucontrol->value.enumerated.item[0] > e->max - 1)\r
+ return -EINVAL;\r
+ val = ucontrol->value.enumerated.item[0] << e->shift_l;\r
+ mask = (bitmask - 1) << e->shift_l;\r
+ if (e->shift_l != e->shift_r) {\r
+ if (ucontrol->value.enumerated.item[1] > e->max - 1)\r
+ return -EINVAL;\r
+ val |= ucontrol->value.enumerated.item[1] << e->shift_r;\r
+ mask |= (bitmask - 1) << e->shift_r;\r
+ }\r
+\r
+ snd_soc_update_bits(codec, e->reg, mask, val);\r
+ val &= (0x1 << 13);\r
+ if (val == 0)\r
+ {\r
+ snd_soc_update_bits(codec, 0x3c, 0x0000, 0x4000); /*power off classd*/\r
+ snd_soc_update_bits(codec, 0x3c, 0x8000, 0x8000); /*power on classab*/\r
+ }\r
+ else\r
+ {\r
+ snd_soc_update_bits(codec, 0x3c, 0x0000, 0x8000); /*power off classab*/\r
+ snd_soc_update_bits(codec, 0x3c, 0x4000, 0x4000); /*power on classd*/\r
+ }\r
+ return 0;\r
+}\r
+\r
+\r
+\r
+static const struct snd_kcontrol_new rt5621_snd_controls[] = {\r
+SOC_DOUBLE("Speaker Playback Volume", RT5621_SPK_OUT_VOL, 8, 0, 31, 1), \r
+SOC_DOUBLE("Speaker Playback Switch", RT5621_SPK_OUT_VOL, 15, 7, 1, 1),\r
+SOC_DOUBLE("Headphone Playback Volume", RT5621_HP_OUT_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("Headphone Playback Switch", RT5621_HP_OUT_VOL,15, 7, 1, 1),\r
+SOC_DOUBLE("AUX Playback Volume", RT5621_MONO_AUX_OUT_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("AUX Playback Switch", RT5621_MONO_AUX_OUT_VOL, 15, 7, 1, 1),\r
+SOC_DOUBLE("PCM Playback Volume", RT5621_STEREO_DAC_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("Line In Volume", RT5621_LINE_IN_VOL, 8, 0, 31, 1),\r
+SOC_SINGLE("Mic 1 Volume", RT5621_MIC_VOL, 8, 31, 1),\r
+SOC_SINGLE("Mic 2 Volume", RT5621_MIC_VOL, 0, 31, 1),\r
+SOC_ENUM("Mic 1 Boost", rt5621_enum[5]),\r
+SOC_ENUM("Mic 2 Boost", rt5621_enum[6]),\r
+SOC_ENUM_EXT("Speaker Amp Type", rt5621_enum[7], snd_soc_get_enum_double, rt5621_amp_sel_put),\r
+SOC_DOUBLE("AUX In Volume", RT5621_AUXIN_VOL, 8, 0, 31, 1),\r
+SOC_DOUBLE("Capture Volume", RT5621_ADC_REC_GAIN, 7, 0, 31, 0),\r
+};\r
+\r
+\r
+\r
+/* add non dapm controls */\r
+static int rt5621_add_controls(struct snd_soc_codec *codec)\r
+{\r
+ int err, i;\r
+\r
+ for (i = 0; i < ARRAY_SIZE(rt5621_snd_controls); i++) {\r
+ err = snd_ctl_add(codec->card,\r
+ snd_soc_cnew(&rt5621_snd_controls[i],codec, NULL));\r
+ if (err < 0)\r
+ return err;\r
+ }\r
+ return 0;\r
+}\r
+\r
+void hp_depop_mode2(struct snd_soc_codec *codec)\r
+{\r
+ rt5621_write_mask(codec, 0x3e, 0x8000, 0x8000);\r
+ rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+ rt5621_write_mask(codec, 0x3a, 0x0100, 0x0100);\r
+ rt5621_write_mask(codec, 0x3c, 0x2000, 0x2000);\r
+ rt5621_write_mask(codec, 0x3e, 0x0600, 0x0600);\r
+ rt5621_write_mask(codec, 0x5e, 0x0200, 0x0200);\r
+ schedule_timeout_uninterruptible(msecs_to_jiffies(300));\r
+}\r
+\r
+void aux_depop_mode2(struct snd_soc_codec *codec)\r
+{\r
+ rt5621_write_mask(codec, 0x3e, 0x8000, 0x8000);\r
+ rt5621_write_mask(codec, 0x06, 0x8080, 0x8080);\r
+ rt5621_write_mask(codec, 0x3a, 0x0100, 0x0100);\r
+ rt5621_write_mask(codec, 0x3c, 0x2000, 0x2000);\r
+ rt5621_write_mask(codec, 0x3e, 0x6000, 0x6000);\r
+ rt5621_write_mask(codec, 0x5e, 0x0020, 0x0200);\r
+ schedule_timeout_uninterruptible(msecs_to_jiffies(300));\r
+ rt5621_write_mask(codec, 0x3a, 0x0002, 0x0002);\r
+ rt5621_write_mask(codec, 0x3a, 0x0001, 0x0001); \r
+}\r
+#if USE_DAPM_CONTROL\r
+\r
+/*\r
+ * _DAPM_ Controls\r
+ */\r
+\r
+/* We have to create a fake left and right HP mixers because\r
+ * the codec only has a single control that is shared by both channels.\r
+ * This makes it impossible to determine the audio path using the current\r
+ * register map, thus we add a new (virtual) register to help determine the\r
+ * audio route within the device.\r
+ */\r
+ static int mixer_event (struct snd_soc_dapm_widget *w, \r
+ struct snd_kcontrol *kcontrol, int event)\r
+{\r
+\r
+ u16 l, r, lineIn,mic1,mic2, aux, pcm;\r
+\r
+ l = rt5621_read(w->codec, HPL_MIXER);\r
+ r = rt5621_read(w->codec, HPR_MIXER);\r
+ lineIn = rt5621_read(w->codec, RT5621_LINE_IN_VOL);\r
+ mic2 = rt5621_read(w->codec, RT5621_MIC_ROUTING_CTRL);\r
+ aux = rt5621_read(w->codec,RT5621_AUXIN_VOL);\r
+ pcm = rt5621_read(w->codec, RT5621_STEREO_DAC_VOL);\r
+\r
+\r
+ if (event & SND_SOC_DAPM_PRE_REG)\r
+ return 0;\r
+\r
+ if (l & 0x1 || r & 0x1)\r
+ rt5621_write(w->codec, RT5621_STEREO_DAC_VOL, pcm & 0x7fff);\r
+ else\r
+ rt5621_write(w->codec, RT5621_STEREO_DAC_VOL, pcm | 0x8000);\r
+\r
+ if (l & 0x2 || r & 0x2)\r
+ rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic2 & 0xff7f);\r
+ else\r
+ rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic2 | 0x0080);\r
+\r
+ mic1 = rt5621_read(w->codec, RT5621_MIC_ROUTING_CTRL);\r
+ if (l & 0x4 || r & 0x4)\r
+ rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic1 & 0x7fff);\r
+ else\r
+ rt5621_write(w->codec, RT5621_MIC_ROUTING_CTRL, mic1 | 0x8000);\r
+\r
+ if (l & 0x8 || r & 0x8)\r
+ rt5621_write(w->codec, RT5621_AUXIN_VOL, aux & 0x7fff);\r
+ else\r
+ rt5621_write(w->codec, RT5621_AUXIN_VOL, aux | 0x8000);\r
+\r
+ if (l & 0x10 || r & 0x10)\r
+ rt5621_write(w->codec, RT5621_LINE_IN_VOL, lineIn & 0x7fff);\r
+ else\r
+ rt5621_write(w->codec, RT5621_LINE_IN_VOL, lineIn | 0x8000);\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static int hp_event(struct snd_soc_dapm_widget *w, \r
+ struct snd_kcontrol *kcontrol, int event)\r
+{\r
+ struct snd_soc_codec *codec = w->codec;\r
+ unsigned int reg = rt5621_read(codec, MISC_FUNC_REG);\r
+ \r
+ if (((reg & 0x03) != 0x00) && ((reg & 0x03) != 0x03))\r
+ return 0;\r
+ \r
+ switch (event)\r
+ {\r
+ case SND_SOC_DAPM_POST_PMU:\r
+ hp_depop_mode2(codec);\r
+ rt5621_write_mask(codec, 0x04, 0x0000, 0x8080);\r
+ rt5621_write_mask(codec, 0x3a, 0x0020, 0x0020);\r
+ break;\r
+ case SND_SOC_DAPM_POST_PMD:\r
+ rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+ rt5621_write_mask(codec, 0x3a, 0x0000, 0x0010);\r
+ rt5621_write_mask(codec, 0x3a, 0x0000, 0x0020);\r
+ rt5621_write_mask(codec, 0x3e, 0x0000, 0x0600);\r
+ break; \r
+ }\r
+ return 0;\r
+}\r
+\r
+static int aux_event(struct snd_soc_dapm_widget *w, \r
+ struct snd_kcontrol *kcontrol, int event)\r
+{\r
+ struct snd_soc_codec *codec = w->codec;\r
+ unsigned int reg = rt5621_read(codec, MISC_FUNC_REG);\r
+ \r
+ if (((reg & 0x0c) != 0x00) && ((reg & 0x0c) != 0x0c))\r
+ return 0;\r
+ \r
+ switch (event)\r
+ {\r
+ case SND_SOC_DAPM_POST_PMU:\r
+ aux_depop_mode2(codec);\r
+ rt5621_write_mask(codec, 0x06, 0x0000, 0x8080);\r
+ break;\r
+ case SND_SOC_DAPM_POST_PMD:\r
+ rt5621_write_mask(codec, 0x06, 0x8080, 0x8080);\r
+ rt5621_write_mask(codec, 0x3a, 0x0000, 0x0001);\r
+ rt5621_write_mask(codec, 0x3a, 0x0000, 0x0002);\r
+ rt5621_write_mask(codec, 0x3e, 0x0000, 0x6000); \r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+\r
+/* Left Headphone Mixers */\r
+static const struct snd_kcontrol_new rt5621_hpl_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 4, 1, 0),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", HPL_MIXER, 3, 1, 0),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", HPL_MIXER, 2, 1, 0),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 1, 1, 0),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 0, 1, 0),\r
+SOC_DAPM_SINGLE("RecordL Playback Switch", RT5621_ADC_REC_GAIN, 15, 1,1),\r
+};\r
+\r
+/* Right Headphone Mixers */\r
+static const struct snd_kcontrol_new rt5621_hpr_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 4, 1, 0),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", HPR_MIXER, 3, 1, 0),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", HPR_MIXER, 2, 1, 0),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 1, 1, 0),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 0, 1, 0),\r
+SOC_DAPM_SINGLE("RecordR Playback Switch", RT5621_ADC_REC_GAIN, 14, 1,1),\r
+};\r
+\r
+//Left Record Mixer\r
+static const struct snd_kcontrol_new rt5621_captureL_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5621_ADC_REC_MIXER, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5621_ADC_REC_MIXER, 13, 1, 1),\r
+SOC_DAPM_SINGLE("LineInL Capture Switch",RT5621_ADC_REC_MIXER,12, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Capture Switch", RT5621_ADC_REC_MIXER, 11, 1, 1),\r
+SOC_DAPM_SINGLE("HPMixerL Capture Switch", RT5621_ADC_REC_MIXER,10, 1, 1),\r
+SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5621_ADC_REC_MIXER,9, 1, 1),\r
+SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5621_ADC_REC_MIXER,8, 1, 1),\r
+};\r
+\r
+\r
+//Right Record Mixer\r
+static const struct snd_kcontrol_new rt5621_captureR_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5621_ADC_REC_MIXER, 6, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5621_ADC_REC_MIXER, 5, 1, 1),\r
+SOC_DAPM_SINGLE("LineInR Capture Switch",RT5621_ADC_REC_MIXER,4, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Capture Switch", RT5621_ADC_REC_MIXER, 3, 1, 1),\r
+SOC_DAPM_SINGLE("HPMixerR Capture Switch", RT5621_ADC_REC_MIXER,2, 1, 1),\r
+SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5621_ADC_REC_MIXER,1, 1, 1),\r
+SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5621_ADC_REC_MIXER,0, 1, 1),\r
+};\r
+\r
+/* Speaker Mixer */\r
+static const struct snd_kcontrol_new rt5621_speaker_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", RT5621_LINE_IN_VOL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", RT5621_AUXIN_VOL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5621_MIC_ROUTING_CTRL, 14, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5621_MIC_ROUTING_CTRL, 6, 1, 1),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", RT5621_STEREO_DAC_VOL, 14, 1, 1),\r
+};\r
+\r
+\r
+/* Mono Mixer */\r
+static const struct snd_kcontrol_new rt5621_mono_mixer_controls[] = {\r
+SOC_DAPM_SINGLE("LineIn Playback Switch", RT5621_LINE_IN_VOL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5621_MIC_ROUTING_CTRL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5621_MIC_ROUTING_CTRL, 5, 1, 1),\r
+SOC_DAPM_SINGLE("AUXIN Playback Switch", RT5621_AUXIN_VOL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("PCM Playback Switch", RT5621_STEREO_DAC_VOL, 13, 1, 1),\r
+SOC_DAPM_SINGLE("RecordL Playback Switch", RT5621_ADC_REC_GAIN, 13, 1,1),\r
+SOC_DAPM_SINGLE("RecordR Playback Switch", RT5621_ADC_REC_GAIN, 12, 1,1),\r
+};\r
+\r
+/* mono output mux */\r
+static const struct snd_kcontrol_new rt5621_mono_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[4]);\r
+\r
+/* speaker left output mux */\r
+static const struct snd_kcontrol_new rt5621_hp_spk_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[1]);\r
+\r
+\r
+/* headphone left output mux */\r
+static const struct snd_kcontrol_new rt5621_hpl_out_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[2]);\r
+\r
+/* headphone right output mux */\r
+static const struct snd_kcontrol_new rt5621_hpr_out_mux_controls =\r
+SOC_DAPM_ENUM("Route", rt5621_enum[3]);\r
+\r
+static const struct snd_soc_dapm_widget rt5621_dapm_widgets[] = {\r
+SND_SOC_DAPM_MUX("Mono Out Mux", SND_SOC_NOPM, 0, 0,\r
+ &rt5621_mono_mux_controls),\r
+SND_SOC_DAPM_MUX("Speaker Out Mux", SND_SOC_NOPM, 0, 0,\r
+ &rt5621_hp_spk_mux_controls),\r
+SND_SOC_DAPM_MUX("Left Headphone Out Mux", SND_SOC_NOPM, 0, 0,\r
+ &rt5621_hpl_out_mux_controls),\r
+SND_SOC_DAPM_MUX("Right Headphone Out Mux", SND_SOC_NOPM, 0, 0,\r
+ &rt5621_hpr_out_mux_controls),\r
+ \r
+SND_SOC_DAPM_MIXER_E("Left HP Mixer",RT5621_PWR_MANAG_ADD2, 5, 0,\r
+ &rt5621_hpl_mixer_controls[0], ARRAY_SIZE(rt5621_hpl_mixer_controls),\r
+ mixer_event, SND_SOC_DAPM_POST_REG), \r
+SND_SOC_DAPM_MIXER_E("Right HP Mixer",RT5621_PWR_MANAG_ADD2, 4, 0,\r
+ &rt5621_hpr_mixer_controls[0], ARRAY_SIZE(rt5621_hpr_mixer_controls),\r
+ mixer_event, SND_SOC_DAPM_POST_REG), \r
+SND_SOC_DAPM_MIXER("Mono Mixer", RT5621_PWR_MANAG_ADD2, 2, 0,\r
+ &rt5621_mono_mixer_controls[0], ARRAY_SIZE(rt5621_mono_mixer_controls)),\r
+ \r
+SND_SOC_DAPM_MIXER("Speaker Mixer", RT5621_PWR_MANAG_ADD2,3,0,\r
+ &rt5621_speaker_mixer_controls[0], ARRAY_SIZE(rt5621_speaker_mixer_controls)), \r
+ \r
+SND_SOC_DAPM_MIXER("Left Record Mixer", RT5621_PWR_MANAG_ADD2,1,0,\r
+ &rt5621_captureL_mixer_controls[0], ARRAY_SIZE(rt5621_captureL_mixer_controls)), \r
+SND_SOC_DAPM_MIXER("Right Record Mixer", RT5621_PWR_MANAG_ADD2,0,0,\r
+ &rt5621_captureR_mixer_controls[0], ARRAY_SIZE(rt5621_captureR_mixer_controls)), \r
+ \r
+SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", RT5621_PWR_MANAG_ADD2,9, 0),\r
+SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", RT5621_PWR_MANAG_ADD2, 8, 0),\r
+\r
+SND_SOC_DAPM_MIXER("IIS Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+SND_SOC_DAPM_MIXER("AUXIN Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", RT5621_PWR_MANAG_ADD2, 7, 0),\r
+SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", RT5621_PWR_MANAG_ADD2, 6, 0),\r
+\r
+SND_SOC_DAPM_PGA_E("Left Headphone", MISC_FUNC_REG, 0, 0, NULL, 0, \r
+ hp_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+SND_SOC_DAPM_PGA_E("Right Headphone", MISC_FUNC_REG, 1, 0, NULL, 0, \r
+ hp_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+\r
+SND_SOC_DAPM_PGA("Speaker PGA", RT5621_PWR_MANAG_ADD3, 12, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_PGA_E("AUXL Out", MISC_FUNC_REG, 2, 0, NULL, 0,\r
+ aux_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+SND_SOC_DAPM_PGA_E("AUXR Out", MISC_FUNC_REG, 3, 0, NULL, 0,\r
+ aux_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),\r
+\r
+SND_SOC_DAPM_PGA("Left Line In", RT5621_PWR_MANAG_ADD3, 7, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Right Line In", RT5621_PWR_MANAG_ADD3, 6, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Left AUX In", RT5621_PWR_MANAG_ADD3, 5, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Right AUX In", RT5621_PWR_MANAG_ADD3, 4, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_PGA("Mic 1 PGA", RT5621_PWR_MANAG_ADD3, 3, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic 2 PGA", RT5621_PWR_MANAG_ADD3, 2, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic 1 Pre Amp", RT5621_PWR_MANAG_ADD3, 1, 0, NULL, 0),\r
+SND_SOC_DAPM_PGA("Mic 2 Pre Amp", RT5621_PWR_MANAG_ADD3, 0, 0, NULL, 0),\r
+\r
+SND_SOC_DAPM_MICBIAS("Mic Bias1", RT5621_PWR_MANAG_ADD1, 11, 0),\r
+\r
+SND_SOC_DAPM_OUTPUT("AUXL"),\r
+SND_SOC_DAPM_OUTPUT("AUXR"),\r
+SND_SOC_DAPM_OUTPUT("HPL"),\r
+SND_SOC_DAPM_OUTPUT("HPR"),\r
+SND_SOC_DAPM_OUTPUT("SPK"),\r
+\r
+SND_SOC_DAPM_INPUT("LINEL"),\r
+SND_SOC_DAPM_INPUT("LINER"),\r
+SND_SOC_DAPM_INPUT("AUXINL"),\r
+SND_SOC_DAPM_INPUT("AUXINR"),\r
+SND_SOC_DAPM_INPUT("MIC1"),\r
+SND_SOC_DAPM_INPUT("MIC2"),\r
+SND_SOC_DAPM_VMID("VMID"),\r
+};\r
+\r
+static const struct snd_soc_dapm_route audio_map[] = {\r
+ /* left HP mixer */\r
+ {"Left HP Mixer" , "LineIn Playback Switch" , "Left Line In"},\r
+ {"Left HP Mixer" , "AUXIN Playback Switch" , "Left AUX In"},\r
+ {"Left HP Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"},\r
+ {"Left HP Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"},\r
+ {"Left HP Mixer" , "PCM Playback Switch" , "Left DAC"},\r
+ {"Left HP Mixer" , "RecordL Playback Switch" , "Left Record Mixer"},\r
+ \r
+ /* right HP mixer */\r
+ {"Right HP Mixer" , "LineIn Playback Switch" , "Right Line In"},\r
+ {"Right HP Mixer" , "AUXIN Playback Switch" , "Right AUX In"},\r
+ {"Right HP Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"},\r
+ {"Right HP Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"},\r
+ {"Right HP Mixer" , "PCM Playback Switch" , "Right DAC"},\r
+ {"Right HP Mixer" , "RecordR Playback Switch" , "Right Record Mixer"},\r
+ \r
+ /* virtual mixer - mixes left & right channels for spk and mono */\r
+ {"IIS Mixer" , NULL , "Left DAC"},\r
+ {"IIS Mixer" , NULL , "Right DAC"},\r
+ {"Line Mixer" , NULL , "Right Line In"},\r
+ {"Line Mixer" , NULL , "Left Line In"},\r
+ {"AUXIN Mixer" , NULL , "Left AUX In"},\r
+ {"AUXIN Mixer" , NULL , "Right AUX In"},\r
+ {"HP Mixer" , NULL , "Left HP Mixer"},\r
+ {"HP Mixer" , NULL , "Right HP Mixer"},\r
+ \r
+ /* speaker mixer */\r
+ {"Speaker Mixer" , "LineIn Playback Switch" , "Line Mixer"},\r
+ {"Speaker Mixer" , "AUXIN Playback Switch" , "AUXIN Mixer"},\r
+ {"Speaker Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"},\r
+ {"Speaker Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"},\r
+ {"Speaker Mixer" , "PCM Playback Switch" , "IIS Mixer"},\r
+\r
+\r
+ /* mono mixer */\r
+ {"Mono Mixer" , "LineIn Playback Switch" , "Line Mixer"},\r
+ {"Mono Mixer" , "Mic1 Playback Switch" , "Mic 1 PGA"},\r
+ {"Mono Mixer" , "Mic2 Playback Switch" , "Mic 2 PGA"},\r
+ {"Mono Mixer" , "PCM Playback Switch" , "IIS Mixer"},\r
+ {"Mono Mixer" , "AUXIN Playback Switch" , "AUXIN Mixer"},\r
+ {"Mono Mixer" , "RecordL Playback Switch" , "Left Record Mixer"},\r
+ {"Mono Mixer" , "RecordR Playback Switch" , "Right Record Mixer"},\r
+ \r
+ /*Left record mixer */\r
+ {"Left Record Mixer" , "Mic1 Capture Switch" , "Mic 1 Pre Amp"},\r
+ {"Left Record Mixer" , "Mic2 Capture Switch" , "Mic 2 Pre Amp"},\r
+ {"Left Record Mixer" , "LineInL Capture Switch" , "LINEL"},\r
+ {"Left Record Mixer" , "AUXIN Capture Switch" , "AUXINL"},\r
+ {"Left Record Mixer" , "HPMixerL Capture Switch" , "Left HP Mixer"},\r
+ {"Left Record Mixer" , "SPKMixer Capture Switch" , "Speaker Mixer"},\r
+ {"Left Record Mixer" , "MonoMixer Capture Switch" , "Mono Mixer"},\r
+ \r
+ /*Right record mixer */\r
+ {"Right Record Mixer" , "Mic1 Capture Switch" , "Mic 1 Pre Amp"},\r
+ {"Right Record Mixer" , "Mic2 Capture Switch" , "Mic 2 Pre Amp"},\r
+ {"Right Record Mixer" , "LineInR Capture Switch" , "LINER"},\r
+ {"Right Record Mixer" , "AUXIN Capture Switch" , "AUXINR"},\r
+ {"Right Record Mixer" , "HPMixerR Capture Switch" , "Right HP Mixer"},\r
+ {"Right Record Mixer" , "SPKMixer Capture Switch" , "Speaker Mixer"},\r
+ {"Right Record Mixer" , "MonoMixer Capture Switch" , "Mono Mixer"}, \r
+\r
+ /* headphone left mux */\r
+ {"Left Headphone Out Mux" , "HPL mixer" , "Left HP Mixer"},\r
+\r
+ /* headphone right mux */\r
+ {"Right Headphone Out Mux", "HPR mixer", "Right HP Mixer"},\r
+\r
+ /* speaker mux */\r
+ {"Speaker Out Mux", "HP mixer", "HP Mixer"},\r
+ {"Speaker Out Mux", "SPK mixer", "Speaker Mixer"},\r
+ {"Speaker Out Mux", "Mono Mixer", "Mono Mixer"},\r
+\r
+ /* mono mux */\r
+ {"Mono Out Mux", "HP mixer", "HP Mixer"},\r
+ {"Mono Out Mux", "SPK mixer", "Speaker Mixer"},\r
+ {"Mono Out Mux", "Mono Mixer", "Mono Mixer"},\r
+ \r
+ /* output pga */\r
+ {"HPL", NULL, "Left Headphone"},\r
+ {"Left Headphone", NULL, "Left Headphone Out Mux"},\r
+\r
+ {"HPR", NULL, "Right Headphone"},\r
+ {"Right Headphone", NULL, "Right Headphone Out Mux"},\r
+\r
+ {"SPK", NULL, "Speaker PGA"},\r
+ {"Speaker PGA", NULL, "Speaker Out Mux"},\r
+\r
+ {"AUXL", NULL, "AUXL Out"},\r
+ {"AUXL Out", NULL, "Mono Out Mux"},\r
+\r
+ {"AUXR", NULL, "AUXR Out"},\r
+ {"AUXR Out", NULL, "Mono Out Mux"},\r
+\r
+ /* input pga */\r
+ {"Left Line In", NULL, "LINEL"},\r
+ {"Right Line In", NULL, "LINER"},\r
+ \r
+ {"Left AUX In", NULL, "AUXINL"},\r
+ {"Right AUX In", NULL, "AUXINR"},\r
+ \r
+ {"Mic 1 Pre Amp", NULL, "MIC1"},\r
+ {"Mic 2 Pre Amp", NULL, "MIC2"}, \r
+ {"Mic 1 PGA", NULL, "Mic 1 Pre Amp"},\r
+ {"Mic 2 PGA", NULL, "Mic 2 Pre Amp"},\r
+\r
+ /* left ADC */\r
+ {"Left ADC", NULL, "Left Record Mixer"},\r
+\r
+ /* right ADC */\r
+ {"Right ADC", NULL, "Right Record Mixer"},\r
+ \r
+};\r
+\r
+static int rt5621_add_widgets(struct snd_soc_codec *codec)\r
+{\r
+ snd_soc_dapm_new_controls(codec, rt5621_dapm_widgets,\r
+ ARRAY_SIZE(rt5621_dapm_widgets));\r
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));\r
+ snd_soc_dapm_new_widgets(codec);\r
+\r
+ return 0;\r
+}\r
+\r
+#else\r
+\r
+static int rt5621_pcm_hw_prepare(struct snd_pcm_substream *substream,\r
+ struct snd_soc_dai *codec_dai)\r
+{\r
+\r
+ struct snd_soc_codec *codec = codec_dai->codec;\r
+ int stream = substream->stream;\r
+\r
+ switch (stream)\r
+ {\r
+ case SNDRV_PCM_STREAM_PLAYBACK:\r
+\r
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D1_PLAYBACK); //power on dac to hp and speaker out\r
+ \r
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_SPK,0); //unmute speaker out\r
+ \r
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_HP,0); //unmute hp out\r
+\r
+ break;\r
+ case SNDRV_PCM_STREAM_CAPTURE:\r
+\r
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D1_RECORD); //power on input to adc\r
+\r
+ Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,1); //enable record source from mic1\r
+\r
+ break; \r
+ }\r
+ \r
+ return 0;\r
+}\r
+\r
+#endif\r
+/* PLL divisors */\r
+struct _pll_div {\r
+ u32 pll_in;\r
+ u32 pll_out;\r
+ u16 regvalue;\r
+};\r
+\r
+static const struct _pll_div codec_pll_div[] = {\r
+ \r
+ { 2048000, 8192000, 0x0ea0}, \r
+ { 3686400, 8192000, 0x4e27}, \r
+ { 12000000, 8192000, 0x456b}, \r
+ { 13000000, 8192000, 0x495f},\r
+ { 13100000, 8192000, 0x0320}, \r
+ { 2048000, 11289600, 0xf637},\r
+ { 3686400, 11289600, 0x2f22}, \r
+ { 12000000, 11289600, 0x3e2f}, \r
+ { 13000000, 11289600, 0x4d5b},\r
+ { 13100000, 11289600, 0x363b}, \r
+ { 2048000, 16384000, 0x1ea0},\r
+ { 3686400, 16384000, 0x9e27}, \r
+ { 12000000, 16384000, 0x452b}, \r
+ { 13000000, 16384000, 0x542f},\r
+ { 13100000, 16384000, 0x03a0}, \r
+ { 2048000, 16934400, 0xe625},\r
+ { 3686400, 16934400, 0x9126}, \r
+ { 12000000, 16934400, 0x4d2c}, \r
+ { 13000000, 16934400, 0x742f},\r
+ { 13100000, 16934400, 0x3c27}, \r
+ { 2048000, 22579200, 0x2aa0},\r
+ { 3686400, 22579200, 0x2f20}, \r
+ { 12000000, 22579200, 0x7e2f}, \r
+ { 13000000, 22579200, 0x742f},\r
+ { 13100000, 22579200, 0x3c27}, \r
+ { 2048000, 24576000, 0x2ea0},\r
+ { 3686400, 24576000, 0xee27}, \r
+ { 12000000, 24576000, 0x2915}, \r
+ { 13000000, 24576000, 0x772e},\r
+ { 13100000, 24576000, 0x0d20}, \r
+};\r
+\r
+static const struct _pll_div codec_bclk_pll_div[] = {\r
+\r
+ { 1536000, 24576000, 0x3ea0}, \r
+ { 3072000, 24576000, 0x1ea0},\r
+ { 512000, 24576000, 0x8e90},\r
+ { 256000, 24576000, 0xbe80},\r
+ { 2822400, 11289600, 0x1ee0}, //flove040711\r
+ { 3072000, 12288000, 0x1ee0}, //flove040711 \r
+};\r
+\r
+\r
+static int rt5621_set_dai_pll(struct snd_soc_dai *codec_dai,\r
+ int pll_id, unsigned int freq_in, unsigned int freq_out)\r
+{\r
+ int i;\r
+ int ret = -EINVAL;\r
+ struct snd_soc_codec *codec = codec_dai->codec;\r
+\r
+ if (pll_id < RT5621_PLL_FR_MCLK || pll_id > RT5621_PLL_FR_BCLK)\r
+ return -EINVAL;\r
+\r
+ //rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2, 0x0000,0x1000); //disable PLL power \r
+ \r
+ if (!freq_in || !freq_out) {\r
+\r
+ return 0;\r
+ } \r
+\r
+ if (RT5621_PLL_FR_MCLK == pll_id) {\r
+ for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) {\r
+ \r
+ if (codec_pll_div[i].pll_in == freq_in && codec_pll_div[i].pll_out == freq_out)\r
+ {\r
+ rt5621_write_mask(codec, RT5621_GLOBAL_CLK_CTRL_REG, 0x0000, 0x4000); \r
+ rt5621_write(codec,RT5621_PLL_CTRL,codec_pll_div[i].regvalue);//set PLL parameter \r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power \r
+ ret = 0;\r
+ }\r
+ }\r
+ }\r
+ else if (RT5621_PLL_FR_BCLK == pll_id)\r
+ {\r
+ for (i = 0; i < ARRAY_SIZE(codec_bclk_pll_div); i++)\r
+ {\r
+ if ((freq_in == codec_bclk_pll_div[i].pll_in) && (freq_out == codec_bclk_pll_div[i].pll_out))\r
+ {\r
+ rt5621_write_mask(codec, RT5621_GLOBAL_CLK_CTRL_REG, 0x4000, 0x4000);\r
+ rt5621_write(codec,RT5621_PLL_CTRL,codec_bclk_pll_div[i].regvalue);//set PLL parameter \r
+ rt5621_write_mask(codec,RT5621_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power \r
+ ret = 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ rt5621_write_mask(codec,RT5621_GLOBAL_CLK_CTRL_REG,0x8000,0x8000);//Codec sys-clock from PLL \r
+ return ret;\r
+}\r
+\r
+\r
+struct _coeff_div {\r
+ u32 mclk;\r
+ u32 rate;\r
+ u16 fs;\r
+ u16 regvalue;\r
+};\r
+\r
+/* codec hifi mclk (after PLL) clock divider coefficients */\r
+static const struct _coeff_div coeff_div[] = {\r
+ /* 8k */\r
+ { 8192000, 8000, 256*4, 0x2a2d},\r
+ {12288000, 8000, 384*4, 0x2c2f},\r
+\r
+ /* 11.025k */\r
+ {11289600, 11025, 256*4, 0x2a2d},\r
+ {16934400, 11025, 384*4, 0x2c2f},\r
+\r
+ /* 16k */\r
+ {12288000, 16000, 384*2, 0x1c2f},\r
+ {16384000, 16000, 256*4, 0x2a2d},\r
+ {24576000, 16000, 384*4, 0x2c2f},\r
+\r
+ /* 22.05k */ \r
+ {11289600, 22050, 256*2, 0x1a2d},\r
+ {16934400, 22050, 384*2, 0x1c2f},\r
+\r
+ /* 32k */\r
+ {12288000, 32000, 384 , 0x0c2f},\r
+ {16384000, 32000, 256*2, 0x1a2d},\r
+ {24576000, 32000, 384*2, 0x1c2f},\r
+\r
+ /* 44.1k */\r
+ {11289600, 44100, 256*1, 0x0a2d},\r
+ {22579200, 44100, 256*2, 0x1a2d},\r
+ {45158400, 44100, 256*4, 0x2a2d}, \r
+\r
+ /* 48k */\r
+ {12288000, 48000, 256*1, 0x0a2d},\r
+ {24576000, 48000, 256*2, 0x1a2d},\r
+ {49152000, 48000, 256*4, 0x2a2d},\r
+\r
+};\r
+\r
+\r
+\r
+static int get_coeff(int mclk, int rate)\r
+{\r
+ int i;\r
+ \r
+ printk("get_coeff mclk=%d,rate=%d\n",mclk,rate);\r
+\r
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {\r
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)\r
+ return i;\r
+ }\r
+ return -EINVAL;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+ * Clock after PLL and dividers\r
+ */\r
+ /*in this driver, you have to set sysclk to be 24576000,\r
+ * but you don't need to give a clk to be 24576000, our \r
+ * internal pll will generate this clock! so it won't make\r
+ * you any difficult.\r
+ */\r
+static int rt5621_set_dai_sysclk(struct snd_soc_dai *codec_dai,\r
+ int clk_id, unsigned int freq, int dir)\r
+{\r
+ struct snd_soc_codec *codec = codec_dai->codec;\r
+ struct rt5621_priv *rt5621 = codec->private_data;\r
+\r
+ switch (freq) {\r
+ case 24576000:\r
+ rt5621->sysclk = freq;\r
+ return 0;\r
+ }\r
+ return 0;\r
+}\r
+\r
+\r
+static int rt5621_set_dai_fmt(struct snd_soc_dai *codec_dai,\r
+ unsigned int fmt)\r
+{\r
+ struct snd_soc_codec *codec = codec_dai->codec;\r
+ u16 iface = 0;\r
+\r
+ /* set master/slave audio interface */\r
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {\r
+ case SND_SOC_DAIFMT_CBM_CFM:\r
+ iface = 0x0000;\r
+ break;\r
+ case SND_SOC_DAIFMT_CBS_CFS:\r
+ iface = 0x8000;\r
+ break;\r
+ default:\r
+ return -EINVAL;\r
+ }\r
+\r
+ /* interface format */\r
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {\r
+ case SND_SOC_DAIFMT_I2S:\r
+ iface |= 0x0000;\r
+ break;\r
+ case SND_SOC_DAIFMT_RIGHT_J:\r
+ iface |= 0x0001;\r
+ break;\r
+ case SND_SOC_DAIFMT_LEFT_J:\r
+ iface |= 0x0002;\r
+ break;\r
+ case SND_SOC_DAIFMT_DSP_A:\r
+ iface |= 0x0003;\r
+ break;\r
+ case SND_SOC_DAIFMT_DSP_B:\r
+ iface |= 0x4003;\r
+ break;\r
+ default:\r
+ return -EINVAL;\r
+ }\r
+\r
+ /* clock inversion */\r
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {\r
+ case SND_SOC_DAIFMT_NB_NF:\r
+ iface |= 0x0000;\r
+ break;\r
+ case SND_SOC_DAIFMT_IB_NF:\r
+ iface |= 0x0100;\r
+ break;\r
+ default:\r
+ return -EINVAL;\r
+ }\r
+\r
+ rt5621_write(codec,RT5621_AUDIO_INTERFACE,iface);\r
+ return 0;\r
+}\r
+\r
+\r
+static int rt5621_pcm_hw_params(struct snd_pcm_substream *substream,\r
+ struct snd_pcm_hw_params *params,\r
+ struct snd_soc_dai *codec_dai)\r
+{\r
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
+ struct snd_soc_device *socdev = rtd->socdev;\r
+ struct snd_soc_codec *codec = socdev ->card->codec;\r
+ struct rt5621_priv *rt5621 = codec->private_data;\r
+ u16 iface=rt5621_read(codec,RT5621_AUDIO_INTERFACE)&0xfff3;\r
+ int coeff = get_coeff(rt5621->sysclk, params_rate(params));\r
+\r
+ printk("rt5621_pcm_hw_params\n");\r
+ if (coeff < 0)\r
+ coeff = get_coeff(24576000, params_rate(params)); /*if not set sysclk, default to be 24.576MHz*/\r
+\r
+ /* bit size */\r
+ switch (params_format(params)) {\r
+ case SNDRV_PCM_FORMAT_S16_LE:\r
+ iface |= 0x0000;\r
+ break;\r
+ case SNDRV_PCM_FORMAT_S20_3LE:\r
+ iface |= 0x0004;\r
+ break;\r
+ case SNDRV_PCM_FORMAT_S24_LE:\r
+ iface |= 0x0008;\r
+ break;\r
+ case SNDRV_PCM_FORMAT_S32_LE:\r
+ iface |= 0x000c;\r
+ break;\r
+ }\r
+\r
+ /* set iface & srate */\r
+ rt5621_write(codec, RT5621_AUDIO_INTERFACE, iface);\r
+\r
+ if (coeff >= 0)\r
+ rt5621_write(codec, RT5621_STEREO_AD_DA_CLK_CTRL, coeff_div[coeff].regvalue);\r
+// else\r
+// {\r
+// printk(KERN_ERR "cant find matched sysclk and rate config\n");\r
+// return -EINVAL;\r
+ \r
+// }\r
+ return 0;\r
+}\r
+\r
+#if !USE_DAPM_CONTROL\r
+static int rt5621_set_bias_level(struct snd_soc_codec *codec, \r
+ enum snd_soc_bias_level level)\r
+{\r
+ switch (level) {\r
+ case SND_SOC_BIAS_ON:\r
+ break;\r
+ case SND_SOC_BIAS_PREPARE:\r
+ break;\r
+ case SND_SOC_BIAS_STANDBY:\r
+ break;\r
+ case SND_SOC_BIAS_OFF:\r
+\r
+ rt5621_write_mask(codec, 0x02, 0x8080, 0x8080);\r
+ rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+ rt5621_write(codec, 0x3e, 0x0000);\r
+ rt5621_write(codec, 0x3c, 0x0000);\r
+ rt5621_write(codec, 0x3a, 0x0000);\r
+ break; \r
+ }\r
+ codec->bias_level = level;\r
+ return 0;\r
+}\r
+#else\r
+static int rt5621_set_bias_level(struct snd_soc_codec *codec, \r
+ enum snd_soc_bias_level level)\r
+{\r
+ switch (level) {\r
+ case SND_SOC_BIAS_ON:\r
+ break;\r
+ case SND_SOC_BIAS_PREPARE:\r
+ break;\r
+ case SND_SOC_BIAS_STANDBY:\r
+\r
+ break;\r
+ case SND_SOC_BIAS_OFF:\r
+\r
+ rt5621_write_mask(codec, 0x02, 0x8080, 0x8080);\r
+ rt5621_write_mask(codec, 0x04, 0x8080, 0x8080);\r
+ rt5621_write(codec, 0x3e, 0x0000);\r
+ rt5621_write(codec, 0x3c, 0x0000);\r
+ rt5621_write(codec, 0x3a, 0x0000);\r
+ break; \r
+ }\r
+ codec->bias_level = level;\r
+ return 0;\r
+}\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+#if !USE_DAPM_CONTROL\r
+\r
+static void rt5621_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai)\r
+{\r
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
+ struct snd_soc_device *socdev = rtd->socdev;\r
+ struct snd_soc_codec *codec = socdev->card->codec;\r
+ int stream = substream->stream;\r
+ \r
+ switch (stream)\r
+ {\r
+ case SNDRV_PCM_STREAM_PLAYBACK:\r
+\r
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_SPK,1); //mute speaker out\r
+ \r
+ rt5621_AudioOutEnable(codec,RT_WAVOUT_HP,1); //mute hp out\r
+\r
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D2_PLAYBACK); //power off dac to hp and speaker out\r
+ \r
+\r
+\r
+ break;\r
+ case SNDRV_PCM_STREAM_CAPTURE:\r
+\r
+ Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,0); //disable record source from mic1\r
+\r
+ rt5621_ChangeCodecPowerStatus(codec,POWER_STATE_D2_RECORD);\r
+ \r
+\r
+ break; \r
+ } \r
+}\r
+\r
+#endif\r
+\r
+\r
+#define RT5621_HIFI_RATES SNDRV_PCM_RATE_8000_48000\r
+\r
+#define RT5621_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\\r
+ SNDRV_PCM_FMTBIT_S24_LE)\r
+\r
+struct snd_soc_dai_ops rt5621_hifi_ops = {\r
+ .hw_params = rt5621_pcm_hw_params, \r
+ .set_fmt = rt5621_set_dai_fmt,\r
+ .set_sysclk = rt5621_set_dai_sysclk,\r
+ .set_pll = rt5621_set_dai_pll,\r
+#if !USE_DAPM_CONTROL\r
+ .prepare = rt5621_pcm_hw_prepare,\r
+ .shutdown = rt5621_shutdown,\r
+#endif\r
+ \r
+};\r
+\r
+struct snd_soc_dai rt5621_dai = { \r
+ \r
+ .name = "RT5621",\r
+ .playback = {\r
+ .stream_name = "HiFi Playback",\r
+ .channels_min = 1,\r
+ .channels_max = 2,\r
+ .rates = RT5621_HIFI_RATES,\r
+ .formats = RT5621_FORMATS,},\r
+ .capture = {\r
+ .stream_name = "HiFi Capture",\r
+ .channels_min = 1,\r
+ .channels_max = 2,\r
+ .rates = RT5621_HIFI_RATES,\r
+ .formats = RT5621_FORMATS,},\r
+\r
+ .ops = &rt5621_hifi_ops,\r
+};\r
+\r
+\r
+EXPORT_SYMBOL_GPL(rt5621_dai);\r
+\r
+static ssize_t rt5621_index_reg_show(struct device *dev, \r
+ struct device_attribute *attr, char *buf)\r
+{\r
+ struct snd_soc_device *socdev = dev_get_drvdata(dev);\r
+ struct snd_soc_codec *codec = socdev ->card->codec;\r
+ int count = 0;\r
+ int value;\r
+ int i; \r
+ \r
+ count += sprintf(buf, "%s index register\n", codec->name);\r
+\r
+ for (i = 0; i < 0x60; i++) {\r
+ count += sprintf(buf + count, "index-%2x ", i);\r
+ if (count >= PAGE_SIZE - 1)\r
+ break;\r
+ value = rt5621_read_index(codec, i);\r
+ count += snprintf(buf + count, PAGE_SIZE - count, "0x%4x", value);\r
+\r
+ if (count >= PAGE_SIZE - 1)\r
+ break;\r
+\r
+ count += snprintf(buf + count, PAGE_SIZE - count, "\n");\r
+ if (count >= PAGE_SIZE - 1)\r
+ break;\r
+ }\r
+\r
+ if (count >= PAGE_SIZE)\r
+ count = PAGE_SIZE - 1;\r
+ \r
+ return count;\r
+ \r
+}\r
+\r
+static DEVICE_ATTR(index_reg, 0444, rt5621_index_reg_show, NULL);\r
+\r
+#if defined(CONFIG_SND_HWDEP)\r
+#if REALTEK_HWDEP\r
+\r
+#define RT_CE_CODEC_HWDEP_NAME "rt56xx hwdep "\r
+\r
+static int rt56xx_hwdep_open(struct snd_hwdep *hw, struct file *file)\r
+{\r
+ printk("enter %s\n", __func__);\r
+ return 0;\r
+}\r
+\r
+static int rt56xx_hwdep_release(struct snd_hwdep *hw, struct file *file)\r
+{\r
+ printk("enter %s\n", __func__);\r
+ return 0;\r
+}\r
+\r
+\r
+static int rt56xx_hwdep_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+ struct rt56xx_cmd rt56xx;\r
+ struct rt56xx_cmd __user *_rt56xx = arg;\r
+ struct rt56xx_reg_state *buf;\r
+ struct rt56xx_reg_state *p;\r
+ struct snd_soc_codec *codec = hw->private_data;\r
+\r
+ if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))\r
+ return -EFAULT;\r
+ buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL);\r
+ if (buf == NULL)\r
+ return -ENOMEM;\r
+ if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number)) {\r
+ goto err;\r
+ }\r
+ switch (cmd) {\r
+ case RT_READ_CODEC_REG_IOCTL:\r
+ for (p = buf; p < buf + rt56xx.number; p++)\r
+ {\r
+ p->reg_value = codec->read(codec, p->reg_index);\r
+ }\r
+ if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))\r
+ goto err;\r
+ \r
+ break;\r
+ case RT_WRITE_CODEC_REG_IOCTL:\r
+ for (p = buf; p < buf + rt56xx.number; p++)\r
+ codec->write(codec, p->reg_index, p->reg_value);\r
+ break;\r
+ }\r
+\r
+ kfree(buf);\r
+ return 0;\r
+\r
+err:\r
+ kfree(buf);\r
+ return -EFAULT;\r
+ \r
+}\r
+\r
+static int rt56xx_codec_dump_reg(struct snd_hwdep *hw, struct file *file, unsigned long arg)\r
+{\r
+ struct rt56xx_cmd rt56xx;\r
+ struct rt56xx_cmd __user *_rt56xx = arg;\r
+ struct rt56xx_reg_state *buf;\r
+ struct snd_soc_codec *codec = hw->private_data;\r
+ int number = codec->reg_cache_size;\r
+ int i;\r
+\r
+ printk(KERN_DEBUG "enter %s, number = %d\n", __func__, number); \r
+ if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))\r
+ return -EFAULT;\r
+ \r
+ buf = kmalloc(sizeof(*buf) * number, GFP_KERNEL);\r
+ if (buf == NULL)\r
+ return -ENOMEM;\r
+\r
+ for (i = 0; i < number; i++)\r
+ {\r
+ buf[i].reg_index = i << 1;\r
+ buf[i].reg_value = codec->read(codec, buf[i].reg_index);\r
+ }\r
+ if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * i))\r
+ goto err;\r
+ rt56xx.number = number;\r
+ if (copy_to_user(_rt56xx, &rt56xx, sizeof(rt56xx)))\r
+ goto err;\r
+ kfree(buf);\r
+ return 0;\r
+err:\r
+ kfree(buf);\r
+ return -EFAULT;\r
+ \r
+}\r
+\r
+static int rt56xx_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)\r
+{\r
+ if (cmd == RT_READ_ALL_CODEC_REG_IOCTL)\r
+ {\r
+ return rt56xx_codec_dump_reg(hw, file, arg);\r
+ }\r
+ else\r
+ {\r
+ return rt56xx_hwdep_ioctl_common(hw, file, cmd, arg);\r
+ }\r
+}\r
+\r
+static int realtek_ce_init_hwdep(struct snd_soc_codec *codec)\r
+{\r
+ struct snd_hwdep *hw;\r
+ struct snd_card *card = codec->card;\r
+ int err;\r
+\r
+ if ((err = snd_hwdep_new(card, RT_CE_CODEC_HWDEP_NAME, 0, &hw)) < 0)\r
+ return err;\r
+ \r
+ strcpy(hw->name, RT_CE_CODEC_HWDEP_NAME);\r
+ hw->private_data = codec;\r
+ hw->ops.open = rt56xx_hwdep_open;\r
+ hw->ops.release = rt56xx_hwdep_release;\r
+ hw->ops.ioctl = rt56xx_hwdep_ioctl;\r
+ return 0;\r
+}\r
+\r
+#endif\r
+#endif\r
+\r
+static void rt5621_work(struct work_struct *work)\r
+{\r
+ struct snd_soc_codec *codec =\r
+ container_of(work, struct snd_soc_codec, delayed_work.work);\r
+ \r
+ rt5621_set_bias_level(codec, codec->bias_level);\r
+}\r
+\r
+\r
+static int rt5621_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+ struct snd_soc_codec *codec = socdev ->card->codec;\r
+\r
+ /* we only need to suspend if we are a valid card */\r
+ if(!codec->card)\r
+ return 0;\r
+ \r
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_STANDBY);\r
+ return 0;\r
+}\r
+\r
+static int rt5621_resume(struct platform_device *pdev)\r
+{\r
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+ struct snd_soc_codec *codec = socdev ->card->codec;\r
+ int i;\r
+ u8 data[3];\r
+ u16 *cache = codec->reg_cache;\r
+\r
+ /* we only need to resume if we are a valid card */\r
+ if(!codec->card)\r
+ return 0;\r
+\r
+ /* Sync reg_cache with the hardware */ \r
+\r
+ for (i = 0; i < ARRAY_SIZE(rt5621_reg); i++) {\r
+ if (i == RT5621_RESET)\r
+ continue;\r
+ data[0] =i << 1; \r
+ data[1] = (0xFF00 & cache[i]) >> 8;\r
+ data[2] = 0x00FF & cache[i]; \r
+ codec->hw_write(codec->control_data, data, 3);\r
+ } \r
+\r
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_STANDBY);\r
+ \r
+ /* charge rt5621 caps */\r
+ \r
+ if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {\r
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_PREPARE);\r
+ codec->bias_level = SND_SOC_BIAS_ON;\r
+ schedule_delayed_work(&codec->delayed_work,\r
+ msecs_to_jiffies(caps_charge));\r
+ }\r
+ return 0;\r
+}\r
+\r
+\r
+/*\r
+ * initialise the RT5621 driver\r
+ * register the mixer and dsp interfaces with the kernel\r
+ */\r
+static int rt5621_init(struct snd_soc_device *socdev)\r
+{\r
+ struct snd_soc_codec *codec = socdev ->card->codec;\r
+ int ret = 0;\r
+\r
+ printk(KERN_INFO "alsa version is 1.0.21, codec driver version is 0.04\n");\r
+ codec->name = "RT5621";\r
+ codec->owner = THIS_MODULE;\r
+ codec->read = rt5621_read;\r
+ codec->write = rt5621_write;\r
+ codec->set_bias_level = rt5621_set_bias_level;\r
+ codec->dai = &rt5621_dai;\r
+ codec->num_dai = 1;\r
+ codec->reg_cache_step = 2;\r
+ codec->reg_cache_size = ARRAY_SIZE(rt5621_reg) * 2;\r
+ codec->reg_cache = kmemdup(rt5621_reg, sizeof(rt5621_reg), GFP_KERNEL);\r
+\r
+ if (codec->reg_cache == NULL)\r
+ return -ENOMEM;\r
+ \r
+ /* register pcms */\r
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);\r
+ if (ret < 0) {\r
+ printk(KERN_ERR "rt5621: failed to create pcms\n");\r
+ goto pcm_err;\r
+ }\r
+\r
+\r
+ rt5621_reset(codec);\r
+ rt5621_write(codec, RT5621_PWR_MANAG_ADD3, 0x8000);//enable Main bias\r
+ rt5621_write(codec, RT5621_PWR_MANAG_ADD2, 0x2000);//enable Vref\r
+\r
+ hp_depop_mode2(codec);\r
+\r
+ rt5621_init_reg(codec);\r
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_PREPARE);\r
+ codec->bias_level = SND_SOC_BIAS_STANDBY;\r
+ schedule_delayed_work(&codec->delayed_work,\r
+ msecs_to_jiffies(caps_charge));\r
+ \r
+ rt5621_add_controls(codec);\r
+\r
+ #if USE_DAPM_CONTROL\r
+\r
+ rt5621_add_widgets(codec); \r
+\r
+ #endif\r
+\r
+ #if defined(CONFIG_SND_HWDEP)\r
+ #if REALTEK_HWDEP\r
+\r
+ realtek_ce_init_hwdep(codec);\r
+\r
+ #endif\r
+ #endif\r
+\r
+ ret = snd_soc_init_card(socdev);\r
+\r
+ if (ret < 0) {\r
+ printk(KERN_ERR "rt5621: failed to register card\n");\r
+ goto card_err;\r
+ }\r
+ return ret;\r
+\r
+card_err:\r
+ snd_soc_free_pcms(socdev);\r
+ snd_soc_dapm_free(socdev);\r
+pcm_err:\r
+ kfree(codec->reg_cache);\r
+ return ret;\r
+}\r
+\r
+static int rt5621_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)\r
+{\r
+ struct snd_soc_device *socdev = rt5621_socdev;\r
+ struct snd_soc_codec *codec = socdev ->card->codec;\r
+ int ret;\r
+\r
+ i2c_set_clientdata(i2c, codec);\r
+ codec->control_data = i2c;\r
+\r
+ ret = rt5621_init(socdev);\r
+ if (ret < 0)\r
+ pr_err("failed to initialise rt5621\n");\r
+\r
+ return ret;\r
+}\r
+\r
+\r
+static int rt5621_i2c_remove(struct i2c_client *client)\r
+{\r
+ struct snd_soc_codec *codec = i2c_get_clientdata(client);\r
+ kfree(codec->reg_cache);\r
+ return 0;\r
+}\r
+\r
+static const struct i2c_device_id rt5621_i2c_id[] = {\r
+ {"ALC5621", 0},\r
+ {}\r
+};\r
+MODULE_DEVICE_TABLE(i2c, rt5621_i2c_id);\r
+static struct i2c_driver rt5621_i2c_driver = {\r
+ .driver = {\r
+ .name = "RT5621 I2C Codec",\r
+ .owner = THIS_MODULE,\r
+ },\r
+ .probe = rt5621_i2c_probe,\r
+ .remove = rt5621_i2c_remove,\r
+ .id_table = rt5621_i2c_id,\r
+};\r
+\r
+static int rt5621_add_i2c_device(struct platform_device *pdev,\r
+ const struct rt5621_setup_data *setup)\r
+{\r
+#if 0\r
+ struct i2c_board_info info;\r
+ struct i2c_adapter *adapter;\r
+ struct i2c_client *client;\r
+#endif\r
+ int ret;\r
+ ret = i2c_add_driver(&rt5621_i2c_driver);\r
+ if (ret != 0) {\r
+ dev_err(&pdev->dev, "can't add i2c driver\n");\r
+ return ret;\r
+ }\r
+#if 0\r
+ memset(&info, 0, sizeof(struct i2c_board_info));\r
+ info.addr = setup->i2c_address;\r
+ strlcpy(info.type, "rt5621", I2C_NAME_SIZE);\r
+\r
+ adapter = i2c_get_adapter(setup->i2c_bus);\r
+ if (!adapter) {\r
+ dev_err(&pdev->dev, "can't get i2c adapter %d\n",\r
+ setup->i2c_bus);\r
+ goto err_driver;\r
+ }\r
+\r
+ client = i2c_new_device(adapter, &info);\r
+ i2c_put_adapter(adapter);\r
+ if (!client) {\r
+ dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",\r
+ (unsigned int)info.addr);\r
+ goto err_driver;\r
+ }\r
+#endif\r
+ return 0;\r
+\r
+#if 0\r
+err_driver:\r
+ i2c_del_driver(&rt5621_i2c_driver);\r
+ return -ENODEV;\r
+#endif\r
+}\r
+\r
+\r
+static int rt5621_probe(struct platform_device *pdev)\r
+{\r
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+ struct rt5621_setup_data *setup = socdev->codec_data;\r
+ struct snd_soc_codec *codec;\r
+ struct rt5621_priv *rt5621;\r
+ int ret;\r
+\r
+ pr_info("RT5621 Audio Codec %s\n", RT5621_VERSION);\r
+\r
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);\r
+ if (codec == NULL)\r
+ return -ENOMEM;\r
+\r
+ rt5621 = kzalloc(sizeof(struct rt5621_priv), GFP_KERNEL);\r
+ if (rt5621 == NULL) {\r
+ kfree(codec);\r
+ return -ENOMEM;\r
+ }\r
+ codec->private_data = rt5621;\r
+ socdev ->card->codec = codec;\r
+ mutex_init(&codec->mutex);\r
+ INIT_LIST_HEAD(&codec->dapm_widgets);\r
+ INIT_LIST_HEAD(&codec->dapm_paths);\r
+ rt5621_socdev = socdev;\r
+ INIT_DELAYED_WORK(&codec->delayed_work, rt5621_work);\r
+ ret = device_create_file(&pdev->dev, &dev_attr_index_reg);\r
+ if (ret < 0)\r
+ printk(KERN_WARNING "asoc: failed to add index_reg sysfs files\n");\r
+\r
+ ret = -ENODEV;\r
+// if (setup->i2c_address) {\r
+ codec->hw_write = (hw_write_t)i2c_master_send;\r
+ ret = rt5621_add_i2c_device(pdev, setup);\r
+// }\r
+ if (ret != 0) {\r
+ kfree(codec->private_data);\r
+ kfree(codec);\r
+ }\r
+ return ret;\r
+}\r
+\r
+static int run_delayed_work(struct delayed_work *dwork)\r
+{\r
+ int ret;\r
+\r
+ /* cancel any work waiting to be queued. */\r
+ ret = cancel_delayed_work(dwork);\r
+\r
+ /* if there was any work waiting then we run it now and\r
+ * wait for it's completion */\r
+ if (ret) {\r
+ schedule_delayed_work(dwork, 0);\r
+ flush_scheduled_work();\r
+ }\r
+ return ret;\r
+}\r
+\r
+static int rt5621_remove(struct platform_device *pdev)\r
+{\r
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);\r
+ struct snd_soc_codec *codec = socdev ->card->codec;\r
+\r
+ if (codec->control_data)\r
+ rt5621_set_bias_level(codec, SND_SOC_BIAS_OFF);\r
+ run_delayed_work(&codec->delayed_work);\r
+ snd_soc_free_pcms(socdev);\r
+ snd_soc_dapm_free(socdev);\r
+ device_remove_file(&pdev->dev, &dev_attr_index_reg);\r
+ i2c_unregister_device(codec->control_data);\r
+ i2c_del_driver(&rt5621_i2c_driver);\r
+ kfree(codec->private_data);\r
+ kfree(codec);\r
+\r
+ return 0;\r
+}\r
+\r
+struct snd_soc_codec_device soc_codec_dev_rt5621 = {\r
+ .probe = rt5621_probe,\r
+ .remove = rt5621_remove,\r
+ .suspend = rt5621_suspend,\r
+ .resume = rt5621_resume,\r
+};\r
+\r
+EXPORT_SYMBOL_GPL(soc_codec_dev_rt5621);\r
+\r
+static int __init rt5621_modinit(void)\r
+{\r
+ return snd_soc_register_dai(&rt5621_dai);\r
+}\r
+\r
+static void __exit rt5621_exit(void)\r
+{\r
+ snd_soc_unregister_dai(&rt5621_dai);\r
+}\r
+\r
+module_init(rt5621_modinit);\r
+module_exit(rt5621_exit);\r
+MODULE_LICENSE("GPL");\r
+\r
--- /dev/null
+#ifndef _RT5621_H\r
+#define _RT5621_H\r
+\r
+\r
+#define RT5621_RESET 0X00 //RESET CODEC TO DEFAULT\r
+#define RT5621_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME\r
+#define RT5621_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME\r
+#define RT5621_MONO_AUX_OUT_VOL 0X06 //MONO OUTPUT/AUXOUT VOLUME\r
+#define RT5621_AUXIN_VOL 0X08 //AUXIN VOLUME\r
+#define RT5621_LINE_IN_VOL 0X0A //LINE IN VOLUME\r
+#define RT5621_STEREO_DAC_VOL 0X0C //STEREO DAC VOLUME\r
+#define RT5621_MIC_VOL 0X0E //MICROPHONE VOLUME\r
+#define RT5621_MIC_ROUTING_CTRL 0X10 //MIC ROUTING CONTROL\r
+#define RT5621_ADC_REC_GAIN 0X12 //ADC RECORD GAIN\r
+#define RT5621_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL\r
+#define RT5621_SOFT_VOL_CTRL_TIME 0X16 //SOFT VOLUME CONTROL TIME\r
+#define RT5621_OUTPUT_MIXER_CTRL 0X1C //OUTPUT MIXER CONTROL\r
+#define RT5621_MIC_CTRL 0X22 //MICROPHONE CONTROL\r
+#define RT5621_AUDIO_INTERFACE 0X34 //AUDIO INTERFACE\r
+#define RT5621_STEREO_AD_DA_CLK_CTRL 0X36 //STEREO AD/DA CLOCK CONTROL\r
+#define RT5621_COMPANDING_CTRL 0X38 //COMPANDING CONTROL\r
+#define RT5621_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1\r
+#define RT5621_PWR_MANAG_ADD2 0X3C //POWER MANAGMENT ADDITION 2\r
+#define RT5621_PWR_MANAG_ADD3 0X3E //POWER MANAGMENT ADDITION 3\r
+#define RT5621_ADD_CTRL_REG 0X40 //ADDITIONAL CONTROL REGISTER\r
+#define RT5621_GLOBAL_CLK_CTRL_REG 0X42 //GLOBAL CLOCK CONTROL REGISTER\r
+#define RT5621_PLL_CTRL 0X44 //PLL CONTROL\r
+#define RT5621_GPIO_OUTPUT_PIN_CTRL 0X4A //GPIO OUTPUT PIN CONTROL\r
+#define RT5621_GPIO_PIN_CONFIG 0X4C //GPIO PIN CONFIGURATION\r
+#define RT5621_GPIO_PIN_POLARITY 0X4E //GPIO PIN POLARITY/TYPE \r
+#define RT5621_GPIO_PIN_STICKY 0X50 //GPIO PIN STICKY \r
+#define RT5621_GPIO_PIN_WAKEUP 0X52 //GPIO PIN WAKE UP\r
+#define RT5621_GPIO_PIN_STATUS 0X54 //GPIO PIN STATUS\r
+#define RT5621_GPIO_PIN_SHARING 0X56 //GPIO PIN SHARING\r
+#define RT5621_OVER_TEMP_CURR_STATUS 0X58 //OVER TEMPERATURE AND CURRENT STATUS\r
+#define RT5621_JACK_DET_CTRL 0X5A //JACK DETECT CONTROL REGISTER\r
+#define RT5621_MISC_CTRL 0X5E //MISC CONTROL\r
+#define RT5621_PSEDUEO_SPATIAL_CTRL 0X60 //PSEDUEO STEREO & SPATIAL EFFECT BLOCK CONTROL\r
+#define RT5621_EQ_CTRL 0X62 //EQ CONTROL\r
+#define RT5621_EQ_MODE_ENABLE 0X66 //EQ MODE CHANGE ENABLE\r
+#define RT5621_AVC_CTRL 0X68 //AVC CONTROL\r
+#define RT5621_HID_CTRL_INDEX 0X6A //HIDDEN CONTROL INDEX PORT\r
+#define RT5621_HID_CTRL_DATA 0X6C //HIDDEN CONTROL DATA PORT\r
+#define RT5621_VENDOR_ID1 0x7C //VENDOR ID1\r
+#define RT5621_VENDOR_ID2 0x7E //VENDOR ID2\r
+\r
+\r
+//global definition\r
+#define RT_L_MUTE (0x1<<15) //MUTE LEFT CONTROL BIT\r
+#define RT_L_ZC (0x1<<14) //LEFT ZERO CROSS CONTROL BIT\r
+#define RT_L_SM (0x1<<13) //LEFT SOFTMUTE CONTROL BIT\r
+#define RT_R_MUTE (0x1<<7) //MUTE RIGHT CONTROL BIT\r
+#define RT_R_ZC (0x1<<6) //RIGHT ZERO CROSS CONTROL BIT\r
+#define RT_R_SM (0x1<<5) //RIGHT SOFTMUTE CONTROL BIT\r
+#define RT_M_HP_MIXER (0x1<<15) //Mute source to HP Mixer\r
+#define RT_M_SPK_MIXER (0x1<<14) //Mute source to Speaker Mixer\r
+#define RT_M_MONO_MIXER (0x1<<13) //Mute source to Mono Mixer\r
+#define SPK_CLASS_AB 0\r
+#define SPK_CLASS_D 1\r
+\r
+//Mic Routing Control(0x10)\r
+#define M_MIC1_TO_HP_MIXER (0x1<<15) //Mute MIC1 to HP mixer\r
+#define M_MIC1_TO_SPK_MIXER (0x1<<14) //Mute MiC1 to SPK mixer\r
+#define M_MIC1_TO_MONO_MIXER (0x1<<13) //Mute MIC1 to MONO mixer\r
+#define MIC1_DIFF_INPUT_CTRL (0x1<<12) //MIC1 different input control\r
+#define M_MIC2_TO_HP_MIXER (0x1<<7) //Mute MIC2 to HP mixer\r
+#define M_MIC2_TO_SPK_MIXER (0x1<<6) //Mute MiC2 to SPK mixer\r
+#define M_MIC2_TO_MONO_MIXER (0x1<<5) //Mute MIC2 to MONO mixer\r
+#define MIC2_DIFF_INPUT_CTRL (0x1<<4) //MIC2 different input control\r
+\r
+//ADC Record Gain(0x12)\r
+#define M_ADC_L_TO_HP_MIXER (0x1<<15) //Mute left of ADC to HP Mixer\r
+#define M_ADC_R_TO_HP_MIXER (0x1<<14) //Mute right of ADC to HP Mixer\r
+#define M_ADC_L_TO_MONO_MIXER (0x1<<13) //Mute left of ADC to MONO Mixer\r
+#define M_ADC_R_TO_MONO_MIXER (0x1<<12) //Mute right of ADC to MONO Mixer\r
+#define ADC_L_GAIN_MASK (0x1f<<7) //ADC Record Gain Left channel Mask\r
+#define ADC_L_ZC_DET (0x1<<6) //ADC Zero-Cross Detector Control\r
+#define ADC_R_ZC_DET (0x1<<5) //ADC Zero-Cross Detector Control\r
+#define ADC_R_GAIN_MASK (0x1f<<0) //ADC Record Gain Right channel Mask\r
+\r
+//ADC Input Mixer Control(0x14)\r
+#define M_MIC1_TO_ADC_L_MIXER (0x1<<14) //Mute mic1 to left channel of ADC mixer\r
+#define M_MIC2_TO_ADC_L_MIXER (0x1<<13) //Mute mic2 to left channel of ADC mixer\r
+#define M_LINEIN_L_TO_ADC_L_MIXER (0x1<<12) //Mute line In left channel to left channel of ADC mixer\r
+#define M_AUXIN_L_TO_ADC_L_MIXER (0x1<<11) //Mute aux In left channel to left channel of ADC mixer\r
+#define M_HPMIXER_L_TO_ADC_L_MIXER (0x1<<10) //Mute HP mixer left channel to left channel of ADC mixer\r
+#define M_SPKMIXER_L_TO_ADC_L_MIXER (0x1<<9) //Mute SPK mixer left channel to left channel of ADC mixer\r
+#define M_MONOMIXER_L_TO_ADC_L_MIXER (0x1<<8) //Mute MONO mixer left channel to left channel of ADC mixer\r
+#define M_MIC1_TO_ADC_R_MIXER (0x1<<6) //Mute mic1 to right channel of ADC mixer\r
+#define M_MIC2_TO_ADC_R_MIXER (0x1<<5) //Mute mic2 to right channel of ADC mixer\r
+#define M_LINEIN_R_TO_ADC_R_MIXER (0x1<<4) //Mute lineIn right channel to right channel of ADC mixer\r
+#define M_AUXIN_R_TO_ADC_R_MIXER (0x1<<3) //Mute aux In right channel to right channel of ADC mixer\r
+#define M_HPMIXER_R_TO_ADC_R_MIXER (0x1<<2) //Mute HP mixer right channel to right channel of ADC mixer\r
+#define M_SPKMIXER_R_TO_ADC_R_MIXER (0x1<<1) //Mute SPK mixer right channel to right channel of ADC mixer\r
+#define M_MONOMIXER_R_TO_ADC_R_MIXER (0x1<<0) //Mute MONO mixer right channel to right channel of ADC mixer\r
+\r
+//Output Mixer Control(0x1C)\r
+#define SPKOUT_N_SOUR_MASK (0x3<<14) \r
+#define SPKOUT_N_SOUR_LN (0x2<<14)\r
+#define SPKOUT_N_SOUR_RP (0x1<<14)\r
+#define SPKOUT_N_SOUR_RN (0x0<<14)\r
+#define SPK_OUTPUT_CLASS_AB (0x0<<13)\r
+#define SPK_OUTPUT_CLASS_D (0x1<<13)\r
+#define SPK_CLASS_AB_S_AMP (0x0<<12)\r
+#define SPK_CALSS_AB_W_AMP (0x1<<12)\r
+#define SPKOUT_INPUT_SEL_MASK (0x3<<10)\r
+#define SPKOUT_INPUT_SEL_MONOMIXER (0x3<<10)\r
+#define SPKOUT_INPUT_SEL_SPKMIXER (0x2<<10)\r
+#define SPKOUT_INPUT_SEL_HPMIXER (0x1<<10)\r
+#define SPKOUT_INPUT_SEL_VMID (0x0<<10)\r
+#define HPL_INPUT_SEL_HPLMIXER (0x1<<9)\r
+#define HPR_INPUT_SEL_HPRMIXER (0x1<<8) \r
+#define MONO_AUX_INPUT_SEL_MASK (0x3<<6)\r
+#define MONO_AUX_INPUT_SEL_MONO (0x3<<6)\r
+#define MONO_AUX_INPUT_SEL_SPK (0x2<<6)\r
+#define MONO_AUX_INPUT_SEL_HP (0x1<<6)\r
+#define MONO_AUX_INPUT_SEL_VMID (0x0<<6)\r
+\r
+//Micphone Control define(0x22)\r
+#define MIC1 1\r
+#define MIC2 2\r
+#define MIC_BIAS_90_PRECNET_AVDD 1\r
+#define MIC_BIAS_75_PRECNET_AVDD 2\r
+\r
+#define MIC1_BOOST_CTRL_MASK (0x3<<10)\r
+#define MIC1_BOOST_CTRL_BYPASS (0x0<<10)\r
+#define MIC1_BOOST_CTRL_20DB (0x1<<10)\r
+#define MIC1_BOOST_CTRL_30DB (0x2<<10)\r
+#define MIC1_BOOST_CTRL_40DB (0x3<<10)\r
+\r
+#define MIC2_BOOST_CTRL_MASK (0x3<<8)\r
+#define MIC2_BOOST_CTRL_BYPASS (0x0<<8)\r
+#define MIC2_BOOST_CTRL_20DB (0x1<<8)\r
+#define MIC2_BOOST_CTRL_30DB (0x2<<8)\r
+#define MIC2_BOOST_CTRL_40DB (0x3<<8)\r
+\r
+#define MICBIAS_VOLT_CTRL_MASK (0x1<<5)\r
+#define MICBIAS_VOLT_CTRL_90P (0x0<<5)\r
+#define MICBIAS_VOLT_CTRL_75P (0x1<<5)\r
+\r
+#define MICBIAS_SHORT_CURR_DET_MASK (0x3)\r
+#define MICBIAS_SHORT_CURR_DET_600UA (0x0)\r
+#define MICBIAS_SHORT_CURR_DET_1200UA (0x1)\r
+#define MICBIAS_SHORT_CURR_DET_1800UA (0x2)\r
+\r
+//Audio Interface(0x34) \r
+#define SDP_MASTER_MODE (0x0<<15) //Main I2S interface select Master mode\r
+#define SDP_SLAVE_MODE (0x1<<15) //Main I2S interface select Slave mode\r
+#define I2S_PCM_MODE (0x1<<14) //PCM 0:mode A ,1:mode B \r
+#define MAIN_I2S_BCLK_POL_CTRL (0x1<<7) //0:Normal 1:Invert\r
+#define ADC_DATA_L_R_SWAP (0x1<<5) //0:ADC data appear at left phase of LRCK\r
+ //1:ADC data appear at right phase of LRCK\r
+#define DAC_DATA_L_R_SWAP (0x1<<4) //0:DAC data appear at left phase of LRCK\r
+ //1:DAC data appear at right phase of LRCK \r
+//Data Length Slection\r
+#define I2S_DL_MASK (0x3<<2) //main i2s Data Length mask \r
+#define I2S_DL_16 (0x0<<2) //16 bits\r
+#define I2S_DL_20 (0x1<<2) //20 bits\r
+#define I2S_DL_24 (0x2<<2) //24 bits\r
+#define I2S_DL_32 (0x3<<2) //32 bits\r
+ \r
+//PCM Data Format Selection\r
+#define I2S_DF_MASK (0x3) //main i2s Data Format mask\r
+#define I2S_DF_I2S (0x0) //I2S FORMAT \r
+#define I2S_DF_RIGHT (0x1) //RIGHT JUSTIFIED format\r
+#define I2S_DF_LEFT (0x2) //LEFT JUSTIFIED format\r
+#define I2S_DF_PCM (0x3) //PCM format\r
+\r
+//Stereo AD/DA Clock Control(0x36h)\r
+#define I2S_PRE_DIV_MASK (0x7<<12) \r
+#define I2S_PRE_DIV_1 (0x0<<12) //DIV 1\r
+#define I2S_PRE_DIV_2 (0x1<<12) //DIV 2\r
+#define I2S_PRE_DIV_4 (0x2<<12) //DIV 4\r
+#define I2S_PRE_DIV_8 (0x3<<12) //DIV 8\r
+#define I2S_PRE_DIV_16 (0x4<<12) //DIV 16\r
+#define I2S_PRE_DIV_32 (0x5<<12) //DIV 32\r
+\r
+#define I2S_SCLK_DIV_MASK (0x7<<9) \r
+#define I2S_SCLK_DIV_1 (0x0<<9) //DIV 1\r
+#define I2S_SCLK_DIV_2 (0x1<<9) //DIV 2\r
+#define I2S_SCLK_DIV_3 (0x2<<9) //DIV 3\r
+#define I2S_SCLK_DIV_4 (0x3<<9) //DIV 4\r
+#define I2S_SCLK_DIV_6 (0x4<<9) //DIV 6\r
+#define I2S_SCLK_DIV_8 (0x5<<9) //DIV 8\r
+#define I2S_SCLK_DIV_12 (0x6<<9) //DIV 12\r
+#define I2S_SCLK_DIV_16 (0x7<<9) //DIV 16\r
+\r
+#define I2S_WCLK_DIV_PRE_MASK (0xF<<5) \r
+#define I2S_WCLK_PRE_DIV_1 (0x0<<5) //DIV 1\r
+#define I2S_WCLK_PRE_DIV_2 (0x1<<5) //DIV 2\r
+#define I2S_WCLK_PRE_DIV_3 (0x2<<5) //DIV 3\r
+#define I2S_WCLK_PRE_DIV_4 (0x3<<5) //DIV 4\r
+#define I2S_WCLK_PRE_DIV_5 (0x4<<5) //DIV 5\r
+#define I2S_WCLK_PRE_DIV_6 (0x5<<5) //DIV 6\r
+#define I2S_WCLK_PRE_DIV_7 (0x6<<5) //DIV 7\r
+#define I2S_WCLK_PRE_DIV_8 (0x7<<5) //DIV 8\r
+//........................\r
+\r
+#define I2S_WCLK_DIV_MASK (0x7<<2) \r
+#define I2S_WCLK_DIV_2 (0x0<<2) //DIV 2\r
+#define I2S_WCLK_DIV_4 (0x1<<2) //DIV 4\r
+#define I2S_WCLK_DIV_8 (0x2<<2) //DIV 8\r
+#define I2S_WCLK_DIV_16 (0x3<<2) //DIV 16\r
+#define I2S_WCLK_DIV_32 (0x4<<2) //DIV 32\r
+\r
+#define ADDA_FILTER_CLK_SEL_256FS (0<<1) //256FS\r
+#define ADDA_FILTER_CLK_SEL_384FS (1<<1) //384FS\r
+\r
+#define ADDA_OSR_SEL_64FS (0) //64FS\r
+#define ADDA_OSR_SEL_128FS (1) //128FS\r
+\r
+//Power managment addition 1 (0x3A),0:Disable,1:Enable\r
+#define PWR_MAIN_I2S_EN (0x1<<15)\r
+#define PWR_ZC_DET_PD_EN (0x1<<14) \r
+#define PWR_MIC1_BIAS_EN (0x1<<11)\r
+#define PWR_SHORT_CURR_DET_EN (0x1<<10)\r
+#define PWR_SOFTGEN_EN (0x1<<8)\r
+#define PWR_DEPOP_BUF_HP (0x1<<6)\r
+#define PWR_HP_OUT_AMP (0x1<<5)\r
+#define PWR_HP_OUT_ENH_AMP (0x1<<4)\r
+#define PWR_DEPOP_BUF_AUX (0x1<<2)\r
+#define PWR_AUX_OUT_AMP (0x1<<1)\r
+#define PWR_AUX_OUT_ENH_AMP (0x1)\r
+\r
+\r
+//Power managment addition 2(0x3C),0:Disable,1:Enable\r
+#define PWR_CLASS_AB (0x1<<15)\r
+#define PWR_CLASS_D (0x1<<14)\r
+#define PWR_VREF (0x1<<13)\r
+#define PWR_PLL (0x1<<12)\r
+#define PWR_DAC_REF_CIR (0x1<<10)\r
+#define PWR_L_DAC_CLK (0x1<<9)\r
+#define PWR_R_DAC_CLK (0x1<<8)\r
+#define PWR_L_ADC_CLK_GAIN (0x1<<7)\r
+#define PWR_R_ADC_CLK_GAIN (0x1<<6)\r
+#define PWR_L_HP_MIXER (0x1<<5)\r
+#define PWR_R_HP_MIXER (0x1<<4)\r
+#define PWR_SPK_MIXER (0x1<<3)\r
+#define PWR_MONO_MIXER (0x1<<2)\r
+#define PWR_L_ADC_REC_MIXER (0x1<<1)\r
+#define PWR_R_ADC_REC_MIXER (0x1)\r
+\r
+//Power managment addition 3(0x3E),0:Disable,1:Enable\r
+#define PWR_MAIN_BIAS (0x1<<15)\r
+#define PWR_AUXOUT_L_VOL_AMP (0x1<<14)\r
+#define PWR_AUXOUT_R_VOL_AMP (0x1<<13)\r
+#define PWR_SPK_OUT (0x1<<12)\r
+#define PWR_HP_L_OUT_VOL (0x1<<10)\r
+#define PWR_HP_R_OUT_VOL (0x1<<9)\r
+#define PWR_LINEIN_L_VOL (0x1<<7)\r
+#define PWR_LINEIN_R_VOL (0x1<<6)\r
+#define PWR_AUXIN_L_VOL (0x1<<5)\r
+#define PWR_AUXIN_R_VOL (0x1<<4)\r
+#define PWR_MIC1_FUN_CTRL (0x1<<3)\r
+#define PWR_MIC2_FUN_CTRL (0x1<<2)\r
+#define PWR_MIC1_BOOST_MIXER (0x1<<1)\r
+#define PWR_MIC2_BOOST_MIXER (0x1)\r
+\r
+\r
+//Additional Control Register(0x40)\r
+#define AUXOUT_SEL_DIFF (0x1<<15) //Differential Mode\r
+#define AUXOUT_SEL_SE (0x1<<15) //Single-End Mode\r
+\r
+#define SPK_AB_AMP_CTRL_MASK (0x7<<12)\r
+#define SPK_AB_AMP_CTRL_RATIO_225 (0x0<<12) //2.25 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_200 (0x1<<12) //2.00 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_175 (0x2<<12) //1.75 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_150 (0x3<<12) //1.50 Vdd\r
+#define SPK_AB_AMP_CTRL_RATIO_125 (0x4<<12) //1.25 Vdd \r
+#define SPK_AB_AMP_CTRL_RATIO_100 (0x5<<12) //1.00 Vdd\r
+\r
+#define SPK_D_AMP_CTRL_MASK (0x3<<10)\r
+#define SPK_D_AMP_CTRL_RATIO_175 (0x0<<10) //1.75 Vdd\r
+#define SPK_D_AMP_CTRL_RATIO_150 (0x1<<10) //1.50 Vdd \r
+#define SPK_D_AMP_CTRL_RATIO_125 (0x2<<10) //1.25 Vdd\r
+#define SPK_D_AMP_CTRL_RATIO_100 (0x3<<10) //1.00 Vdd\r
+\r
+#define STEREO_DAC_HI_PASS_FILTER_EN (0x1<<9) //Stereo DAC high pass filter enable\r
+#define STEREO_ADC_HI_PASS_FILTER_EN (0x1<<8) //Stereo ADC high pass filter enable\r
+\r
+#define DIG_VOL_BOOST_MASK (0x3<<4) //Digital volume Boost mask\r
+#define DIG_VOL_BOOST_0DB (0x0<<4) //Digital volume Boost 0DB\r
+#define DIG_VOL_BOOST_6DB (0x1<<4) //Digital volume Boost 6DB\r
+#define DIG_VOL_BOOST_12DB (0x2<<4) //Digital volume Boost 12DB\r
+#define DIG_VOL_BOOST_18DB (0x3<<4) //Digital volume Boost 18DB\r
+\r
+\r
+//Global Clock Control Register(0x42)\r
+#define SYSCLK_SOUR_SEL_MASK (0x1<<15)\r
+#define SYSCLK_SOUR_SEL_MCLK (0x0<<15) //system Clock source from MCLK\r
+#define SYSCLK_SOUR_SEL_PLL (0x1<<15) //system Clock source from PLL\r
+#define PLLCLK_SOUR_SEL_MCLK (0x0<<14) //PLL clock source from MCLK\r
+#define PLLCLK_SOUR_SEL_BITCLK (0x1<<14) //PLL clock source from BITCLK\r
+\r
+#define PLLCLK_DIV_RATIO_MASK (0x3<<1) \r
+#define PLLCLK_DIV_RATIO_DIV1 (0x0<<1) //DIV 1\r
+#define PLLCLK_DIV_RATIO_DIV2 (0x1<<1) //DIV 2\r
+#define PLLCLK_DIV_RATIO_DIV4 (0x2<<1) //DIV 4\r
+#define PLLCLK_DIV_RATIO_DIV8 (0x3<<1) //DIV 8\r
+\r
+#define PLLCLK_PRE_DIV1 (0x0) //DIV 1\r
+#define PLLCLK_PRE_DIV2 (0x1) //DIV 2\r
+\r
+//PLL Control(0x44)\r
+\r
+#define PLL_CTRL_M_VAL(m) ((m)&0xf)\r
+#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4)\r
+#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8)\r
+\r
+//GPIO Pin Configuration(0x4C)\r
+#define GPIO_PIN_MASK (0x1<<1)\r
+#define GPIO_PIN_SET_INPUT (0x1<<1)\r
+#define GPIO_PIN_SET_OUTPUT (0x0<<1)\r
+\r
+//Pin Sharing(0x56)\r
+#define LINEIN_L_PIN_SHARING (0x1<<15)\r
+#define LINEIN_L_PIN_AS_LINEIN_L (0x0<<15)\r
+#define LINEIN_L_PIN_AS_JD1 (0x1<<15)\r
+\r
+#define LINEIN_R_PIN_SHARING (0x1<<14)\r
+#define LINEIN_R_PIN_AS_LINEIN_R (0x0<<14)\r
+#define LINEIN_R_PIN_AS_JD2 (0x1<<14)\r
+\r
+#define GPIO_PIN_SHARING (0x3)\r
+#define GPIO_PIN_AS_GPIO (0x0)\r
+#define GPIO_PIN_AS_IRQOUT (0x1)\r
+#define GPIO_PIN_AS_PLLOUT (0x3)\r
+\r
+//Jack Detect Control Register(0x5A)\r
+#define JACK_DETECT_MASK (0x3<<14)\r
+#define JACK_DETECT_USE_JD2 (0x3<<14)\r
+#define JACK_DETECT_USE_JD1 (0x2<<14)\r
+#define JACK_DETECT_USE_GPIO (0x1<<14)\r
+#define JACK_DETECT_OFF (0x0<<14)\r
+\r
+#define SPK_EN_IN_HI (0x1<<11)\r
+#define AUX_R_EN_IN_HI (0x1<<10)\r
+#define AUX_L_EN_IN_HI (0x1<<9)\r
+#define HP_EN_IN_HI (0x1<<8)\r
+#define SPK_EN_IN_LO (0x1<<7)\r
+#define AUX_R_EN_IN_LO (0x1<<6)\r
+#define AUX_L_EN_IN_LO (0x1<<5)\r
+#define HP_EN_IN_LO (0x1<<4)\r
+\r
+////MISC CONTROL(0x5E)\r
+#define DISABLE_FAST_VREG (0x1<<15)\r
+#define SPK_CLASS_AB_OC_PD (0x1<<13)\r
+#define SPK_CLASS_AB_OC_DET (0x1<<12)\r
+#define HP_DEPOP_MODE3_EN (0x1<<10)\r
+#define HP_DEPOP_MODE2_EN (0x1<<9)\r
+#define HP_DEPOP_MODE1_EN (0x1<<8)\r
+#define AUXOUT_DEPOP_MODE3_EN (0x1<<6)\r
+#define AUXOUT_DEPOP_MODE2_EN (0x1<<5)\r
+#define AUXOUT_DEPOP_MODE1_EN (0x1<<4)\r
+#define M_DAC_L_INPUT (0x1<<3)\r
+#define M_DAC_R_INPUT (0x1<<2)\r
+#define IRQOUT_INV_CTRL (0x1<<0)\r
+\r
+//Psedueo Stereo & Spatial Effect Block Control(0x60)\r
+#define SPATIAL_CTRL_EN (0x1<<15)\r
+#define ALL_PASS_FILTER_EN (0x1<<14)\r
+#define PSEUDO_STEREO_EN (0x1<<13)\r
+#define STEREO_EXPENSION_EN (0x1<<12)\r
+\r
+#define GAIN_3D_PARA_L_MASK (0x7<<9)\r
+#define GAIN_3D_PARA_L_1_00 (0x0<<9)\r
+#define GAIN_3D_PARA_L_1_25 (0x1<<9)\r
+#define GAIN_3D_PARA_L_1_50 (0x2<<9)\r
+#define GAIN_3D_PARA_L_1_75 (0x3<<9)\r
+#define GAIN_3D_PARA_L_2_00 (0x4<<9)\r
+\r
+#define GAIN_3D_PARA_R_MASK (0x7<<6)\r
+#define GAIN_3D_PARA_R_1_00 (0x0<<6)\r
+#define GAIN_3D_PARA_R_1_25 (0x1<<6)\r
+#define GAIN_3D_PARA_R_1_50 (0x2<<6)\r
+#define GAIN_3D_PARA_R_1_75 (0x3<<6)\r
+#define GAIN_3D_PARA_R_2_00 (0x4<<6)\r
+\r
+#define RATIO_3D_L_MASK (0x3<<4)\r
+#define RATIO_3D_L_0_0 (0x0<<4)\r
+#define RATIO_3D_L_0_66 (0x1<<4)\r
+#define RATIO_3D_L_1_0 (0x2<<4)\r
+\r
+#define RATIO_3D_R_MASK (0x3<<2)\r
+#define RATIO_3D_R_0_0 (0x0<<2)\r
+#define RATIO_3D_R_0_66 (0x1<<2)\r
+#define RATIO_3D_R_1_0 (0x2<<2)\r
+\r
+#define APF_MASK (0x3)\r
+#define APF_FOR_48K (0x3)\r
+#define APF_FOR_44_1K (0x2)\r
+#define APF_FOR_32K (0x1)\r
+\r
+//EQ CONTROL(0x62)\r
+\r
+#define EN_HW_EQ_BLK (0x1<<15) //HW EQ block control\r
+#define EN_HW_EQ_HPF_MODE (0x1<<14) //High Frequency shelving filter mode\r
+#define EN_HW_EQ_SOUR (0x1<<11) //0:DAC PATH,1:ADC PATH\r
+#define EN_HW_EQ_HPF (0x1<<4) //EQ High Pass Filter Control\r
+#define EN_HW_EQ_BP3 (0x1<<3) //EQ Band-3 Control\r
+#define EN_HW_EQ_BP2 (0x1<<2) //EQ Band-2 Control\r
+#define EN_HW_EQ_BP1 (0x1<<1) //EQ Band-1 Control\r
+#define EN_HW_EQ_LPF (0x1<<0) //EQ Low Pass Filter Control\r
+\r
+//EQ Mode Change Enable(0x66)\r
+#define EQ_HPF_CHANGE_EN (0x1<<4) //EQ High Pass Filter Mode Change Enable\r
+#define EQ_BP3_CHANGE_EN (0x1<<3) //EQ Band-3 Pass Filter Mode Change Enable\r
+#define EQ_BP2_CHANGE_EN (0x1<<2) //EQ Band-2 Pass Filter Mode Change Enable\r
+#define EQ_BP1_CHANGE_EN (0x1<<1) //EQ Band-1 Pass Filter Mode Change Enable\r
+#define EQ_LPF_CHANGE_EN (0x1<<0) //EQ Low Pass Filter Mode Change Enable\r
+\r
+\r
+//AVC Control(0x68)\r
+#define AVC_ENABLE (0x1<<15)\r
+#define AVC_TARTGET_SEL_MASK (0x1<<14)\r
+#define AVC_TARTGET_SEL_R (0x1<<14)\r
+#define AVC_TARTGET_SEL_L (0x0<<14)\r
+\r
+\r
+struct rt5621_setup_data {\r
+ unsigned short i2c_address;\r
+ unsigned short i2c_bus;\r
+};\r
+\r
+\r
+\r
+#define RT5621_PLL_FR_MCLK 0\r
+#define RT5621_PLL_FR_BCLK 1\r
+\r
+\r
+#define USE_DAPM_CONTROL 0\r
+#define REALTEK_HWDEP 0\r
+\r
+//WaveOut channel for realtek codec\r
+enum \r
+{\r
+ RT_WAVOUT_SPK =(0x1<<0),\r
+ RT_WAVOUT_SPK_R =(0x1<<1),\r
+ RT_WAVOUT_SPK_L =(0x1<<2),\r
+ RT_WAVOUT_HP =(0x1<<3),\r
+ RT_WAVOUT_HP_R =(0x1<<4),\r
+ RT_WAVOUT_HP_L =(0x1<<5), \r
+ RT_WAVOUT_MONO =(0x1<<6),\r
+ RT_WAVOUT_AUXOUT =(0x1<<7),\r
+ RT_WAVOUT_AUXOUT_R =(0x1<<8),\r
+ RT_WAVOUT_AUXOUT_L =(0x1<<9),\r
+ RT_WAVOUT_LINEOUT =(0x1<<10),\r
+ RT_WAVOUT_LINEOUT_R =(0x1<<11),\r
+ RT_WAVOUT_LINEOUT_L =(0x1<<12), \r
+ RT_WAVOUT_DAC =(0x1<<13), \r
+ RT_WAVOUT_ALL_ON =(0x1<<14),\r
+};\r
+\r
+//WaveIn channel for realtek codec\r
+enum\r
+{\r
+ RT_WAVIN_R_MONO_MIXER =(0x1<<0),\r
+ RT_WAVIN_R_SPK_MIXER =(0x1<<1),\r
+ RT_WAVIN_R_HP_MIXER =(0x1<<2),\r
+ RT_WAVIN_R_PHONE =(0x1<<3),\r
+ RT_WAVIN_R_AUXIN =(0x1<<3), \r
+ RT_WAVIN_R_LINE_IN =(0x1<<4),\r
+ RT_WAVIN_R_MIC2 =(0x1<<5),\r
+ RT_WAVIN_R_MIC1 =(0x1<<6),\r
+\r
+ RT_WAVIN_L_MONO_MIXER =(0x1<<8),\r
+ RT_WAVIN_L_SPK_MIXER =(0x1<<9),\r
+ RT_WAVIN_L_HP_MIXER =(0x1<<10),\r
+ RT_WAVIN_L_PHONE =(0x1<<11),\r
+ RT_WAVIN_L_AUXIN =(0x1<<11),\r
+ RT_WAVIN_L_LINE_IN =(0x1<<12),\r
+ RT_WAVIN_L_MIC2 =(0x1<<13),\r
+ RT_WAVIN_L_MIC1 =(0x1<<14),\r
+};\r
+\r
+enum \r
+{\r
+ POWER_STATE_D0=0,\r
+ POWER_STATE_D1,\r
+ POWER_STATE_D1_PLAYBACK,\r
+ POWER_STATE_D1_RECORD,\r
+ POWER_STATE_D2,\r
+ POWER_STATE_D2_PLAYBACK,\r
+ POWER_STATE_D2_RECORD,\r
+ POWER_STATE_D3,\r
+ POWER_STATE_D4\r
+\r
+}; \r
+\r
+#if REALTEK_HWDEP\r
+\r
+struct rt56xx_reg_state\r
+{\r
+ unsigned int reg_index;\r
+ unsigned int reg_value;\r
+};\r
+\r
+struct rt56xx_cmd\r
+{\r
+ size_t number;\r
+ struct rt56xx_reg_state __user *buf; \r
+};\r
+\r
+enum \r
+{\r
+ RT_READ_CODEC_REG_IOCTL = _IOR('R', 0x01, struct rt56xx_cmd),\r
+ RT_READ_ALL_CODEC_REG_IOCTL = _IOR('R', 0x02, struct rt56xx_cmd),\r
+ RT_WRITE_CODEC_REG_IOCTL = _IOW('R', 0x03, struct rt56xx_cmd),\r
+};\r
+\r
+#endif\r
+\r
+extern struct snd_soc_dai rt5621_dai; \r
+extern struct snd_soc_codec_device soc_codec_dev_rt5621;\r
+\r
+#endif\r
--- /dev/null
+/*
+ * rt5631.c -- RT5631 ALSA Soc Audio driver
+ *
+ * Copyright 2009 Realtek Microelectronics
+ *
+ * Author: flove <flove@realtek.com>
+ *
+ * Based on WM8753.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include "rt5631.h"
+
+#define RT5631_VERSION "0.01 alsa 1.0.21"
+#define ALSA_SOC_VERSION "1.0.21"
+static const u16 rt5631_reg[0x80];
+static int timesofbclk = 32;
+module_param(timesofbclk, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(timeofbclk, "relationship between bclk and fs");
+
+#define VIRTUAL_POWER_CONTROL 0x90
+/*
+ * bit0: spkl amp power
+ * bit1: spkr amp power
+ * bit2: dmic flag
+ *
+*/
+struct rt5631_priv {
+ int master;
+ int sysclk;
+ int dmic_used_flag;
+};
+
+static unsigned int reg90;
+static int rt5631_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val);
+static unsigned int rt5631_read(struct snd_soc_codec *codec, unsigned int reg);
+#define rt5631_reset(c) rt5631_write(c, RT5631_RESET, 0)
+#define rt5631_write_mask(c, reg, val, mask) snd_soc_update_bits(c, reg, mask, val)
+static int rt5631_reg_init(struct snd_soc_codec *codec);
+
+static struct snd_soc_device *rt5631_socdev;
+/*
+ * read rt5631 register cache
+ */
+static inline unsigned int rt5631_read_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg < 1 || reg > (ARRAY_SIZE(rt5631_reg) + 1))
+ return -1;
+ return cache[reg];
+}
+
+
+/*
+ * write rt5631 register cache
+ */
+
+static inline void rt5631_write_reg_cache(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ u16 *cache = codec->reg_cache;
+ if (reg < 0 || reg > 0x7e)
+ return;
+ cache[reg] = value;
+}
+
+static int rt5631_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val)
+{
+ u8 data[3];
+
+ if (reg > 0x7e) {
+ if (reg == 0x90)
+ reg90 = val;
+ }
+
+ data[0] = reg;
+ data[1] = (0xff00 & val) >> 8;
+ data[2] = (0xff & val);
+
+ if (codec->hw_write(codec->control_data, data, 3) == 3) {
+ rt5631_write_reg_cache(codec, reg, val);
+ printk(KERN_INFO "%s reg=0x%x, val=0x%x\n", __func__, reg, val);
+ return 0;
+ } else {
+ printk(KERN_ERR "%s failed\n", __func__);
+ return -EIO;
+ }
+}
+
+static unsigned int rt5631_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+ u8 data[2] = {0};
+ unsigned int value = 0x0;
+
+ if (reg > 0x7e) {
+ if (reg == 0x90)
+ return reg90;
+ }
+
+ data[0] = reg;
+
+ i2c_master_reg8_recv(codec->control_data,reg,data,2,100 * 1000);
+
+ value = (data[0]<<8) | data[1];
+
+ printk("rt5631_read reg%x=%x\n",reg,value);
+
+ return value;
+}
+
+#define rt5631_write_index_reg(c, addr, data) \
+{ \
+ rt5631_write(c, 0x6a, addr); \
+ rt5631_write(c, 0x6c, data); \
+}
+
+
+struct rt5631_init_reg{
+ u8 reg;
+ u16 val;
+};
+
+static struct rt5631_init_reg init_list[] = {
+
+ {RT5631_SPK_OUT_VOL , 0xc8c8}, //speaker channel volume select SPKMIXER,0DB by default
+ {RT5631_HP_OUT_VOL , 0xc0c0}, //Headphone channel volume select OUTMIXER,0DB by default
+ {RT5631_MONO_AXO_1_2_VOL , 0xf0c0}, //AXO1/AXO2 channel volume select OUTMIXER,0DB by default
+ {RT5631_ADC_REC_MIXER , 0xb0f0}, //Record Mixer source from Mic1 by default
+ {RT5631_MIC_CTRL_2 , 0x5500}, //Mic1/Mic2 boost 40DB by default
+ {RT5631_OUTMIXER_L_CTRL , 0xdfC0}, //DAC_L-->OutMixer_L by default
+ {RT5631_OUTMIXER_R_CTRL , 0xdfC0}, //DAC_R-->OutMixer_R by default
+ {RT5631_AXO1MIXER_CTRL , 0x8840}, //OutMixer_L-->AXO1Mixer by default
+ {RT5631_AXO2MIXER_CTRL , 0x8880}, //OutMixer_R-->AXO2Mixer by default
+ {RT5631_SPK_MIXER_CTRL , 0xd8d8}, //DAC-->SpeakerMixer
+ {RT5631_SPK_MONO_OUT_CTRL , 0x6c00}, //Speaker volume-->SPOMixer(L-->L,R-->R)
+ {RT5631_GEN_PUR_CTRL_REG , 0x4e00}, //Speaker AMP ratio gain is 1.44X
+ {RT5631_SPK_MONO_HP_OUT_CTRL, 0x0000}, //HP from OutMixer,speaker out from SpeakerOut Mixer
+ {RT5631_DEPOP_FUN_CTRL_2 , 0x8000}, //HP depop by register control
+ {RT5631_INT_ST_IRQ_CTRL_2 , 0x0f18}, //enable HP zero cross
+ {RT5631_MIC_CTRL_1 , 0x8000}, //set mic 1 to differnetial mode
+// {RT5631_GPIO_CTRL , 0x0000}, //set GPIO to input pin
+// {RT5631_JACK_DET_CTRL , 0x4e80}, //Jack detect for GPIO,high is HP,low is speaker
+// {RT5631_JACK_DET_CTRL , 0x4bc0}, //Jack detect for GPIO,high is speaker,low is hp
+};
+
+#define RT5631_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static int rt5631_reg_init(struct snd_soc_codec *codec)
+{
+ int i;
+
+ for (i = 0; i < RT5631_INIT_REG_LEN; i ++) {
+ rt5631_write(codec, init_list[i].reg, init_list[i].val);
+ }
+
+ return 0;
+}
+
+static const char *rt5631_spol_source_sel[] = {"SPOLMIX", "MONOIN_RX", "VDAC", "DACL"};
+static const char *rt5631_spor_source_sel[] = {"SPORMIX", "MONOIN_RX", "VDAC", "DACR"};
+static const char *rt5631_mono_source_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"};
+static const char *rt5631_input_mode_source_sel[] = {"Single-end", "Differential"};
+static const char *rt5631_mic_boost[] = {"Bypass", "+20db", "+24db", "+30db",
+ "+35db", "+40db", "+44db", "+50db", "+52db"};
+
+static const struct soc_enum rt5631_enum[] = {
+SOC_ENUM_SINGLE(RT5631_SPK_MONO_HP_OUT_CTRL, 14, 4, rt5631_spol_source_sel), /*0*/
+SOC_ENUM_SINGLE(RT5631_SPK_MONO_HP_OUT_CTRL, 10, 4, rt5631_spor_source_sel), /*1*/
+SOC_ENUM_SINGLE(RT5631_SPK_MONO_HP_OUT_CTRL, 6, 3, rt5631_mono_source_sel), /*2*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_1, 15, 2, rt5631_input_mode_source_sel), /*3*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_1, 7, 2, rt5631_input_mode_source_sel), /*4*/
+SOC_ENUM_SINGLE(RT5631_MONO_INPUT_VOL, 15, 2, rt5631_input_mode_source_sel), /*5*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_2, 12, 9, rt5631_mic_boost), /*6*/
+SOC_ENUM_SINGLE(RT5631_MIC_CTRL_2, 8, 9, rt5631_mic_boost), /*7*/
+};
+
+static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int val;
+
+ val = rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0004;
+ val >>= 2;
+ ucontrol->value.integer.value[0] = val;
+ return 0;
+}
+
+static void rt5631_close_dmic(struct snd_soc_codec *codec) //disable DMic to ADC filter
+{
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_L_CH_MUTE | DMIC_R_CH_MUTE, DMIC_L_CH_MUTE_MASK | DMIC_R_CH_MUTE_MASK);
+
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_DIS, DMIC_ENA_MASK);
+}
+
+static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int old, new;
+ struct rt5631_priv *rt5631 = codec->private_data;
+
+ old = rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0004;
+ new = ucontrol->value.integer.value[0] << 2;
+
+ if (old == new)
+ return 0;
+
+ rt5631_write_mask(codec, VIRTUAL_POWER_CONTROL, new, 0x0004);
+
+ if (new)
+ rt5631->dmic_used_flag = 1;
+ else
+ {
+ rt5631_close_dmic(codec);
+ rt5631->dmic_used_flag=0;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new rt5631_snd_controls[] = {
+SOC_ENUM("MIC1 Mode Control", rt5631_enum[3]),
+SOC_ENUM("MIC1 Boost", rt5631_enum[6]),
+
+SOC_ENUM("MIC2 Mode Control", rt5631_enum[4]),
+SOC_ENUM("MIC2 Boost", rt5631_enum[7]),
+SOC_ENUM("MONOIN Mode Control", rt5631_enum[5]),
+
+SOC_DOUBLE("PCM Playback Volume", RT5631_STEREO_DAC_VOL_2, 8, 0, 255, 1),
+SOC_DOUBLE("PCM Playback Switch", RT5631_STEREO_DAC_VOL_1,15, 7, 1, 1),
+
+SOC_DOUBLE("MONOIN_RX Capture Volume", RT5631_MONO_INPUT_VOL, 8, 0, 31, 1),
+
+SOC_DOUBLE("AXI Capture Volume", RT5631_AUX_IN_VOL, 8, 0, 31, 1),
+
+SOC_SINGLE("AXO1 Playback Switch", RT5631_MONO_AXO_1_2_VOL, 15, 1, 1),
+SOC_SINGLE("AXO2 Playback Switch", RT5631_MONO_AXO_1_2_VOL, 7, 1, 1),
+SOC_DOUBLE("OUTVOL Playback Volume", RT5631_MONO_AXO_1_2_VOL, 8, 0, 31, 1),
+
+SOC_DOUBLE("Speaker Playback Switch", RT5631_SPK_OUT_VOL,15, 7, 1, 1),
+SOC_DOUBLE("Speaker Playback Volume", RT5631_SPK_OUT_VOL, 8, 0, 63, 1),
+
+SOC_SINGLE("MONO Playback Switch", RT5631_MONO_AXO_1_2_VOL, 13, 1, 1),
+
+SOC_DOUBLE("HP Playback Switch", RT5631_HP_OUT_VOL,15, 7, 1, 1),
+SOC_DOUBLE("HP Playback Volume", RT5631_HP_OUT_VOL, 8, 0, 63, 1),
+
+//SOC_SINGLE_EXT("HIFI Loopback", ),/*not finished*/
+//SOC_SINGLE_EXT("Voice Loopback", ), /*not finished*/
+SOC_SINGLE_EXT("DMIC Capture Switch", VIRTUAL_POWER_CONTROL, 2, 1, 0,
+ rt5631_dmic_get, rt5631_dmic_put),
+};
+
+static int rt5631_add_controls(struct snd_soc_codec *codec)
+{
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(rt5631_snd_controls); i ++) {
+
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&rt5631_snd_controls[i],
+ codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new rt5631_recmixl_mixer_controls[] = {
+SOC_DAPM_SINGLE("OUTMIXL Capture Switch", RT5631_ADC_REC_MIXER, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC1_BST1 Capture Switch", RT5631_ADC_REC_MIXER, 14, 1, 1),
+SOC_DAPM_SINGLE("AXILVOL Capture Switch", RT5631_ADC_REC_MIXER, 13, 1, 1),
+SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER, 12, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_recmixr_mixer_controls[] = {
+SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER, 4, 1, 1),
+SOC_DAPM_SINGLE("AXIRVOL Capture Switch", RT5631_ADC_REC_MIXER, 5, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Capture Switch", RT5631_ADC_REC_MIXER, 6, 1, 1),
+SOC_DAPM_SINGLE("OUTMIXR Capture Switch", RT5631_ADC_REC_MIXER, 7, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_spkmixl_mixer_controls[] = {
+SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_SPK_MIXER_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC1_P Playback Switch", RT5631_SPK_MIXER_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_SPK_MIXER_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("OUTMIXL Playback Switch", RT5631_SPK_MIXER_CTRL, 12, 1, 1)
+};
+
+static const struct snd_kcontrol_new rt5631_spkmixr_mixer_controls[] = {
+SOC_DAPM_SINGLE("OUTMIXR Playback Switch", RT5631_SPK_MIXER_CTRL, 4, 1, 1),
+SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_SPK_MIXER_CTRL, 5, 1, 1),
+SOC_DAPM_SINGLE("MIC2_P Playback Switch", RT5631_SPK_MIXER_CTRL, 6, 1, 1),
+SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_SPK_MIXER_CTRL, 7, 1, 1),
+};
+
+static const struct snd_kcontrol_new rt5631_outmixl_mixer_controls[] = {
+SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_L_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_L_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_OUTMIXER_L_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_L_CTRL, 12, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_L_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("MONOIN_RXP Playback Switch", RT5631_OUTMIXER_L_CTRL, 10, 1, 1),
+SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_L_CTRL, 9, 1, 1),
+SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_L_CTRL, 8, 1, 1),
+SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_L_CTRL, 7, 1, 1)
+};
+
+static const struct snd_kcontrol_new rt5631_outmixr_mixer_controls[] = {
+SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_R_CTRL, 7, 1, 1),
+SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_R_CTRL, 8, 1, 1),
+SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_R_CTRL, 9, 1, 1),
+SOC_DAPM_SINGLE("MONOIN_RXN Playback Switch", RT5631_OUTMIXER_R_CTRL, 10, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_R_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_R_CTRL, 12, 1, 1),
+SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_OUTMIXER_R_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_R_CTRL, 14, 1, 1),
+SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_R_CTRL, 15, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_AXO1MIX_mixer_controls[] = {
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO1MIXER_CTRL, 15 , 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO1MIXER_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO1MIXER_CTRL, 7 ,1 ,1),
+SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO1MIXER_CTRL, 6, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_AXO2MIX_mixer_controls[] = {
+SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO2MIXER_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO2MIXER_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO2MIXER_CTRL, 7, 1, 1),
+SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO2MIXER_CTRL, 6, 1 ,1),
+};
+
+static const struct snd_kcontrol_new rt5631_spolmix_mixer_controls[] = {
+SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 15, 1, 1),
+SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 14, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_spormix_mixer_controls[] = {
+SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 13, 1, 1),
+SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 12, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = {
+SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 11, 1, 1),
+SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, 10, 1, 1),
+};
+
+
+static const struct snd_kcontrol_new rt5631_spol_mux_control =
+SOC_DAPM_ENUM("Route", rt5631_enum[0]);
+static const struct snd_kcontrol_new rt5631_spor_mux_control =
+SOC_DAPM_ENUM("Route", rt5631_enum[1]);
+static const struct snd_kcontrol_new rt5631_mono_mux_control =
+SOC_DAPM_ENUM("Route", rt5631_enum[2]);
+
+
+
+static int spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int l, r;
+
+ l = rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0001;
+ r = (rt5631_read(codec, VIRTUAL_POWER_CONTROL) & 0x0002) >> 1;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMD:
+ printk("spk_event --SND_SOC_DAPM_POST_PMD\n");
+ rt5631_write_mask(codec, RT5631_SPK_OUT_VOL, 0x8080, 0x8080);
+
+ if ((l == 0) && (r == 0))
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x0000, 0x1000);
+
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD4, 0x0000, 0xC000);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ printk("spk_event --SND_SOC_DAPM_POST_PMU\n");
+ if ((l != 0) || (r != 0))
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x1000, 0x1000);
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD4, 0xC000, 0xC000);
+ rt5631_write_mask(codec, RT5631_SPK_OUT_VOL, 0x0000, 0x8080);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static void hp_depop2(struct snd_soc_codec *codec,unsigned int EnableHPOut)
+{
+
+ unsigned int SoftVol,HPZeroCross;
+
+ SoftVol = rt5631_read(codec, RT5631_SOFT_VOL_CTRL);
+ rt5631_write(codec,RT5631_SOFT_VOL_CTRL,0);
+ HPZeroCross=rt5631_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+ rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross&0xf7ff); //disable Zero Cross of HP
+ //enable HP out
+ if(EnableHPOut)
+ {
+
+ rt5631_write_index_reg(codec,0x56,0x303e);
+
+ rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,PWR_CHARGE_PUMP|PWR_HP_L_AMP|PWR_HP_R_AMP
+ ,PWR_CHARGE_PUMP|PWR_HP_L_AMP|PWR_HP_R_AMP);
+ rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_DEPOP2_FOR_HP);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(100));
+ rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,PWR_HP_DEPOP_DIS|PWR_HP_AMP_DRIVING,PWR_HP_DEPOP_DIS|PWR_HP_AMP_DRIVING);
+ }
+ else //disable HP out
+ {
+ rt5631_write_index_reg(codec,0x56,0x303F);
+ rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_MUTE_UNMUTE_DEPOP|PD_HPAMP_L_ST_UP|PD_HPAMP_R_ST_UP);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(75));
+ rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|PD_HPAMP_L_ST_UP|PD_HPAMP_R_ST_UP);
+ rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,0,PWR_HP_DEPOP_DIS|PWR_HP_AMP_DRIVING);
+ rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_DEPOP2_FOR_HP|PD_HPAMP_L_ST_UP|PD_HPAMP_R_ST_UP);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(80));
+ rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN);
+ rt5631_write_mask(codec,RT5631_PWR_MANAG_ADD3,0,PWR_CHARGE_PUMP|PWR_HP_L_AMP|PWR_HP_R_AMP);
+ }
+
+ rt5631_write(codec,RT5631_SOFT_VOL_CTRL,SoftVol);
+ rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross);
+
+}
+
+static void HP_Mute_Unmute_Depop(struct snd_soc_codec *codec,unsigned int EnableHPOut)
+{
+
+ unsigned int SoftVol,HPZeroCross;
+
+ SoftVol = rt5631_read(codec, RT5631_SOFT_VOL_CTRL);
+ rt5631_write(codec,RT5631_SOFT_VOL_CTRL,0);
+ HPZeroCross=rt5631_read(codec, RT5631_INT_ST_IRQ_CTRL_2);
+ rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross&0xf7ff); //disable Zero Cross of HP
+
+ if(EnableHPOut) //unmute HP out
+ {
+ schedule_timeout_uninterruptible(msecs_to_jiffies(10));
+ rt5631_write_index_reg(codec,0x56,0x302f);
+ rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_MUTE_UNMUTE_DEPOP|EN_HP_R_M_UN_MUTE_DEPOP|EN_HP_L_M_UN_MUTE_DEPOP);
+ rt5631_write_mask(codec,RT5631_HP_OUT_VOL,0x0000,0x8080);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(160));
+
+ }
+ else //mute HP out
+ {
+ rt5631_write_index_reg(codec,0x56,0x302f);
+ rt5631_write(codec,RT5631_DEPOP_FUN_CTRL_1,POW_ON_SOFT_GEN|EN_MUTE_UNMUTE_DEPOP|EN_HP_R_M_UN_MUTE_DEPOP|EN_HP_L_M_UN_MUTE_DEPOP);
+ rt5631_write_mask(codec,RT5631_HP_OUT_VOL,0x8080,0x8080);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(150));
+ }
+
+ rt5631_write(codec,RT5631_SOFT_VOL_CTRL,SoftVol);
+ rt5631_write(codec,RT5631_INT_ST_IRQ_CTRL_2,HPZeroCross);
+
+}
+
+static int open_hp_end_widgets(struct snd_soc_codec *codec)
+{
+ /*need to be fixed*/
+ /*
+ *
+ *open hp last widget, e.g. power, switch
+ */
+
+ HP_Mute_Unmute_Depop(codec,1);
+
+ return 0;
+}
+
+static int close_hp_end_widgets(struct snd_soc_codec *codec)
+{
+ /*need to be fixed*/
+ /*
+ *
+ *close hp last widget, e.g. power, switch
+ */
+
+ HP_Mute_Unmute_Depop(codec,0);
+
+ return 0;
+}
+static int hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int l, r;
+ static unsigned int hp_out_enable=0;
+
+ l = (rt5631_read(codec, RT5631_PWR_MANAG_ADD4) & (0x01 << 11)) >> 11;
+ r = (rt5631_read(codec, RT5631_PWR_MANAG_ADD4) & (0x01 << 10)) >> 10;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMD:
+ printk("hp_event --SND_SOC_DAPM_PRE_PMD\n");
+ if ((l && r)&&(hp_out_enable))
+ {
+ close_hp_end_widgets(codec);
+ hp_depop2(codec,0);
+ hp_out_enable=0;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ printk("hp_event --SND_SOC_DAPM_POST_PMU\n");
+ if ((l && r)&&(!hp_out_enable))
+ {
+ hp_depop2(codec,1);
+ open_hp_end_widgets(codec);
+ hp_out_enable=1;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
+
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_INPUT("AXIL"),
+SND_SOC_DAPM_INPUT("AXIR"),
+SND_SOC_DAPM_INPUT("MONOIN_RXN"),
+SND_SOC_DAPM_INPUT("MONOIN_RXP"),
+
+
+SND_SOC_DAPM_PGA("Mic1 Boost", RT5631_PWR_MANAG_ADD2, 5, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic2 Boost", RT5631_PWR_MANAG_ADD2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("MONOIN_RXP Boost", RT5631_PWR_MANAG_ADD4, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA("MONOIN_RXN Boost", RT5631_PWR_MANAG_ADD4, 6, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("AXIL Boost", RT5631_PWR_MANAG_ADD4, 9, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AXIR Boost", RT5631_PWR_MANAG_ADD4, 8, 0, NULL, 0),
+SND_SOC_DAPM_MIXER("MONO_IN", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("RECMIXL Mixer", RT5631_PWR_MANAG_ADD2, 11, 0,
+ &rt5631_recmixl_mixer_controls[0], ARRAY_SIZE(rt5631_recmixl_mixer_controls)),
+SND_SOC_DAPM_MIXER("RECMIXR Mixer", RT5631_PWR_MANAG_ADD2, 10, 0,
+ &rt5631_recmixr_mixer_controls[0], ARRAY_SIZE(rt5631_recmixr_mixer_controls)),
+
+SND_SOC_DAPM_MIXER("ADC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("Left ADC", "Left ADC HIFI Capture", RT5631_PWR_MANAG_ADD1, 11, 0),
+SND_SOC_DAPM_ADC("Right ADC", "Right ADC HIFI Capture", RT5631_PWR_MANAG_ADD1, 10, 0),
+SND_SOC_DAPM_DAC("Left DAC", "Left DAC HIFI Playback", RT5631_PWR_MANAG_ADD1, 9, 0),
+SND_SOC_DAPM_DAC("Right DAC", "Right DAC HIFI Playback", RT5631_PWR_MANAG_ADD1, 8, 0),
+SND_SOC_DAPM_DAC("Voice DAC", "Voice DAC Mono Playback", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_PGA("Voice DAC Boost", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("SPKMIXL Mixer", RT5631_PWR_MANAG_ADD2, 13, 0,
+ &rt5631_spkmixl_mixer_controls[0], ARRAY_SIZE(rt5631_spkmixl_mixer_controls)),
+SND_SOC_DAPM_MIXER("OUTMIXL Mixer", RT5631_PWR_MANAG_ADD2, 15, 0,
+ &rt5631_outmixl_mixer_controls[0], ARRAY_SIZE(rt5631_outmixl_mixer_controls)),
+SND_SOC_DAPM_MIXER("OUTMIXR Mixer", RT5631_PWR_MANAG_ADD2, 14, 0,
+ &rt5631_outmixr_mixer_controls[0], ARRAY_SIZE(rt5631_outmixr_mixer_controls)),
+SND_SOC_DAPM_MIXER("SPKMIXR Mixer", RT5631_PWR_MANAG_ADD2, 12, 0,
+ &rt5631_spkmixr_mixer_controls[0], ARRAY_SIZE(rt5631_spkmixr_mixer_controls)),
+SND_SOC_DAPM_PGA("Left SPK Vol", RT5631_PWR_MANAG_ADD4, 15, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right SPK Vol", RT5631_PWR_MANAG_ADD4, 14, 0, NULL, 0),
+SND_SOC_DAPM_PGA_E("Left HP Vol", RT5631_PWR_MANAG_ADD4, 11, 0, NULL, 0,
+ hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("Right HP Vol", RT5631_PWR_MANAG_ADD4, 10, 0, NULL, 0,
+ hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA("Left Out Vol", RT5631_PWR_MANAG_ADD4, 13, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Right Out Vol", RT5631_PWR_MANAG_ADD4, 12, 0, NULL, 0),
+
+SND_SOC_DAPM_MIXER("AXO1MIX Mixer", RT5631_PWR_MANAG_ADD3, 11, 0,
+ &rt5631_AXO1MIX_mixer_controls[0], ARRAY_SIZE(rt5631_AXO1MIX_mixer_controls)),
+SND_SOC_DAPM_MIXER("SPOLMIX Mixer", SND_SOC_NOPM, 0, 0,
+ &rt5631_spolmix_mixer_controls[0], ARRAY_SIZE(rt5631_spolmix_mixer_controls)),
+SND_SOC_DAPM_MIXER("MONOMIX Mixer", RT5631_PWR_MANAG_ADD3, 9, 0,
+ &rt5631_monomix_mixer_controls[0], ARRAY_SIZE(rt5631_monomix_mixer_controls)),
+SND_SOC_DAPM_MIXER("SPORMIX Mixer", SND_SOC_NOPM, 0, 0,
+ &rt5631_spormix_mixer_controls[0], ARRAY_SIZE(rt5631_spormix_mixer_controls)),
+SND_SOC_DAPM_MIXER("AXO2MIX Mixer", RT5631_PWR_MANAG_ADD3, 10, 0,
+ &rt5631_AXO2MIX_mixer_controls[0], ARRAY_SIZE(rt5631_AXO2MIX_mixer_controls)),
+
+
+SND_SOC_DAPM_MUX("SPOL Mux", SND_SOC_NOPM, 0, 0, &rt5631_spol_mux_control),
+SND_SOC_DAPM_MUX("SPOR Mux", SND_SOC_NOPM, 0, 0, &rt5631_spor_mux_control),
+SND_SOC_DAPM_MUX("Mono Mux", SND_SOC_NOPM, 0, 0, &rt5631_mono_mux_control),
+
+SND_SOC_DAPM_PGA("Mono Amp", RT5631_PWR_MANAG_ADD3, 7, 0, NULL, 0),
+
+
+SND_SOC_DAPM_PGA_E("SPKL Amp", VIRTUAL_POWER_CONTROL, 0, 0, NULL, 0,
+ spk_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("SPKR Amp", VIRTUAL_POWER_CONTROL, 1, 0, NULL, 0,
+ spk_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_MICBIAS("Mic Bias1", RT5631_PWR_MANAG_ADD2, 3, 0),
+SND_SOC_DAPM_MICBIAS("Mic Bias2", RT5631_PWR_MANAG_ADD2, 2, 0),
+
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+SND_SOC_DAPM_OUTPUT("SPOL"),
+SND_SOC_DAPM_OUTPUT("SPOR"),
+SND_SOC_DAPM_OUTPUT("HPOL"),
+SND_SOC_DAPM_OUTPUT("HPOR"),
+SND_SOC_DAPM_OUTPUT("MONO"),
+
+};
+
+
+static const struct snd_soc_dapm_route audio_map[] = {
+
+ {"Mic1 Boost", NULL, "MIC1"},
+ {"Mic2 Boost", NULL, "MIC2"},
+ {"MONOIN_RXP Boost", NULL, "MONOIN_RXP"},
+ {"MONOIN_RXN Boost", NULL, "MONOIN_RXN"},
+ {"AXIL Boost", NULL, "AXIL"},
+ {"AXIR Boost", NULL, "AXIR"},
+
+ {"MONO_IN", NULL, "MONOIN_RXP Boost"},
+ {"MONO_IN", NULL, "MONOIN_RXN Boost"},
+
+ {"RECMIXL Mixer", "OUTMIXL Capture Switch", "OUTMIXL Mixer"},
+ {"RECMIXL Mixer", "MIC1_BST1 Capture Switch", "Mic1 Boost"},
+ {"RECMIXL Mixer", "AXILVOL Capture Switch", "AXIL Boost"},
+ {"RECMIXL Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+ {"RECMIXR Mixer", "OUTMIXR Capture Switch", "OUTMIXR Mixer"},
+ {"RECMIXR Mixer", "MIC2_BST2 Capture Switch", "Mic2 Boost"},
+ {"RECMIXR Mixer", "AXIRVOL Capture Switch", "AXIR Boost"},
+ {"RECMIXR Mixer", "MONOIN_RX Capture Switch", "MONO_IN"},
+
+ {"ADC Mixer", NULL, "RECMIXL Mixer"},
+ {"ADC Mixer", NULL, "RECMIXR Mixer"},
+ {"Left ADC", NULL, "ADC Mixer"},
+ {"Right ADC", NULL,"ADC Mixer"},
+
+ {"Voice DAC Boost", NULL, "Voice DAC"},
+
+ {"SPKMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+ {"SPKMIXL Mixer", "MIC1_P Playback Switch", "MIC1"},
+ {"SPKMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+ {"SPKMIXL Mixer", "OUTMIXL Playback Switch", "OUTMIXL Mixer"},
+
+ {"SPKMIXR Mixer", "OUTMIXR Playback Switch", "OUTMIXR Mixer"},
+ {"SPKMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+ {"SPKMIXR Mixer", "MIC2_P Playback Switch", "MIC2"},
+ {"SPKMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+
+
+ {"OUTMIXL Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+ {"OUTMIXL Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+ {"OUTMIXL Mixer", "DACL Playback Switch", "Left DAC"},
+ {"OUTMIXL Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+ {"OUTMIXL Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+ {"OUTMIXL Mixer", "MONOIN_RXP Playback Switch", "MONOIN_RXP Boost"},
+ {"OUTMIXL Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+ {"OUTMIXL Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+ {"OUTMIXL Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+ {"OUTMIXR Mixer", "RECMIXL Playback Switch", "RECMIXL Mixer"},
+ {"OUTMIXR Mixer", "RECMIXR Playback Switch", "RECMIXR Mixer"},
+ {"OUTMIXR Mixer", "DACR Playback Switch", "Right DAC"},
+ {"OUTMIXR Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+ {"OUTMIXR Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+ {"OUTMIXR Mixer", "MONOIN_RXN Playback Switch", "MONOIN_RXN Boost"},
+ {"OUTMIXR Mixer", "AXILVOL Playback Switch", "AXIL Boost"},
+ {"OUTMIXR Mixer", "AXIRVOL Playback Switch", "AXIR Boost"},
+ {"OUTMIXR Mixer", "VDAC Playback Switch", "Voice DAC Boost"},
+
+ {"Left SPK Vol", NULL, "SPKMIXL Mixer"},
+ {"Right SPK Vol", NULL, "SPKMIXR Mixer"},
+ {"Left HP Vol", NULL, "OUTMIXL Mixer"},
+ {"Left Out Vol", NULL, "OUTMIXL Mixer"},
+ {"Right Out Vol", NULL, "OUTMIXR Mixer"},
+ {"Right HP Vol", NULL, "OUTMIXR Mixer"},
+
+
+ {"AXO1MIX Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+ {"AXO1MIX Mixer", "OUTVOLL Playback Switch", "Left Out Vol"},
+ {"AXO1MIX Mixer", "OUTVOLR Playback Switch", "Right Out Vol"},
+ {"AXO1MIX Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+
+
+ {"AXO2MIX Mixer", "MIC1_BST1 Playback Switch", "Mic1 Boost"},
+ {"AXO2MIX Mixer", "OUTVOLL Playback Switch", "Left Out Vol"},
+ {"AXO2MIX Mixer", "OUTVOLR Playback Switch", "Right Out Vol"},
+ {"AXO2MIX Mixer", "MIC2_BST2 Playback Switch", "Mic2 Boost"},
+
+
+ {"SPOLMIX Mixer", "SPKVOLL Playback Switch", "Left SPK Vol"},
+ {"SPOLMIX Mixer", "SPKVOLR Playback Switch", "Right SPK Vol"},
+
+ {"SPORMIX Mixer", "SPKVOLL Playback Switch", "Left SPK Vol"},
+ {"SPORMIX Mixer", "SPKVOLR Playback Switch", "Right SPK Vol"},
+
+
+ {"MONOMIX Mixer", "OUTVOLL Playback Switch", "Left Out Vol"},
+ {"MONOMIX Mixer", "OUTVOLR Playback Switch", "Right Out Vol"},
+
+
+
+ {"SPOL Mux", "SPOLMIX", "SPOLMIX Mixer"},
+ {"SPOL Mux", "MONOIN_RX", "MONO_IN"},
+ {"SPOL Mux", "VDAC", "Voice DAC Boost"},
+ {"SPOL Mux", "DACL", "Left DAC"},
+
+ {"SPOR Mux", "SPORMIX", "SPORMIX Mixer"},
+ {"SPOR Mux", "MONOIN_RX", "MONO_IN"},
+ {"SPOR Mux", "VDAC", "Voice DAC Boost"},
+ {"SPOR Mux", "DACR", "Right DAC"},
+
+ {"Mono Mux", "MONOMIX", "MONOMIX Mixer"},
+ {"Mono Mux", "MONOIN_RX", "MONO_IN"},
+ {"Mono Mux", "VDAC", "Voice DAC Boost"},
+
+ {"SPKL Amp", NULL, "SPOL Mux"},
+ {"SPKR Amp", NULL, "SPOR Mux"},
+ {"Mono Amp", NULL, "Mono Mux"},
+
+ {"LOUT", NULL, "AXO1MIX Mixer"},
+ {"ROUT", NULL, "AXO2MIX Mixer"},
+ {"SPOL", NULL, "SPKL Amp"},
+ {"SPOR", NULL, "SPKR Amp"},
+ {"HPOL", NULL, "Left HP Vol"},
+ {"HPOR", NULL, "Right HP Vol"},
+ {"MONO", NULL, "Mono Amp"}
+
+};
+
+static int rt5631_add_widgets(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_new_controls(codec, rt5631_dapm_widgets,
+ ARRAY_SIZE(rt5631_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ snd_soc_dapm_new_widgets(codec);
+
+ return 0;
+}
+
+struct _coeff_div{
+ unsigned int mclk; //pllout or MCLK
+ unsigned int bclk; //master mode
+ unsigned int rate;
+ unsigned int reg_val;
+};
+/*PLL divisors*/
+struct _pll_div {
+ u32 pll_in;
+ u32 pll_out;
+ u16 regvalue;
+};
+
+static const struct _pll_div codec_master_pll_div[] = {
+
+ { 2048000, 8192000, 0x0ea0},
+ { 3686400, 8192000, 0x4e27},
+ { 12000000, 8192000, 0x456b},
+ { 13000000, 8192000, 0x495f},
+ { 13100000, 8192000, 0x0320},
+ { 2048000, 11289600, 0xf637},
+ { 3686400, 11289600, 0x2f22},
+ { 12000000, 11289600, 0x3e2f},
+ { 13000000, 11289600, 0x4d5b},
+ { 13100000, 11289600, 0x363b},
+ { 2048000, 16384000, 0x1ea0},
+ { 3686400, 16384000, 0x9e27},
+ { 12000000, 16384000, 0x452b},
+ { 13000000, 16384000, 0x542f},
+ { 13100000, 16384000, 0x03a0},
+ { 2048000, 16934400, 0xe625},
+ { 3686400, 16934400, 0x9126},
+ { 12000000, 16934400, 0x4d2c},
+ { 13000000, 16934400, 0x742f},
+ { 13100000, 16934400, 0x3c27},
+ { 2048000, 22579200, 0x2aa0},
+ { 3686400, 22579200, 0x2f20},
+ { 12000000, 22579200, 0x7e2f},
+ { 13000000, 22579200, 0x742f},
+ { 13100000, 22579200, 0x3c27},
+ { 2048000, 24576000, 0x2ea0},
+ { 3686400, 24576000, 0xee27},
+ { 12000000, 24576000, 0x2915},
+ { 13000000, 24576000, 0x772e},
+ { 13100000, 24576000, 0x0d20},
+ { 26000000, 24576000, 0x2027},
+ { 26000000, 22579200, 0x392f},
+ { 24576000, 22579200, 0x0921},
+ { 24576000, 24576000, 0x02a0},
+};
+
+static const struct _pll_div codec_slave_pll_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 coeff_div[] = {
+ //sysclk is 256fs
+ { 2048000, 8000 * 32, 8000, 0x1000},
+ { 2048000, 8000 * 64, 8000, 0x0000},
+ { 2822400, 11025 * 32, 11025, 0x1000},
+ { 2822400, 11025 * 64, 11025, 0x0000},
+ { 4096000, 16000 * 32, 16000, 0x1000},
+ { 4096000, 16000 * 64, 16000, 0x0000},
+ { 5644800, 22050 * 32, 22050, 0x1000},
+ { 5644800, 22050 * 64, 22050, 0x0000},
+ { 8192000, 32000 * 32, 32000, 0x1000},
+ { 8192000, 32000 * 64, 32000, 0x0000},
+ {11289600, 44100 * 32, 44100, 0x1000},
+ {11289600, 44100 * 64, 44100, 0x0000},
+ {12288000, 48000 * 32, 48000, 0x1000},
+ {12288000, 48000 * 64, 48000, 0x0000},
+ //sysclk is 512fs
+ { 4096000, 8000 * 32, 8000, 0x3000},
+ { 4096000, 8000 * 64, 8000, 0x2000},
+ { 5644800, 11025 * 32, 11025, 0x3000},
+ { 5644800, 11025 * 64, 11025, 0x2000},
+ { 8192000, 16000 * 32, 16000, 0x3000},
+ { 8192000, 16000 * 64, 16000, 0x2000},
+ {11289600, 22050 * 32, 22050, 0x3000},
+ {11289600, 22050 * 64, 22050, 0x2000},
+ {16384000, 32000 * 32, 32000, 0x3000},
+ {16384000, 32000 * 64, 32000, 0x2000},
+ {22579200, 44100 * 32, 44100, 0x3000},
+ {22579200, 44100 * 64, 44100, 0x2000},
+ {24576000, 48000 * 32, 48000, 0x3000},
+ {24576000, 48000 * 64, 48000, 0x2000},
+ //sysclk is 24.576Mhz or 22.579200Mhz
+ {24576000, 8000 * 32, 8000, 0x7080},
+ {24576000, 8000 * 64, 8000, 0x6080},
+ {24576000, 16000 * 32, 16000, 0x5080},
+ {24576000, 16000 * 64, 16000, 0x4080},
+ {24576000, 24000 * 32, 24000, 0x5000},
+ {24576000, 24000 * 64, 24000, 0x4000},
+ {24576000, 32000 * 32, 32000, 0x3080},
+ {24576000, 32000 * 64, 32000, 0x2080},
+
+ {22579200, 11025 * 32, 11025, 0x7000},
+ {22579200, 11025 * 64, 11025, 0x6000},
+ {22579200, 22050 * 32, 22050, 0x5000},
+ {22579200, 22050 * 64, 22050, 0x4000},
+
+};
+
+
+
+
+static int get_coeff(int mclk, int rate, int timesofbclk)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if ((coeff_div[i].mclk == mclk)
+ && (coeff_div[i].rate == rate)
+ && ((coeff_div[i].bclk / coeff_div[i].rate) == timesofbclk))
+ return i;
+ }
+
+ return -1;
+}
+
+static int get_coeff_in_slave_mode(int mclk, int rate)
+{
+ return get_coeff(mclk, rate, timesofbclk);
+}
+
+static int get_coeff_in_master_mode(int mclk, int rate, int bclk)
+{
+ return get_coeff(mclk, rate, (bclk / rate));
+}
+static void rt5631_set_dmic_params(struct snd_soc_codec *codec, struct snd_pcm_hw_params *params)
+{
+// struct rt5631_priv *rt5631 = codec->private_data;
+
+ unsigned int rate;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ rt5631_write_mask(codec, RT5631_GPIO_CTRL, GPIO_PIN_FUN_SEL_GPIO_DIMC|GPIO_DMIC_FUN_SEL_DIMC
+ , GPIO_PIN_FUN_SEL_MASK|GPIO_DMIC_FUN_SEL_MASK);
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_ENA, DMIC_ENA_MASK);
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL,DMIC_L_CH_LATCH_FALLING|DMIC_R_CH_LATCH_RISING
+ ,DMIC_L_CH_LATCH_MASK|DMIC_R_CH_LATCH_MASK);
+
+ rate = params_rate(params);
+ switch (rate) {
+ case 44100:
+ case 48000:
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_CLK_CTRL_TO_32FS, DMIC_CLK_CTRL_MASK);
+ break;
+ case 32000:
+ case 22050:
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_CLK_CTRL_TO_64FS, DMIC_CLK_CTRL_MASK);
+ break;
+ case 16000:
+ case 11025:
+ case 8000:
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL, DMIC_CLK_CTRL_TO_128FS, DMIC_CLK_CTRL_MASK);
+ break;
+ }
+
+ rt5631_write_mask(codec, RT5631_DIG_MIC_CTRL,
+ DMIC_L_CH_UNMUTE | DMIC_R_CH_UNMUTE, DMIC_L_CH_MUTE_MASK | DMIC_R_CH_MUTE_MASK);
+
+}
+
+static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+// struct snd_soc_codec *codec = dai->codec;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct rt5631_priv *rt5631 = codec->private_data;
+ int stream = substream->stream;
+ unsigned int iface = 0;
+ int rate = params_rate(params);
+ int coeff = 0;
+ unsigned int CodecRegData;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+
+ if (!rt5631->master)
+ coeff = get_coeff_in_slave_mode(rt5631->sysclk, rate);
+ else
+ coeff = get_coeff_in_master_mode(rt5631->sysclk, rate, rate * timesofbclk);
+
+ if (coeff < 0) {
+ printk(KERN_ERR "%s get_coeff err!\n", __func__);
+ // return -EINVAL;
+ }
+
+ switch (params_format(params))
+ {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ iface |= 0x0004;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iface |= 0x0008;
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ iface |= 0x000c;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (rt5631->dmic_used_flag) //use Digital Mic
+ rt5631_set_dmic_params(codec, params);
+ else //use Analog Mic
+ {
+ CodecRegData=rt5631_read(codec,RT5631_ADC_REC_MIXER);
+ if((CodecRegData&0x4040)==0) //use stereo mic from mic1&mic2,no copy ADC channel
+ {
+ rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x0000, 0xc000);
+ }
+ else if((CodecRegData&0x4000)==0) //use mic1,copy ADC left to right
+ {
+ rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x4000, 0xc000);
+ }
+ else if((CodecRegData&0x0040)==0)//use mic2,copy ADC right to left
+ {
+ rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x8000, 0xc000);
+ }
+ else
+ {
+ rt5631_write_mask(codec, RT5631_INT_ST_IRQ_CTRL_2, 0x0000, 0xc000);
+ }
+
+ }
+ }
+
+ rt5631_write_mask(codec, RT5631_SDP_CTRL, iface, SDP_I2S_DL_MASK);
+
+ if(coeff>=0)
+ rt5631_write(codec, RT5631_STEREO_AD_DA_CLK_CTRL, coeff_div[coeff].reg_val);
+
+
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x80e0, 0x80e0);
+
+return 0;
+}
+
+static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct rt5631_priv *rt5631 = codec->private_data;
+ u16 iface = 0;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ rt5631->master = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ iface |= (0x0001 << 15);
+ rt5631->master = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ 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;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= (0x0001 << 7);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rt5631_write(codec, RT5631_SDP_CTRL, iface);
+
+ return 0;
+}
+static int rt5631_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct rt5631_priv *rt5631 = codec->private_data;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
+ rt5631->sysclk = freq;
+ return 0;
+ }
+
+ printk("unsupported sysclk freq %u for audio i2s\n", freq);
+ printk("Set sysclk to 24.576Mhz by default\n");
+
+ rt5631->sysclk = 24576000;
+ return 0;
+ //return -EINVAL;
+}
+
+static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai,
+ int pll_id, unsigned int freq_in, unsigned int freq_out)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct rt5631_priv *rt5631 = codec->private_data;
+ int i;
+ int ret = -EINVAL;
+
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+// rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2, 0, PWR_PLL);
+
+ if (!freq_in || !freq_out)
+ return 0;
+
+ if (rt5631->master) {
+ for (i = 0; i < ARRAY_SIZE(codec_master_pll_div); i ++) {
+
+ if ((freq_in == codec_master_pll_div[i].pll_in) && (freq_out == codec_master_pll_div[i].pll_out)) {
+
+ rt5631_write(codec, RT5631_PLL_CTRL, codec_master_pll_div[i].regvalue);
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2, PWR_PLL, PWR_PLL);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+ rt5631_write(codec, RT5631_GLOBAL_CLK_CTRL, 0x4000);
+ ret = 0;
+
+ }
+
+ }
+ } else {
+
+ for (i = 0; i < ARRAY_SIZE(codec_slave_pll_div); i ++) {
+
+ if ((freq_in == codec_slave_pll_div[i].pll_in) && (freq_out == codec_slave_pll_div[i].pll_out)) {
+
+ rt5631_write(codec, RT5631_PLL_CTRL, codec_slave_pll_div[i].regvalue);
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2, PWR_PLL, PWR_PLL);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(20));
+ rt5631_write(codec, RT5631_GLOBAL_CLK_CTRL, 0x5000);
+ ret = 0;
+
+ }
+
+ }
+ }
+
+ return 0;
+}
+
+static void rt5631_hifi_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai)
+{
+
+}
+
+#define RT5631_STEREO_RATES (SNDRV_PCM_RATE_8000_48000)
+#define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+ SNDRV_PCM_FMTBIT_S8)
+
+struct snd_soc_dai_ops rt5631_ops = {
+ .hw_params = rt5631_hifi_pcm_params,
+ .set_fmt = rt5631_hifi_codec_set_dai_fmt,
+ .set_sysclk = rt5631_hifi_codec_set_dai_sysclk,
+ .set_pll = rt5631_codec_set_dai_pll,
+ .shutdown = rt5631_hifi_shutdown,
+};
+
+struct snd_soc_dai rt5631_dai[] = {
+ {
+ .name = "RT5631 HIFI",
+ .id = 1,
+ .playback = {
+ .stream_name = "HIFI Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5631_STEREO_RATES,
+ .formats = RT5631_FORMAT,
+ } ,
+ .capture = {
+ .stream_name = "HIFI Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = RT5631_STEREO_RATES,
+ .formats = RT5631_FORMAT,
+ },
+ .ops =&rt5631_ops,
+ },
+
+ {
+ .name = "RT5631 Reserved",
+ .id = 2,
+ }
+};
+
+EXPORT_SYMBOL_GPL(rt5631_dai);
+
+static int rt5631_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+{
+ printk(KERN_DEBUG "enter %s\n", __func__);
+
+ printk("rt5631_set_bias_level=%d\n",level);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3,PWR_VREF|PWR_MAIN_BIAS, PWR_VREF|PWR_MAIN_BIAS);
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD2,0x000c, 0x000c);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+
+ break;
+ case SND_SOC_BIAS_OFF:
+ rt5631_write_mask(codec, RT5631_SPK_OUT_VOL ,0x8080, 0x8080);
+ rt5631_write_mask(codec, RT5631_HP_OUT_VOL ,0x8080, 0x8080);
+ rt5631_write(codec, RT5631_PWR_MANAG_ADD1, 0x0000);
+ rt5631_write(codec, RT5631_PWR_MANAG_ADD2, 0x0000);
+ rt5631_write(codec, RT5631_PWR_MANAG_ADD3, 0x0000);
+ rt5631_write(codec, RT5631_PWR_MANAG_ADD4, 0x0000);
+ break;
+ }
+
+ codec->bias_level = level;
+ return 0;
+}
+
+static int rt5631_init(struct snd_soc_device *socdev)
+{
+ struct snd_soc_codec *codec = socdev->card->codec;
+ int ret;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ codec->name = "RT5631";
+ codec->owner = THIS_MODULE;
+ codec->read = rt5631_read;
+ codec->write = rt5631_write;
+ codec->set_bias_level = rt5631_set_bias_level;
+ codec->dai = rt5631_dai;
+ codec->num_dai = 2;
+ codec->reg_cache_size = ARRAY_SIZE(rt5631_reg);
+ codec->reg_cache_step = 1;
+ codec->reg_cache = kmemdup(rt5631_reg, sizeof(rt5631_reg), GFP_KERNEL);
+
+ if (codec->reg_cache == NULL)
+ return -ENOMEM;
+
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ printk(KERN_ERR "rt5631: failed to create pcms\n");
+ goto pcm_err;
+ }
+
+ rt5631_reset(codec);
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3,PWR_VREF|PWR_MAIN_BIAS, PWR_VREF|PWR_MAIN_BIAS);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(110));
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3, PWR_FAST_VREF_CTRL, PWR_FAST_VREF_CTRL);
+ codec->bias_level = SND_SOC_BIAS_STANDBY;
+ schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(100));
+
+ rt5631_reg_init(codec);
+ rt5631_add_controls(codec);
+ rt5631_add_widgets(codec);
+ ret = snd_soc_init_card(socdev);
+ if (ret < 0) {
+ printk(KERN_ERR "rt5631: failed to register card!\n");
+ goto card_err;
+ }
+ printk(KERN_INFO "rt5631 initial ok!\n");
+ return 0;
+
+
+card_err:
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+pcm_err:
+ kfree(codec->reg_cache);
+ codec->reg_cache = NULL;
+ return ret;
+}
+
+
+static const struct i2c_device_id rt5631_i2c_id[] = {
+ {"rt5631", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
+
+static int rt5631_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct snd_soc_device *socdev = rt5631_socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ int ret;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ i2c_set_clientdata(i2c, codec);
+ codec->control_data = i2c;
+
+ ret = rt5631_init(socdev);
+ if (ret < 0)
+ pr_err("failed to initialise rt5631!\n");
+
+ return ret;
+
+
+}
+
+static int rt5631_i2c_remove(struct i2c_client *client)
+{
+ struct snd_soc_codec *codec = i2c_get_clientdata(client);
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ kfree(codec->reg_cache);
+ return 0;
+}
+
+struct i2c_driver rt5631_i2c_driver = {
+ .driver = {
+ .name = "RT5631 I2C Codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5631_i2c_probe,
+ .remove = rt5631_i2c_remove,
+ .id_table = rt5631_i2c_id,
+};
+
+
+static int rt5631_add_i2c_device(struct platform_device *pdev,
+ const struct rt5631_setup_data *setup)
+{
+#if 0
+ struct i2c_board_info info;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+#endif
+ int ret;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ ret = i2c_add_driver(&rt5631_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;
+ info.platform_data = pdev;
+ strlcpy(info.type, "rt5631", 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;
+ }
+
+ 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:
+ i2c_del_driver(&rt5631_i2c_driver);
+ return -ENODEV;
+#endif
+
+}
+
+static void rt5631_work(struct work_struct *work)
+{
+ struct snd_soc_codec *codec = container_of(work, struct snd_soc_codec, delayed_work.work);
+
+ rt5631_set_bias_level(codec, codec->bias_level);
+}
+
+static int rt5631_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct rt5631_setup_data *setup;
+ struct snd_soc_codec *codec;
+ struct rt5631_priv *rt5631;
+ int ret = 0;
+
+ printk(KERN_DEBUG "enter %s\n", __func__);
+
+ pr_info("RT5631 Audio Codec %s", RT5631_VERSION);
+
+ if(socdev->codec_data)
+ {
+ setup = socdev->codec_data;
+ }
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL) {
+ return -ENOMEM;
+ }
+
+
+ rt5631 = kzalloc(sizeof(struct rt5631_priv), GFP_KERNEL);
+ if (rt5631 == NULL) {
+ ret = -ENOMEM;
+ goto priv_err;
+ }
+ codec->private_data = rt5631;
+ socdev->card->codec = codec;
+ mutex_init(&codec->mutex);
+ rt5631_socdev = socdev;
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+ INIT_DELAYED_WORK(&codec->delayed_work, rt5631_work);
+
+#if 0
+ if (setup->i2c_address) {
+ codec->hw_write = (hw_write_t)i2c_master_send;
+
+ ret = rt5631_add_i2c_device(pdev, setup);
+ }
+#else
+ //probe i2c device driver
+ {
+ codec->hw_write = (hw_write_t)i2c_master_send;
+ // codec->hw_read = (hw_read_t)i2c_master_recv;
+ ret = rt5631_add_i2c_device(pdev, setup);
+ }
+#endif
+
+ if (ret != 0) {
+ goto i2c_device_err;
+ }
+ return 0;
+
+i2c_device_err:
+ kfree(rt5631);
+ socdev->card->codec->private_data = NULL;
+
+priv_err:
+ kfree(codec);
+ socdev->card->codec = NULL;
+
+ return ret;
+}
+
+static int run_delayed_work(struct delayed_work *dwork)
+{
+ int ret;
+
+ ret = cancel_delayed_work(dwork);
+
+ if (ret) {
+ schedule_delayed_work(dwork, 0);
+ flush_scheduled_work();
+ }
+
+ return ret;
+}
+
+static int rt5631_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)
+ rt5631_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(&rt5631_i2c_driver);
+ kfree(codec->private_data);
+ kfree(codec);
+
+ return 0;
+
+}
+
+static int rt5631_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;
+
+ rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int rt5631_resume(struct platform_device *pdev)
+{
+ 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
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3,PWR_VREF|PWR_MAIN_BIAS, PWR_VREF|PWR_MAIN_BIAS);
+ schedule_timeout_uninterruptible(msecs_to_jiffies(110));
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD3, PWR_FAST_VREF_CTRL, PWR_FAST_VREF_CTRL);
+ rt5631_reg_init(codec);
+ rt5631_write_mask(codec, RT5631_PWR_MANAG_ADD1, 0x80e0, 0x80e0);
+#else
+ printk(KERN_DEBUG "enter %s\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(rt5631_reg); i++) {
+ if (i == RT5631_RESET)
+ continue;
+ data[0] = i << 1;
+ data[1] = (0xff00 & cache[i]) >> 8;
+ data[2] = 0x00ff & cache[i];
+ codec->hw_write(codec->control_data, data, 2);
+ }
+
+ rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+#endif
+
+ if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+ rt5631_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));
+ }
+
+ return 0;
+
+
+}
+
+struct snd_soc_codec_device soc_codec_dev_rt5631 =
+{
+ .probe = rt5631_probe,
+ .remove = rt5631_remove,
+ .suspend = rt5631_suspend,
+ .resume = rt5631_resume,
+};
+
+EXPORT_SYMBOL_GPL(soc_codec_dev_rt5631);
+
+static int __init rt5631_modinit(void)
+{
+ return snd_soc_register_dais(rt5631_dai, ARRAY_SIZE(rt5631_dai));
+}
+
+static void __exit rt5631_modexit(void)
+{
+ snd_soc_unregister_dais(rt5631_dai, ARRAY_SIZE(rt5631_dai));
+}
+
+module_init(rt5631_modinit);
+module_exit(rt5631_modexit);
+MODULE_DESCRIPTION("ASoC RT5631 driver");
+MODULE_AUTHOR("flove");
+MODULE_LICENSE("GPL");
--- /dev/null
+#ifndef __RTCODEC5631_H__\r
+#define __RTCODEC5631_H__\r
+\r
+\r
+#define RT5631_RESET 0X00 //RESET CODEC TO DEFAULT\r
+#define RT5631_SPK_OUT_VOL 0X02 //SPEAKER OUT VOLUME\r
+#define RT5631_HP_OUT_VOL 0X04 //HEADPHONE OUTPUT VOLUME\r
+#define RT5631_MONO_AXO_1_2_VOL 0X06 //MONO/AUXOUT OUTPUT VOLUME\r
+#define RT5631_AUX_IN_VOL 0X0A //AUX IN VOLUME\r
+#define RT5631_STEREO_DAC_VOL_1 0X0C //STEREO DAC VOLUME 1\r
+#define RT5631_MIC_CTRL_1 0X0E //MICROPHONE CONTROL 1\r
+#define RT5631_STEREO_DAC_VOL_2 0X10 //STEREO DAC VOLUME 2\r
+#define RT5631_ADC_CTRL_1 0X12 //STEREO ADC CONTROL 1\r
+#define RT5631_ADC_REC_MIXER 0X14 //ADC RECORD MIXER CONTROL\r
+#define RT5631_ADC_CTRL_2 0X16 //STEREO ADC CONTROL 2\r
+#define RT5631_OUTMIXER_L_CTRL 0X1A //LEFT OUTPUT MIXER CONTROL\r
+#define RT5631_OUTMIXER_R_CTRL 0X1C //RIGHT OUTPUT MIXER CONTROL\r
+#define RT5631_AXO1MIXER_CTRL 0X1E //LOUT MIXER CONTROL\r
+#define RT5631_AXO2MIXER_CTRL 0X20 //LOUT MIXER CONTROL\r
+#define RT5631_MIC_CTRL_2 0X22 //MICROPHONE CONTROL 2\r
+#define RT5631_DIG_MIC_CTRL 0X24 //DIGITAL MICROPHONE CONTROL\r
+#define RT5631_MONO_INPUT_VOL 0X26 //MONO INPUT VOLUME\r
+#define RT5631_SPK_MIXER_CTRL 0X28 //SPEAKER MIXER CONTROL\r
+#define RT5631_SPK_MONO_OUT_CTRL 0X2A //SPEAKER/MONO OUTPUT CONTROL\r
+#define RT5631_SPK_MONO_HP_OUT_CTRL 0X2C //SPEAKER/MONO/HP OUTPUT CONTROL\r
+#define RT5631_SDP_CTRL 0X34 //STEREO I2S SERIAL DATA PORT CONTROL\r
+#define RT5631_STEREO_AD_DA_CLK_CTRL 0X38 //STEREO AD/DA CLOCK CONTROL\r
+#define RT5631_PWR_MANAG_ADD1 0X3A //POWER MANAGMENT ADDITION 1\r
+#define RT5631_PWR_MANAG_ADD2 0X3B //POWER MANAGMENT ADDITION 2\r
+#define RT5631_PWR_MANAG_ADD3 0X3C //POWER MANAGMENT ADDITION 3\r
+#define RT5631_PWR_MANAG_ADD4 0X3E //POWER MANAGMENT ADDITION 4\r
+#define RT5631_GEN_PUR_CTRL_REG 0X40 //GENERAL PURPOSE CONTROL REGISTER\r
+#define RT5631_GLOBAL_CLK_CTRL 0X42 //GLOBAL CLOCK CONTROL\r
+#define RT5631_PLL_CTRL 0X44 //PLL CONTROL\r
+#define RT5631_INT_ST_IRQ_CTRL_1 0X48 //INTERNAL STATUS AND IRQ CONTROL 1\r
+#define RT5631_INT_ST_IRQ_CTRL_2 0X4A //INTERNAL STATUS AND IRQ CONTROL 2\r
+#define RT5631_GPIO_CTRL 0X4C //GPIO OUTPUT CONTROL\r
+#define RT5631_MISC_CTRL 0X52 //MISC CONTROL\r
+#define RT5631_DEPOP_FUN_CTRL_1 0X54 //DE-POP FUNCTION CONTROL 1\r
+#define RT5631_DEPOP_FUN_CTRL_2 0X56 //DE-POP FUNCTION CONTROL 2\r
+#define RT5631_JACK_DET_CTRL 0X5A //JACK DETECT CONTROL REGISTER\r
+#define RT5631_SOFT_VOL_CTRL 0X5C //SOFT VOLUME CONTROL\r
+#define RT5631_ALC_CTRL_1 0X64 //ALC CONTROL 1\r
+#define RT5631_ALC_CTRL_2 0X65 //ALC CONTROL 2\r
+#define RT5631_ALC_CTRL_3 0X66 //ALC CONTROL 3\r
+#define RT5631_PSEUDO_SPATL_CTRL 0X68 //PSEUDO STEREO AND SPATIAL EFFECT CONTROL\r
+#define RT5631_INDEX_ADD 0X6A //INDEX ADDRESS\r
+#define RT5631_INDEX_DATA 0X6C //INDEX DATA\r
+#define RT5631_EQ_CTRL 0X6E //EQ CONTROL \r
+#define RT5631_VENDOR_ID1 0x7C //VENDOR ID1\r
+#define RT5631_VENDOR_ID2 0x7E //VENDOR ID2\r
+\r
+\r
+//global definition\r
+#define RT_L_MUTE (0x1<<15) //MUTE LEFT CONTROL BIT\r
+#define RT_R_MUTE (0x1<<7) //MUTE RIGHT CONTROL BIT\r
+\r
+//Speaker Output Control(0x02)\r
+#define SPK_L_VOL_SEL_MASK (0x1<<14) //Speaker left channel volume input select MASK\r
+#define SPK_L_VOL_SEL_VMID (0x0<<14) //Speaker left channel volume input select VMID\r
+#define SPK_L_VOL_SEL_SPKMIX_L (0x1<<14) //Speaker left channel volume input select SPKMIXER LEFT\r
+#define SPK_R_VOL_SEL_MASK (0x1<< 6) //Speaker right channel volume input select MASK\r
+#define SPK_R_VOL_SEL_VMID (0x0<< 6) //Speaker right channel volume input select VMID\r
+#define SPK_R_VOL_SEL_SPKMIX_R (0x1<< 6) //Speaker right channel volume input select SPKMIXER RIGHT\r
+\r
+//Headphone Output Control(0x04)\r
+#define HP_L_VOL_SEL_MASK (0x1<<14) //HP left channel volume input select MASK\r
+#define HP_L_VOL_SEL_VMID (0x0<<14) //HP left channel volume input select VMID\r
+#define HP_L_VOL_SEL_OUTMIX_L (0x1<<14) //HP left channel volume input select OUTMIXER LEFT\r
+#define HP_R_VOL_SEL_MASK (0x1<< 6) //HP right channel volume input select MASK\r
+#define HP_R_VOL_SEL_VMID (0x0<< 6) //HP right channel volume input select VMID\r
+#define HP_R_VOL_SEL_OUTMIX_R (0x1<< 6) //HP right channel volume input select OUTMIXER RIGHT \r
+\r
+\r
+//Output Control for AUXOUT/MONO(0x06)\r
+#define AUXOUT_1_VOL_SEL_MASK (0x1<<14) //LOUT channel volume input select MASK\r
+#define AUXOUT_1_VOL_SEL_VMID (0x0<<14) //LOUT channel volume input select VMID\r
+#define AUXOUT_1_VOL_SEL_OUTMIX_L (0x1<<14) //LOUT channel volume input select OUTMIXER LEFT\r
+#define MUTE_MONO (0x1<<13) //Mute Mono control\r
+#define AUXOUT_2_VOL_SEL_MASK (0x1<< 6) //ROUT channel volume input select MASK\r
+#define AUXOUT_2_VOL_SEL_VMID (0x0<< 6) //ROUT channel volume input select VMID\r
+#define AUXOUT_2_VOL_SEL_OUTMIX_R (0x1<< 6) //ROUT channel volume input select OUTMIXER RIGHT \r
+\r
+\r
+//Microphone Input Control 1(0x0E)\r
+#define MIC1_DIFF_INPUT_CTRL (0x1<<15) //MIC1 different input control\r
+#define MIC2_DIFF_INPUT_CTRL (0x1<< 7) //MIC2 different input control\r
+\r
+\r
+//ADC Recording Mixer Control(0x14)\r
+#define M_OUTMIXER_L_TO_RECMIXER_L (0x1<<15) //Mute left OUTMIXER to left RECMIXER\r
+#define M_MIC1_TO_RECMIXER_L (0x1<<14) //Mute mic1 to left RECMIXER\r
+#define M_AXIL_TO_RECMIXER_L (0x1<<13) //Mute AXIL to left RECMIXER\r
+#define M_MONO_IN_TO_RECMIXER_L (0x1<<12) //Mute BB_RX to left RECMIXER\r
+#define M_OUTMIXER_R_TO_RECMIXER_R (0x1<< 7) //Mute right OUTMIXER to right RECMIXER\r
+#define M_MIC2_TO_RECMIXER_R (0x1<< 6) //Mute mic2 to right RECMIXER\r
+#define M_AXIR_TO_RECMIXER_R (0x1<< 5) //Mute AXIR to right RECMIXER\r
+#define M_MONO_IN_TO_RECMIXER_R (0x1<< 4) //Mute BB_RX to right RECMIXER\r
+\r
+//Left Output Mixer Control(0x1A)\r
+#define M_RECMIXER_L_TO_OUTMIXER_L (0x1<<15) //Mute Left RecMixer to Left OutMixer \r
+#define M_RECMIXER_R_TO_OUTMIXER_L (0x1<<14) //Mute Right RecMixer to Left OutMixer \r
+#define M_DAC_L_TO_OUTMIXER_L (0x1<<13) //Mute Left Dac to Left OutMixer \r
+#define M_MIC1_TO_OUTMIXER_L (0x1<<12) //Mute Mic1 to Left OutMixer \r
+#define M_MIC2_TO_OUTMIXER_L (0x1<<11) //Mute Mic2 to Left OutMixer \r
+#define M_MONO_IN_P_TO_OUTMIXER_L (0x1<<10) //Mute MONO IN positive to Left OutMixer \r
+#define M_AXIL_TO_OUTMIXER_L (0x1<< 9) //Mute AXIL to Left OutMixer \r
+#define M_AXIR_TO_OUTMIXER_L (0x1<< 8) //Mute AXIR to Left OutMixer \r
+\r
+\r
+//Right Output Mixer Control(0x1C)\r
+#define M_RECMIXER_L_TO_OUTMIXER_R (0x1<<15) //Mute Left RecMixer to Right OutMixer \r
+#define M_RECMIXER_R_TO_OUTMIXER_R (0x1<<14) //Mute Right RecMixer to Right OutMixer \r
+#define M_DAC_R_TO_OUTMIXER_R (0x1<<13) //Mute Left Dac to Right OutMixer \r
+#define M_MIC1_TO_OUTMIXER_R (0x1<<12) //Mute Mic1 to Right OutMixer \r
+#define M_MIC2_TO_OUTMIXER_R (0x1<<11) //Mute Mic2 to Right OutMixer \r
+#define M_MONO_IN_N_TO_OUTMIXER_R (0x1<<10) //Mute MONO IN Negative to Right OutMixer \r
+#define M_AXIL_TO_OUTMIXER_R (0x1<< 9) //Mute AXIL to Right OutMixer \r
+#define M_AXIR_TO_OUTMIXER_R (0x1<< 8) //Mute AXIR to Right OutMixer \r
+\r
+\r
+//Lout Mixer Control(0x1E)\r
+#define M_MIC1_TO_AXO1MIXER (0x1<<15) //Mute MIC1 to LOUT Mixer\r
+#define M_MIC2_TO_AXO1MIXER (0x1<<11) //Mute MIC2 to LOUT Mixer\r
+#define M_OUTMIXER_L_TO_AXO1MIXER (0x1<< 7) //Mute Left Output mixer to LOUT Mixer\r
+#define M_OUTMIXER_R_TO_AXO1MIXER (0x1<< 6) //Mute Right Output mixer to LOUT Mixer\r
+\r
+\r
+//Rout Mixer Control(0x20)\r
+#define M_MIC1_TO_AXO2MIXER (0x1<<15) //Mute MIC1 to ROUT Mixer\r
+#define M_MIC2_TO_AXO2MIXER (0x1<<11) //Mute MIC2 to ROUT Mixer\r
+#define M_OUTMIXER_L_TO_AXO2MIXER (0x1<< 7) //Mute Left Output mixer to ROUT Mixer\r
+#define M_OUTMIXER_R_TO_AXO2MIXER (0x1<< 6) //Mute Right Output mixer to ROUT Mixer\r
+\r
+//Micphone Input Control 2(0x22)\r
+#define MIC_BIAS_90_PRECNET_AVDD 1\r
+#define MIC_BIAS_75_PRECNET_AVDD 2\r
+\r
+#define MIC1_BOOST_CTRL_MASK (0xf<<12)\r
+#define MIC1_BOOST_CTRL_BYPASS (0x0<<12)\r
+#define MIC1_BOOST_CTRL_20DB (0x1<<12)\r
+#define MIC1_BOOST_CTRL_24DB (0x2<<12)\r
+#define MIC1_BOOST_CTRL_30DB (0x3<<12)\r
+#define MIC1_BOOST_CTRL_35DB (0x4<<12)\r
+#define MIC1_BOOST_CTRL_40DB (0x5<<12)\r
+#define MIC1_BOOST_CTRL_34DB (0x6<<12)\r
+#define MIC1_BOOST_CTRL_50DB (0x7<<12)\r
+#define MIC1_BOOST_CTRL_52DB (0x8<<12)\r
+\r
+#define MIC2_BOOST_CTRL_MASK (0xf<< 8)\r
+#define MIC2_BOOST_CTRL_BYPASS (0x0<< 8)\r
+#define MIC2_BOOST_CTRL_20DB (0x1<< 8)\r
+#define MIC2_BOOST_CTRL_24DB (0x2<< 8)\r
+#define MIC2_BOOST_CTRL_30DB (0x3<< 8)\r
+#define MIC2_BOOST_CTRL_35DB (0x4<< 8)\r
+#define MIC2_BOOST_CTRL_40DB (0x5<< 8)\r
+#define MIC2_BOOST_CTRL_34DB (0x6<< 8)\r
+#define MIC2_BOOST_CTRL_50DB (0x7<< 8)\r
+#define MIC2_BOOST_CTRL_52DB (0x8<< 8)\r
+\r
+#define MICBIAS1_VOLT_CTRL_MASK (0x1<< 7)\r
+#define MICBIAS1_VOLT_CTRL_90P (0x0<< 7)\r
+#define MICBIAS1_VOLT_CTRL_75P (0x1<< 7)\r
+\r
+#define MICBIAS1_S_C_DET_MASK (0x1<< 6)\r
+#define MICBIAS1_S_C_DET_DIS (0x0<< 6)\r
+#define MICBIAS1_S_C_DET_ENA (0x1<< 6)\r
+\r
+#define MICBIAS1_SHORT_CURR_DET_MASK (0x3<< 4)\r
+#define MICBIAS1_SHORT_CURR_DET_600UA (0x0<< 4)\r
+#define MICBIAS1_SHORT_CURR_DET_1500UA (0x1<< 4)\r
+#define MICBIAS1_SHORT_CURR_DET_2000UA (0x2<< 4)\r
+\r
+#define MICBIAS2_VOLT_CTRL_MASK (0x1<< 3)\r
+#define MICBIAS2_VOLT_CTRL_90P (0x0<< 3)\r
+#define MICBIAS2_VOLT_CTRL_75P (0x1<< 3)\r
+\r
+#define MICBIAS2_S_C_DET_MASK (0x1<< 2)\r
+#define MICBIAS2_S_C_DET_DIS (0x0<< 2)\r
+#define MICBIAS2_S_C_DET_ENA (0x1<< 2)\r
+\r
+#define MICBIAS2_SHORT_CURR_DET_MASK (0x3)\r
+#define MICBIAS2_SHORT_CURR_DET_600UA (0x0)\r
+#define MICBIAS2_SHORT_CURR_DET_1500UA (0x1)\r
+#define MICBIAS2_SHORT_CURR_DET_2000UA (0x2)\r
+\r
+\r
+//Digital Microphone Control(0x24)\r
+#define DMIC_ENA_MASK (0x1<<15) \r
+#define DMIC_ENA (0x1<<15) //use DMIC to ADC Digital filter\r
+#define DMIC_DIS (0x0<<15) //use ADC mixer to ADC Digital filter\r
+\r
+#define DMIC_L_CH_MUTE_MASK (0x1<<13)\r
+#define DMIC_L_CH_UNMUTE (0x0<<13)\r
+#define DMIC_L_CH_MUTE (0x1<<13)\r
+\r
+#define DMIC_R_CH_MUTE_MASK (0x1<<12)\r
+#define DMIC_R_CH_UNMUTE (0x0<<12)\r
+#define DMIC_R_CH_MUTE (0x1<<12)\r
+\r
+#define DMIC_L_CH_LATCH_MASK (0x1<< 9)\r
+#define DMIC_L_CH_LATCH_RISING (0x1<< 9)\r
+#define DMIC_L_CH_LATCH_FALLING (0x0<< 9)\r
+\r
+#define DMIC_R_CH_LATCH_MASK (0x1<< 8)\r
+#define DMIC_R_CH_LATCH_RISING (0x1<< 8)\r
+#define DMIC_R_CH_LATCH_FALLING (0x0<< 8)\r
+\r
+#define DMIC_CLK_CTRL_MASK (0x3<<4)\r
+#define DMIC_CLK_CTRL_TO_128FS (0x0<<4)\r
+#define DMIC_CLK_CTRL_TO_64FS (0x1<<4)\r
+#define DMIC_CLK_CTRL_TO_32FS (0x2<<4)\r
+\r
+\r
+//Speaker Mixer Control(0x28)\r
+#define M_RECMIXER_L_TO_SPKMIXER_L (0x1<<15) //Mute Left RecMixer to Left Speaker Mixer\r
+#define M_MIC1_P_TO_SPKMIXER_L (0x1<<14) //Mute MIC1 Positive to Left Speaker Mixer \r
+#define M_DAC_L_TO_SPKMIXER_L (0x1<<13) //Mute Left Dac to Left Speaker Mixer \r
+#define M_OUTMIXER_L_TO_SPKMIXER_L (0x1<<12) //Mute Left OutMixer to Left Speaker Mixer \r
+\r
+#define M_RECMIXER_R_TO_SPKMIXER_R (0x1<< 7) //Mute Right RecMixer to Right Speaker Mixer\r
+#define M_MIC2_P_TO_SPKMIXER_R (0x1<< 6) //Mute MIC1 Positive to Right Speaker Mixer \r
+#define M_DAC_R_TO_SPKMIXER_R (0x1<< 5) //Mute Right Dac to Right Speaker Mixer \r
+#define M_OUTMIXER_R_TO_SPKMIXER_R (0x1<< 4) //Mute Right OutMixer to Right Speaker Mixer \r
+\r
+\r
+\r
+//Speaker/Mono Output Control(0x2A)\r
+#define M_SPKVOL_L_TO_SPOL_MIXER (0x1<<15) //Mute Left Speaker Volume to SPOL Mixer\r
+#define M_SPKVOL_R_TO_SPOL_MIXER (0x1<<14) //Mute Right Speaker Volume to SPOL Mixer \r
+#define M_SPKVOL_L_TO_SPOR_MIXER (0x1<<13) //Mute Left Speaker Volume to SPOR Mixer\r
+#define M_SPKVOL_R_TO_SPOR_MIXER (0x1<<12) //Mute Right Speaker Volume to SPOR Mixer \r
+#define M_OUTVOL_L_TO_MONOMIXER (0x1<<11) //Mute Left Output Volume to Mono Mixer\r
+#define M_OUTVOL_R_TO_MONOMIXER (0x1<<10) //Mute Right Output Volume to Mono Mixer \r
+\r
+\r
+//Speaker/Mono/HP Output Control(0x2C)\r
+#define SPK_L_MUX_SEL_MASK (0x3<<14) //Left Speaker mux select Mask\r
+#define SPK_L_MUX_SEL_SPKMIXER_L (0x0<<14) //Left Speaker mux select Speaker mixer left\r
+#define SPK_L_MUX_SEL_MONO_IN (0x1<<14) //Left Speaker mux select MONO input\r
+#define SPK_L_MUX_SEL_DAC_L (0x3<<14) //Left Speaker mux select Dac left\r
+\r
+#define SPK_R_MUX_SEL_MASK (0x3<<10) //Right Speaker mux select Mask\r
+#define SPK_R_MUX_SEL_SPKMIXER_R (0x0<<10) //Right Speaker mux select Speaker mixer right\r
+#define SPK_R_MUX_SEL_MONO_IN (0x1<<10) //Right Speaker mux select MONO input\r
+#define SPK_R_MUX_SEL_DAC_R (0x3<<10) //Right Speaker mux select Dac right\r
+\r
+#define MONO_MUX_SEL_MASK (0x3<< 6) //Monoout mux select Mask\r
+#define MONO_MUX_SEL_MONOMIXER (0x0<< 6) //Monoout mux select Mono Mixer \r
+#define MONO_MUX_SEL_MONO_IN (0x1<< 6) //Monoout mux select MONO input\r
+\r
+#define HP_L_MUX_SEL_MASK (0x1<< 3) //HP left mux select Mask\r
+#define HP_L_MUX_SEL_HPVOL_L (0x0<< 3) //HP left mux select left HP output volume \r
+#define HP_L_MUX_SEL_DAC_L (0x1<< 3) //HP left mux select Dac left channel\r
+\r
+#define HP_R_MUX_SEL_MASK (0x1<< 2) //HP left mux select Mask\r
+#define HP_R_MUX_SEL_HPVOL_R (0x0<< 2) //HP left mux select left HP output volume\r
+#define HP_R_MUX_SEL_DAC_R (0x1<< 2) //HP left mux select Dac left channel\r
+\r
+\r
+//Stereo I2S Serial Data Port Control(0x34)\r
+#define SDP_MODE_SEL_MASK (0x1<<15) //Main I2S interface select MASK \r
+#define SDP_MODE_SEL_MASTER (0x0<<15) //Main I2S interface select MASTER MODE\r
+#define SDP_MODE_SEL_SLAVE (0x1<<15) //Main I2S interface select SLAVE MODE\r
+\r
+#define SDP_ADC_CPS_SEL_MASK (0x3<<10) //ADC Compress select Mask\r
+#define SDP_ADC_CPS_SEL_OFF (0x0<<10) //ADC Compress select OFF\r
+#define SDP_ADC_CPS_SEL_U_LAW (0x1<<10) //ADC Compress select u_law\r
+#define SDP_ADC_CPS_SEL_A_LAW (0x2<<10) //ADC Compress select a_law\r
+\r
+#define SDP_DAC_CPS_SEL_MASK (0x3<< 8) //DAC Compress select Mask\r
+#define SDP_DAC_CPS_SEL_OFF (0x0<< 8) //DAC Compress select OFF\r
+#define SDP_DAC_CPS_SEL_U_LAW (0x1<< 8) //DAC Compress select u_law\r
+#define SDP_DAC_CPS_SEL_A_LAW (0x2<< 8) //DAC Compress select a_law\r
+ \r
+#define SDP_I2S_BCLK_POL_CTRL (0x1<<7) //0:Normal 1:Invert\r
+\r
+#define SDP_DAC_R_INV (0x1<<6) //0:Normal 1:Invert\r
+\r
+#define SDP_ADC_DATA_L_R_SWAP (0x1<<5) //0:ADC data appear at left phase of LRCK\r
+ //1:ADC data appear at right phase of LRCK\r
+#define SDP_DAC_DATA_L_R_SWAP (0x1<<4) //0:DAC data appear at left phase of LRCK\r
+ //1:DAC data appear at right phase of LRCK \r
+//Data Length Slection\r
+#define SDP_I2S_DL_MASK (0x3<<2) //Stereo Serial Data Length mask \r
+#define SDP_I2S_DL_16 (0x0<<2) //16 bits\r
+#define SDP_I2S_DL_20 (0x1<<2) //20 bits\r
+#define SDP_I2S_DL_24 (0x2<<2) //24 bits\r
+#define SDP_I2S_DL_8 (0x3<<2) //8 bits\r
+ \r
+//PCM Data Format Selection\r
+#define SDP_I2S_DF_MASK (0x3) //main i2s Data Format mask\r
+#define SDP_I2S_DF_I2S (0x0) //I2S FORMAT \r
+#define SDP_I2S_DF_LEFT (0x1) //Left JUSTIFIED\r
+#define SDP_I2S_DF_PCM_A (0x2) //PCM format A\r
+#define SDP_I2S_DF_PCM_B (0x3) //PCM format B\r
+\r
+//Stereo AD/DA Clock Control(0x38h)\r
+#define I2S_PRE_DIV_MASK (0x7<<13) \r
+#define I2S_PRE_DIV_1 (0x0<<13) //DIV 1\r
+#define I2S_PRE_DIV_2 (0x1<<13) //DIV 2\r
+#define I2S_PRE_DIV_4 (0x2<<13) //DIV 4\r
+#define I2S_PRE_DIV_8 (0x3<<13) //DIV 8\r
+#define I2S_PRE_DIV_16 (0x4<<13) //DIV 16\r
+#define I2S_PRE_DIV_32 (0x5<<13) //DIV 32\r
+\r
+#define I2S_LRCK_SEL_N_BCLK_MASK (0x1<<12) //CLOCK RELATIVE OF BCLK AND LCRK\r
+#define I2S_LRCK_SEL_64_BCLK (0x0<<12) //64FS\r
+#define I2S_LRCK_SEL_32_BCLK (0x1<<12) //32FS\r
+\r
+#define DAC_OSR_SEL_MASK (0x3<<10) \r
+#define DAC_OSR_SEL_128FS (0x3<<10)\r
+#define DAC_OSR_SEL_64FS (0x3<<10)\r
+#define DAC_OSR_SEL_32FS (0x3<<10)\r
+#define DAC_OSR_SEL_16FS (0x3<<10)\r
+\r
+#define ADC_OSR_SEL_MASK (0x3<< 8)\r
+#define ADC_OSR_SEL_128FS (0x3<< 8) \r
+#define ADC_OSR_SEL_64FS (0x3<< 8) \r
+#define ADC_OSR_SEL_32FS (0x3<< 8) \r
+#define ADC_OSR_SEL_16FS (0x3<< 8) \r
+\r
+#define ADDA_FILTER_CLK_SEL_256FS (0<<7) //256FS\r
+#define ADDA_FILTER_CLK_SEL_384FS (1<<7) //384FS\r
+\r
+\r
+\r
+//Power managment addition 1 (0x3A),0:Disable,1:Enable\r
+#define PWR_MAIN_I2S_EN (0x1<<15)\r
+#define PWR_CLASS_D (0x1<<12) \r
+#define PWR_ADC_L_CLK (0x1<<11)\r
+#define PWR_ADC_R_CLK (0x1<<10)\r
+#define PWR_DAC_L_CLK (0x1<< 9)\r
+#define PWR_DAC_R_CLK (0x1<< 8)\r
+#define PWR_DAC_REF (0x1<< 7)\r
+#define PWR_DAC_L_TO_MIXER (0x1<< 6)\r
+#define PWR_DAC_R_TO_MIXER (0x1<<5)\r
+\r
+\r
+//Power managment addition 2 (0x3B),0:Disable,1:Enable\r
+#define PWR_OUTMIXER_L (0x1<<15)\r
+#define PWR_OUTMIXER_R (0x1<<14)\r
+#define PWR_SPKMIXER_L (0x1<<13)\r
+#define PWR_SPKMIXER_R (0x1<<12)\r
+#define PWR_RECMIXER_L (0x1<<11)\r
+#define PWR_RECMIXER_R (0x1<<10)\r
+#define PWR_MIC1_BOOT_GAIN (0x1<< 5)\r
+#define PWR_MIC2_BOOT_GAIN (0x1<< 4)\r
+#define PWR_MICBIAS1_VOL (0x1<< 3)\r
+#define PWR_MICBIAS2_VOL (0x1<< 2)\r
+#define PWR_PLL (0x1<< 1)\r
+\r
+\r
+//Power managment addition 3(0x3C),0:Disable,1:Enable\r
+#define PWR_VREF (0x1<<15)\r
+#define PWR_FAST_VREF_CTRL (0x1<<14)\r
+#define PWR_MAIN_BIAS (0x1<<13)\r
+#define PWR_AXO1MIXER (0x1<<11)\r
+#define PWR_AXO2MIXER (0x1<<10)\r
+#define PWR_MONOMIXER (0x1<< 9)\r
+#define PWR_MONO_DEPOP_DIS (0x1<< 8)\r
+#define PWR_MONO_AMP_EN (0x1<< 7)\r
+#define PWR_CHARGE_PUMP (0x1<<4)\r
+#define PWR_HP_L_AMP (0x1<<3)\r
+#define PWR_HP_R_AMP (0x1<<2)\r
+#define PWR_HP_DEPOP_DIS (0x1<<1)\r
+#define PWR_HP_AMP_DRIVING (0x1)\r
+\r
+\r
+//Power managment addition 4(0x3E),0:Disable,1:Enable\r
+#define PWR_SPK_L_VOL (0x1<<15)\r
+#define PWR_SPK_R_VOL (0x1<<14)\r
+#define PWR_LOUT_VOL (0x1<<13)\r
+#define PWR_ROUT_VOL (0x1<<12)\r
+#define PWR_HP_L_OUT_VOL (0x1<<11)\r
+#define PWR_HP_R_OUT_VOL (0x1<<10)\r
+#define PWR_AXIL_IN_VOL (0x1<< 9)\r
+#define PWR_AXIR_IN_VOL (0x1<< 8)\r
+#define PWR_MONO_IN_P_VOL (0x1<< 7)\r
+#define PWR_MONO_IN_N_VOL (0x1<< 6)\r
+\r
+\r
+//General Purpose Control Register(0x40)\r
+#define SPK_AMP_AUTO_RATIO_EN (0x1<<15) //Speaker Amplifier Auto Ratio Gain Control\r
+\r
+#define SPK_AMP_RATIO_CTRL_MASK (0x7<<12)\r
+#define SPK_AMP_RATIO_CTRL_2_34 (0x0<<12) //7.40DB\r
+#define SPK_AMP_RATIO_CTRL_1_99 (0x1<<12) //5.99DB\r
+#define SPK_AMP_RATIO_CTRL_1_68 (0x2<<12) //4.50DB\r
+#define SPK_AMP_RATIO_CTRL_1_56 (0x3<<12) //3.86DB\r
+#define SPK_AMP_RATIO_CTRL_1_44 (0x4<<12) //3.16DB \r
+#define SPK_AMP_RATIO_CTRL_1_27 (0x5<<12) //2.10DB\r
+#define SPK_AMP_RATIO_CTRL_1_09 (0x6<<12) //0.80DB\r
+#define SPK_AMP_RATIO_CTRL_1_00 (0x7<<12) //0.00DB\r
+\r
+#define STEREO_DAC_HI_PASS_FILT_EN (0x1<<11) //Stereo DAC high pass filter enable\r
+#define STEREO_ADC_HI_PASS_FILT_EN (0x1<<10) //Stereo ADC high pass filter enable\r
+\r
+#define ADC_WIND_FILT_MASK (0x3<<4) //Select ADC Wind Filter Clock type\r
+#define ADC_WIND_FILT_8_16_32K (0x0<<4) //8/16/32k\r
+#define ADC_WIND_FILT_11_22_44K (0x1<<4) //11/22/44k\r
+#define ADC_WIND_FILT_12_24_48K (0x2<<4) //12/24/48k\r
+\r
+#define ADC_WIND_FILT_EN (0x1<<3) //Enable ADC Wind Filter\r
+\r
+#define ADC_WIND_CNR_FREQ_MASK (0x7<<0) //SelectADC Wind Filter Corner Frequency \r
+#define ADC_WIND_CNR_FREQ_82_113_122 (0x0<<0) //82/113/122 Hz\r
+#define ADC_WIND_CNR_FREQ_102_141_153 (0x1<<0) //102/141/153 Hz \r
+#define ADC_WIND_CNR_FREQ_131_180_156 (0x2<<0) //131/180/156 Hz\r
+#define ADC_WIND_CNR_FREQ_163_225_245 (0x3<<0) //163/225/245 Hz\r
+#define ADC_WIND_CNR_FREQ_204_281_306 (0x4<<0) //204/281/306 Hz\r
+#define ADC_WIND_CNR_FREQ_261_360_392 (0x5<<0) //261/360/392 Hz\r
+#define ADC_WIND_CNR_FREQ_327_450_490 (0x6<<0) //327/450/490 Hz\r
+#define ADC_WIND_CNR_FREQ_408_563_612 (0x7<<0) //408/563/612 Hz\r
+\r
+\r
+//Global Clock Control Register(0x42)\r
+#define SYSCLK_SOUR_SEL_MASK (0x1<<14)\r
+#define SYSCLK_SOUR_SEL_MCLK (0x0<<14) //system Clock source from MCLK\r
+#define SYSCLK_SOUR_SEL_PLL (0x1<<14) //system Clock source from PLL\r
+#define SYSCLK_SOUR_SEL_PLL_TCK (0x2<<14) //system Clock source from PLL track\r
+\r
+#define PLLCLK_SOUR_SEL_MCLK (0x0<<12) //PLL clock source from MCLK\r
+#define PLLCLK_SOUR_SEL_BITCLK (0x1<<12) //PLL clock source from BITCLK\r
+\r
+#define PLLCLK_PRE_DIV1 (0x0<<11) //DIV 1\r
+#define PLLCLK_PRE_DIV2 (0x1<<11) //DIV 2\r
+\r
+//PLL Control(0x44)\r
+\r
+#define PLL_CTRL_M_VAL(m) ((m)&0xf) //M code for analog PLL\r
+#define PLL_CTRL_K_VAL(k) (((k)&0x7)<<4) //K code for analog PLL\r
+#define PLL_CTRL_N_VAL(n) (((n)&0xff)<<8) //N code for analog PLL\r
+\r
+\r
+//GPIO Pin Configuration(0x4C)\r
+#define GPIO_PIN_FUN_SEL_MASK (0x1<<15)\r
+#define GPIO_PIN_FUN_SEL_IRQ (0x1<<15) //GPIO pin SELECT IRQ\r
+#define GPIO_PIN_FUN_SEL_GPIO_DIMC (0x0<<15) //GPIO PIN SELECT GPIO_DMIC\r
+\r
+\r
+#define GPIO_DMIC_FUN_SEL_MASK (0x1<<3)\r
+#define GPIO_DMIC_FUN_SEL_DIMC (0x1<<3) //GPIO pin SELECT DMIC\r
+#define GPIO_DMIC_FUN_SEL_GPIO (0x0<<3) //GPIO PIN SELECT GPIO\r
+\r
+#define GPIO_PIN_CON_MASK (0x1<<2)\r
+#define GPIO_PIN_SET_INPUT (0x0<<2) //GPIO pin select input\r
+#define GPIO_PIN_SET_OUTPUT (0x1<<2) //GPIO pin select output\r
+\r
+//De-POP function Control 1(0x54)\r
+#define POW_ON_SOFT_GEN (0x1<<15) //POWER ON SOFT GENERATOR\r
+#define EN_MUTE_UNMUTE_DEPOP (0x1<<14) //Enable mute/unmute depop\r
+#define EN_DEPOP2_FOR_HP (0x1<<7) //Enable depop 2 for HP\r
+#define PD_HPAMP_L_ST_UP (0x1<<5) //Power Down HPAMP_L Starts Up Signal\r
+#define PD_HPAMP_R_ST_UP (0x1<<4) //Power Down HPAMP_R Starts Up Signal\r
+#define EN_HP_L_M_UN_MUTE_DEPOP (0x1<<1) //Enable left HP mute/unmute depop\r
+#define EN_HP_R_M_UN_MUTE_DEPOP (0x1<<0) //Enable right HP mute/unmute depop\r
+\r
+//De-POP Fnction Control(0x56)\r
+#define ENA_CAP_FREE_DEPOP (0x1<<14) //enable depop for Capfree block\r
+\r
+\r
+//Jack Detect Control Register(0x5A)\r
+#define JD_USE_MASK (0x3<<14) //JD Pin select\r
+#define JD_USE_JD2 (0x3<<14) //select JD2\r
+#define JD_USE_JD1 (0x2<<14) //select JD1\r
+#define JD_USE_GPIO (0x1<<14) //select GPIO\r
+#define JD_OFF (0x0<<14) //off\r
+\r
+#define JD_HP_EN (0x1<<11) //JD trigger enable for HP\r
+#define JD_HP_TRI_MASK (0x1<<10) //Trigger mask\r
+#define JD_HP_TRI_HI (0x1<<10) //high trigger\r
+#define JD_HP_TRI_LO (0x1<<10) //low trigger\r
+\r
+#define JD_SPK_L_EN (0x1<<9) //JD trigger enable for speaker LP/LN\r
+#define JD_SPK_L_TRI_MASK (0x1<<8) //Trigger mask\r
+#define JD_SPK_L_TRI_HI (0x1<<8) //high trigger\r
+#define JD_SPK_L_TRI_LO (0x0<<8) //low trigger\r
+\r
+#define JD_SPK_R_EN (0x1<<7) //JD trigger enable for speaker RP/RN\r
+#define JD_SPK_R_TRI_MASK (0x1<<6) //Trigger mask\r
+#define JD_SPK_R_TRI_HI (0x1<<6) //high trigger\r
+#define JD_SPK_R_TRI_LO (0x0<<6) //low trigger\r
+\r
+#define JD_MONO_EN (0x1<<5) //JD trigger enable for monoout\r
+#define JD_MONO_TRI_MASK (0x1<<4) //Trigger mask\r
+#define JD_MONO_TRI_HI (0x1<<4) //high trigger\r
+#define JD_MONO_TRI_LO (0x0<<4) //low trigger\r
+\r
+#define JD_AUX_1_EN (0x1<<3) //JD trigger enable for Lout\r
+#define JD_AUX_1_MASK (0x1<<2) //Trigger mask\r
+#define JD_AUX_1_TRI_HI (0x1<<2) //high trigger\r
+#define JD_AUX_1_TRI_LO (0x0<<2) //low trigger\r
+\r
+#define JD_AUX_2_EN (0x1<<1) //JD trigger enable for Rout\r
+\r
+#define JD_AUX_2_MASK (0x1<<0) //Trigger mask\r
+#define JD_AUX_2_TRI_HI (0x1<<0) //high trigger\r
+#define JD_AUX_2_TRI_LO (0x0<<0) //low trigger\r
+\r
+\r
+////ALC CONTROL 1(0x64)\r
+#define ALC_ATTACK_RATE_MASK (0x1F<<8) //select ALC attack rate\r
+#define ALC_RECOVERY_RATE_MASK (0x1F<<0) //select ALC Recovery rate\r
+\r
+\r
+////ALC CONTROL 2(0x65)\r
+#define ALC_COM_NOISE_GATE_MASK (0xF<<0) //select Compensation gain for Noise gate function\r
+\r
+\r
+////ALC CONTROL 3(0x66)\r
+#define ALC_FUN_MASK (0x3<<14) //select ALC path \r
+#define ALC_FUN_DIS (0x0<<14) //disable\r
+#define ALC_ENA_DAC_PATH (0x1<<14) //DAC path\r
+#define ALC_ENA_ADC_PATH (0x3<<14) //ADC path\r
+\r
+#define ALC_PARA_UPDATE (0x1<<13) //update ALC parameter\r
+\r
+#define ALC_LIMIT_LEVEL_MASK (0x1F<<8) //ALC limit level\r
+\r
+#define ALC_NOISE_GATE_FUN_MASK (0x1<<7) //ALC noise gate function\r
+#define ALC_NOISE_GATE_FUN_DIS (0x0<<7) //disable\r
+#define ALC_NOISE_GATE_FUN_ENA (0x1<<7) //enable\r
+\r
+#define ALC_NOISE_GATE_H_D_MASK (0x1<<6) //ALC noise gate hold data function\r
+#define ALC_NOISE_GATE_H_D_DIS (0x0<<6) //disable\r
+#define ALC_NOISE_GATE_H_D_ENA (0x1<<6) //enable\r
+\r
+//Psedueo Stereo & Spatial Effect Block Control(0x68)\r
+#define SPATIAL_CTRL_EN (0x1<<15) //enable Spatial effect\r
+#define ALL_PASS_FILTER_EN (0x1<<14) //enable all pass filter\r
+#define PSEUDO_STEREO_EN (0x1<<13) //enable pseudo stereo block\r
+#define STEREO_EXPENSION_EN (0x1<<12) //enable stereo expansion block\r
+\r
+#define GAIN_3D_PARA_MASK (0x3<<6) //3D gain parameter\r
+#define GAIN_3D_PARA_1_00 (0x0<<6) //3D gain 1.0\r
+#define GAIN_3D_PARA_1_50 (0x1<<6) //3D gain 1.5\r
+#define GAIN_3D_PARA_2_00 (0x2<<6) //3D gain 2.0\r
+\r
+#define RATIO_3D_MASK (0x3<<4) //3D ratio parameter\r
+#define RATIO_3D_0_0 (0x0<<4) //3D ratio 0.0\r
+#define RATIO_3D_0_66 (0x1<<4) //3D ratio 0.66\r
+#define RATIO_3D_1_0 (0x2<<4) //3D ratio 1.0\r
+\r
+#define APF_FUN_SLE_MASK (0x3<<0) //select samplerate for all pass filter \r
+#define APF_FUN_SEL_48K (0x3<<0) //select 48k\r
+#define APF_FUN_SEL_44_1K (0x2<<0) //select 44.1k\r
+#define APF_FUN_SEL_32K (0x1<<0) //select 32k\r
+#define APF_FUN_DIS (0x0<<0) //disable\r
+\r
+\r
+//EQ CONTROL 1(0x6E)\r
+\r
+#define HW_EQ_PATH_SEL_MASK (0x1<<15) //HW EQ FUN SEL\r
+#define HW_EQ_PATH_SEL_DAC (0x0<<15) //HW EQ FOR DAC PATH\r
+#define HW_EQ_PATH_SEL_ADC (0x1<<15) //HW EQ FOR ADC PATH\r
+\r
+#define HW_EQ_UPDATE_CTRL (0x1<<14) //HW EQ Update CTRL\r
+\r
+#define EN_HW_EQ_HPF2 (0x1<<5) //EQ High Pass Filter 2 Control\r
+#define EN_HW_EQ_HPF1 (0x1<<4) //EQ High Pass Filter 1 Control\r
+#define EN_HW_EQ_BP3 (0x1<<3) //EQ Band-3 Control\r
+#define EN_HW_EQ_BP2 (0x1<<2) //EQ Band-2 Control\r
+#define EN_HW_EQ_BP1 (0x1<<1) //EQ Band-1 Control\r
+#define EN_HW_EQ_LPF (0x1<<0) //EQ Low Pass Filter Control\r
+\r
+#define REALTEK_HWDEP 0\r
+struct rt5631_setup_data {\r
+ int i2c_address;\r
+ int i2c_bus; \r
+};\r
+\r
+\r
+extern struct snd_soc_dai rt5631_dai[];\r
+extern struct snd_soc_codec_device soc_codec_dev_rt5631;\r
+\r
+\r
+#endif //__RTCODEC5631_H__\r
help
Say Y if you want to add support for SoC audio on rockchip
with the WM8900.
-
+config SND_RK29_SOC_alc5621
+ tristate "SoC I2S Audio support for rockchip - alc5621"
+ depends on SND_RK29_SOC && I2C_RK29
+ select SND_RK29_SOC_I2S
+ select SND_SOC_alc5621
+ help
+ Say Y if you want to add support for SoC audio on rockchip
+ with the alc5621.
+config SND_RK29_SOC_alc5631
+ tristate "SoC I2S Audio support for rockchip - alc5631"
+ depends on SND_RK29_SOC && I2C_RK29
+ select SND_RK29_SOC_I2S
+ select SND_SOC_alc5631
+ help
+ Say Y if you want to add support for SoC audio on rockchip
+ with the alc5631.
config SND_RK29_SOC_WM8994
tristate "SoC I2S Audio support for rockchip - WM8994"
depends on SND_RK29_SOC && I2C_RK29
Say Y if you want to add support for SoC audio on rockchip
with the RK1000.
-if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900
+if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_alc5621 || SND_RK29_SOC_alc5631
choice
prompt "Set i2s type"
config SND_RK29_CODEC_SOC_MASTER
# ROCKCHIP Machine Support
snd-soc-wm8900-objs := rk29_wm8900.o
+snd-soc-alc5621-objs := rk29_alc5621.o
+snd-soc-alc5631-objs := rk29_rt5631.o
snd-soc-wm8988-objs := rk29_wm8988.o
snd-soc-rk1000-objs := rk29_rk1000codec.o
snd-soc-wm8994-objs := rk29_wm8994.o
obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o
obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_RK29_SOC_WM8900) += snd-soc-wm8900.o
+obj-$(CONFIG_SND_RK29_SOC_alc5621) += snd-soc-alc5621.o
+obj-$(CONFIG_SND_RK29_SOC_alc5631) += snd-soc-alc5631.o
obj-$(CONFIG_SND_RK29_SOC_RK1000) += snd-soc-rk1000.o
--- /dev/null
+/*
+ * rk29_wm8900.c -- SoC audio for rockchip
+ *
+ * Driver for rockchip alc5623 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 <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/rk29_iomap.h>
+#include "../codecs/alc5621.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_alc5623(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 = 0i,sys_clk;
+ int ret;
+
+ DBG("rk29_hw_params for rk29_alc5623\n");
+ /*by Vincent Hsiung for EQ Vol Change*/
+ #define HW_PARAMS_FLAG_EQVOL_ON 0x21
+ #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
+ if ((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("rk29_hw_params set EQ vol for rk29_alc5623\n");
+ }
+ else
+ {
+
+ /* set codec DAI configuration for codec side */
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ DBG("rk29_hw_params for rk29_alc5623 codec as slave\n");
+ 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)
+ DBG("rk29_hw_params for rk29_alc5623 cpu as master\n");
+ 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:
+ sys_clk= 12288000;
+ pll_out = 12288000;
+ break;
+ case 16000:
+ sys_clk= 11289600;
+ pll_out = 12288000;
+ break;
+ case 24000:
+ sys_clk = 24576000;
+ pll_out = 12288000;
+ break;
+ case 32000:
+ sys_clk= 12288000;
+ pll_out = 12288000;
+ case 48000:
+ sys_clk = 12288000;
+ pll_out = 12288000;
+ break;
+ /*------------------------------*/
+ case 11025:
+ sys_clk = 11289600;
+ pll_out = 11289600;
+ break;
+ case 22050:
+ sys_clk = 11289600;
+ pll_out = 11289600;
+ break;
+
+ case 44100:
+ sys_clk = 11289600;
+ pll_out = 11289600;
+ break;
+ default:
+ DBG("rk29_hw_params for rk29_alc5623,invalid sapmleRate:%d\n",params_rate(params));
+ return -EINVAL;
+ break;
+ }
+ DBG("rk29_hw_params for rk29_alc5623, sapmleRate:%d\n",params_rate(params));
+
+
+ /*Set the system clk for codec*/
+ ret=snd_soc_dai_set_sysclk(codec_dai, 0,sys_clk,SND_SOC_CLOCK_IN);//ALC5621 system clk from MCLK or PLL
+ if (ret < 0)
+ {
+ DBG("rk29_hw_params_alc5623:failed to set the sysclk for codec side\n");
+ return ret;
+ }
+
+ /*Set the pll of alc5621,the Pll source from MCLK no matter slave or master mode*/
+ ret=snd_soc_dai_set_pll(codec_dai,RT5621_PLL_FR_BCLK,params_rate(params)*64,sys_clk);
+ if (ret < 0)
+ {
+ DBG("rk29_hw_params_alc5623:failed to set the pll for codec side\n");
+ return ret;
+ }
+
+
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ snd_soc_dai_set_clkdiv(codec_dai, ALC5623_BCLK_DIV, ALC5623_BCLK_DIV_4);
+ snd_soc_dai_set_clkdiv(codec_dai, ALC5623_DAC_LRCLK,(pll_out/4)/params_rate(params));
+ snd_soc_dai_set_clkdiv(codec_dai, ALC5623_ADC_LRCLK,(pll_out/4)/params_rate(params));
+ #endif
+
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ 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);
+ #endif
+ DBG("rk29_hw_params_alc5623:,LRCK=%d\n",(pll_out/4)/params_rate(params));
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget alc5623_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Audio Out", NULL),
+ SND_SOC_DAPM_LINE("Line in", NULL),
+ SND_SOC_DAPM_MIC("Micn", NULL),
+ SND_SOC_DAPM_MIC("Micp", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[]= {
+
+ {"Audio Out", NULL, "HP_L"},
+ {"Audio Out", NULL, "HP_R"},
+ {"Line in", NULL, "RINPUT1"},
+ {"Line in", NULL, "LINPUT1"},
+ {"Micn", NULL, "RINPUT2"},
+ {"Micp", NULL, "LINPUT2"},
+};
+
+/*
+ * Logic for a wm8900 as connected on a rockchip board.
+ */
+static int rk29_alc5623_init(struct snd_soc_codec *codec)
+{
+
+ DBG("rk29_alc5623_init\n");
+
+ /* Add specific widgets */
+ snd_soc_dapm_new_controls(codec, alc5623_dapm_widgets, ARRAY_SIZE(alc5623_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);
+ DBG("rk29_alc5623_init end\n");
+ return 0;
+}
+
+static struct snd_soc_ops rk29_ops = {
+ .hw_params = rk29_hw_params_alc5623,
+};
+
+static struct snd_soc_dai_link rk29_dai_alc5623 = {
+ .name = "ALC5623",
+ .stream_name = "ALC5623 PCM",
+ .cpu_dai = &rk29_i2s_dai[0],
+ .codec_dai = &rt5621_dai,
+ .init = rk29_alc5623_init,
+ .ops = &rk29_ops,
+};
+
+static struct snd_soc_card snd_soc_card_rk29_alc5623 = {
+ .name = "RK29_ALC5623",
+ .platform = &rk29_soc_platform,
+ .dai_link = &rk29_dai_alc5623,
+ .num_links = 1,
+};
+
+
+static struct snd_soc_device rk29_snd_devdata_alc5623 = {
+ .card = &snd_soc_card_rk29_alc5623,
+ .codec_dev = &soc_codec_dev_rt5621,
+};
+
+static struct platform_device *rk29_snd_device_alc5623;
+
+static int __init audio_card_init_alc5623(void)
+{
+ int ret =0;
+ DBG("audio_card_init_alc5623\n");
+ rk29_snd_device_alc5623 = platform_device_alloc("soc-audio", -1);
+ if (!rk29_snd_device_alc5623) {
+ DBG("audio_card_init_alc5623:platform device allocation failed\n");
+ ret = -ENOMEM;
+ return ret;
+ }
+ platform_set_drvdata(rk29_snd_device_alc5623, &rk29_snd_devdata_alc5623);
+ rk29_snd_devdata_alc5623.dev = &rk29_snd_device_alc5623->dev;
+ ret = platform_device_add(rk29_snd_device_alc5623);
+ if (ret) {
+ DBG("audio_card_init_alc5623:platform device add failed\n");
+ platform_device_put(rk29_snd_device_alc5623);
+ }
+ return ret;
+}
+
+static void __exit audio_card_exit_alc5623(void)
+{
+ platform_device_unregister(rk29_snd_device_alc5623);
+}
+
+module_init(audio_card_init_alc5623);
+module_exit(audio_card_exit_alc5623);
+/* Module information */
+MODULE_AUTHOR("rockchip");
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
+MODULE_LICENSE("GPL");
/*
*Turn on or off the transmission path.
*/
+
+static int flag_i2s_tx = 0;
+static int flag_i2s_rx = 0;
static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on)
{
- u32 opr,xfer,fifosts;
- int xor=0;
-
- opr = readl(&(pheadi2s->I2S_DMACR));
- xfer = readl(&(pheadi2s->I2S_XFER));
+ u32 opr,xfer,fifosts;
- if(xfer & I2S_RX_TRAN_START) {
- xor = 1;
- }
+ opr = readl(&(pheadi2s->I2S_DMACR));
+ xfer = readl(&(pheadi2s->I2S_XFER));
+
+ opr &= ~I2S_TRAN_DMA_ENABLE;
+ xfer &= ~I2S_RX_TRAN_START;
+ xfer &= ~I2S_TX_TRAN_START;
+
+ if (on)
+ {
+ I2S_DBG("rockchip_snd_txctrl: on\n");
- opr &= ~I2S_TRAN_DMA_ENABLE;
- xfer &= ~I2S_TX_TRAN_START;
+ //stop tx
+ if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+ writel(xfer, &(pheadi2s->I2S_XFER));
+ writel(opr, &(pheadi2s->I2S_DMACR));
+
+ //start tx
+ opr |= I2S_TRAN_DMA_ENABLE;
+ xfer |= I2S_TX_TRAN_START;
+ xfer |= I2S_RX_TRAN_START;
+ writel(opr, &(pheadi2s->I2S_DMACR));
+ writel(xfer, &(pheadi2s->I2S_XFER));
+
+ flag_i2s_tx = 1;
+ }
+ else
+ {
+ //stop tx
+ flag_i2s_tx = 0;
- if (on)
- {
- if(xor) {
- xfer &= ~I2S_RX_TRAN_START;
- }
- writel(0, &(pheadi2s->I2S_XFER));
- writel(opr, &(pheadi2s->I2S_DMACR));
-
- opr |= I2S_TRAN_DMA_ENABLE;
- xfer |= I2S_TX_TRAN_START;
- if(xor) {
- xfer |= I2S_RX_TRAN_START;
- }
-
- writel(opr, &(pheadi2s->I2S_DMACR));
- writel(xfer, &(pheadi2s->I2S_XFER));
- }
- else
- {
- writel(xfer, &(pheadi2s->I2S_XFER));
- udelay(5);
- writel(opr, &(pheadi2s->I2S_DMACR));
+ if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+ writel(xfer, &(pheadi2s->I2S_XFER));
+ udelay(5);
+ writel(opr, &(pheadi2s->I2S_DMACR));
- }
- I2S_DBG("Enter %s, %d, opr=0x%08X, xfer=0x%08X\n", __func__, __LINE__, opr, xfer);
+ I2S_DBG("rockchip_snd_txctrl: off\n");
+ }
}
static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on)
{
- u32 opr,xfer,fifosts;
- int xor=0;
-
- opr = readl(&(pheadi2s->I2S_DMACR));
- xfer = readl(&(pheadi2s->I2S_XFER));
+ u32 opr,xfer,fifosts;
+
- if(xfer & I2S_TX_TRAN_START){
- xor = 1;
- }
-
- opr &= ~I2S_RECE_DMA_ENABLE;
- xfer &= ~I2S_RX_TRAN_START;
+ opr = readl(&(pheadi2s->I2S_DMACR));
+ xfer = readl(&(pheadi2s->I2S_XFER));
+
+ opr &= ~I2S_RECE_DMA_ENABLE;
+ xfer &= ~I2S_RX_TRAN_START;
+ xfer &= ~I2S_TX_TRAN_START;
+ if (on)
+ {
+ I2S_DBG("rockchip_snd_rxctrl: on\n");
+
+ //stop rx
+ if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+ writel(xfer, &(pheadi2s->I2S_XFER));
+ writel(opr, &(pheadi2s->I2S_DMACR));
+
+ //start rx
+ opr |= I2S_RECE_DMA_ENABLE;
+ xfer |= I2S_TX_TRAN_START;
+ xfer |= I2S_RX_TRAN_START;
+ writel(opr, &(pheadi2s->I2S_DMACR));
+ writel(xfer, &(pheadi2s->I2S_XFER));
+
+ flag_i2s_rx = 1;
+ }
+ else
+ {
+ //stop rx
+ flag_i2s_rx = 0;
- if (on)
- {
- if(xor) {
- xfer &= ~I2S_TX_TRAN_START;
- }
- writel(0, &(pheadi2s->I2S_XFER));
- writel(opr, &(pheadi2s->I2S_DMACR));
-
- opr |= I2S_RECE_DMA_ENABLE;
- xfer |= I2S_RX_TRAN_START;
- if(xor) {
- xfer |= I2S_TX_TRAN_START;
- }
- writel(opr, &(pheadi2s->I2S_DMACR));
- writel(xfer, &(pheadi2s->I2S_XFER));
- }
- else
- {
- writel(xfer, &(pheadi2s->I2S_XFER));
- udelay(5);
- writel(opr, &(pheadi2s->I2S_DMACR));
- }
- I2S_DBG("Enter %s, %d, opr=0x%08X, xfer=0x%08X\n", __func__, __LINE__, opr, xfer);
+ if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+ writel(xfer, &(pheadi2s->I2S_XFER));
+ udelay(5);
+ writel(opr, &(pheadi2s->I2S_DMACR));
+
+ I2S_DBG("rockchip_snd_rxctrl: off\n");
+ }
}
/*
{
struct rk29_i2s_info *i2s;
struct snd_soc_dai *dai;
- struct clk *general_pll;
- unsigned long i2smclk;
int ret;
I2S_DBG("Enter %s, %d pdev->id = %d >>>>>>>>>>>\n", __func__, __LINE__, pdev->id);
}
clk_enable(i2s->iis_clk);
- general_pll=clk_get(NULL, "general_pll");
- if(clk_get_rate(general_pll)>260000000)
- {
- i2smclk=11289600;
- }
- else if(clk_get_rate(general_pll)>130000000)
- {
- i2smclk=11289600/2;
- }
- else
- {
- i2smclk=11289600/4;
- }
- I2S_DBG("func is %s,general pll=%ld,mclk=%ld\n",__FUNCTION__,clk_get_rate(general_pll),i2smclk);
- clk_set_rate(i2s->iis_clk, i2smclk);
+ clk_set_rate(i2s->iis_clk, 11289600);
ret = rk29_i2s_probe(pdev, dai, i2s, 0);
if (ret)
goto err_clk;
--- /dev/null
+/*
+ * rk29_rt5631.c -- SoC audio for rockchip
+ *
+ * Driver for rockchip rt5631 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 <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/rk29_iomap.h>
+#include "../codecs/rt5631.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;
+ unsigned int lrclk = 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 ((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));
+
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+#if 0 //use pll from blck
+ /*Set the pll of rt5631,the Pll source from BITCLK on CPU is master mode*/
+ //bitclk is 64fs
+ ret=snd_soc_dai_set_pll(codec_dai,0,params_rate(params)*64,pll_out);
+ if (ret < 0)
+ {
+ DBG("rk29_hw_params_rt5631:failed to set the pll for codec side\n");
+ return ret;
+ }
+#endif
+ /*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_rt5631:failed to set the sysclk for codec side\n");
+ return ret;
+ }
+ #endif
+
+/*
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+
+ if((24576000%params_rate(params))==0) //for 8k,16k,32k,48k
+ {
+ snd_soc_dai_set_pll(codec_dai,0,pll_out, 24576000);
+ snd_soc_dai_set_sysclk(codec_dai,0, 24576000, SND_SOC_CLOCK_IN);
+ }
+ else if((22579200%params_rate(params))==0) //for 11k,22k,44k
+ {
+ snd_soc_dai_set_pll(codec_dai,0,pll_out, 22579200);
+ snd_soc_dai_set_sysclk(codec_dai,0, 22579200, SND_SOC_CLOCK_IN);
+ }
+
+ #endif
+*/
+
+ #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
+ 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);
+ #endif
+
+ DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget rt5631_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*/
+ {"Mic Bias1", NULL, "Mic Jack"},
+ {"MIC1", NULL, "Mic Bias1"},
+ /* HP_OUT --> Headphone Jack */
+ {"Headphone Jack", NULL, "HPOL"},
+ {"Headphone Jack", NULL, "HPOR"},
+ /* LINE_OUT --> Ext Speaker */
+ {"Ext Spk", NULL, "SPOL"},
+ {"Ext Spk", NULL, "SPOR"},
+
+} ;
+
+/*
+ * Logic for a rt5631 as connected on a rockchip board.
+ */
+static int rk29_rt5631_init(struct snd_soc_codec *codec)
+{
+ struct snd_soc_dai *codec_dai = &codec->dai[0];
+ int ret;
+
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ /* Add specific widgets */
+ snd_soc_dapm_new_controls(codec, rt5631_dapm_widgets,
+ ARRAY_SIZE(rt5631_dapm_widgets));
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+ /* Set up specific audio path audio_mapnects */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+// snd_soc_dapm_nc_pin(codec, "HP_L");
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+// snd_soc_dapm_nc_pin(codec, "HP_R");
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+ snd_soc_dapm_sync(codec);
+ DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+ return 0;
+}
+
+static struct snd_soc_ops rk29_ops = {
+ .hw_params = rk29_hw_params,
+};
+
+static struct snd_soc_dai_link rk29_dai = {
+ .name = "RT5631",
+ .stream_name = "RT5631 PCM",
+ .cpu_dai = &rk29_i2s_dai[0],
+ .codec_dai = &rt5631_dai,
+ .init = rk29_rt5631_init,
+ .ops = &rk29_ops,
+};
+
+static struct snd_soc_card snd_soc_card_rk29 = {
+ .name = "RK29_RT5631",
+ .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_rt5631,
+};
+
+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");
+\r