/* * rt5624.c -- RT5624 ALSA Soc Audio driver * * Copyright 2008 Realtek Microelectronics * * Author: flove * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //////////////////////// //For Headset IRQ //////////////////////// #include #include #include #include #include #include #include //Qisda, Asaku Chen, 2009/08/12, for EM test { #include //Qisda, Asaku Chen, 2009/08/12, for EM test } #include "rt5624.h" #define AUDIO_NAME "rt5624" #define RT5624_VERSION "0.01" //AUDIO PATH relative typedef enum { SND_OUT_PATH_HEADSET=0, SND_OUT_PATH_SPEAKER, SND_OUT_PATH_UNKNOWN }snd_out_path_type; typedef enum { /*Speaker*/ SND_IN_PATH_MIC1=0, /*Headset*/ SND_IN_PATH_MIC2, SND_IN_PATH_UNKNOWN }snd_in_path_type; snd_out_path_type g_snd_out_path = SND_OUT_PATH_UNKNOWN; snd_in_path_type g_snd_in_path = SND_IN_PATH_MIC1/*SND_IN_PATH_UNKNOWN*/; struct snd_ctl_elem_value *ucontrol_store=NULL; static u32 get_headset_jack_status(); static snd_in_path_type set_audio_in_path_dep_on_headset_jack(); static snd_in_path_type set_audio_in_path_dep_on_out_variable(); static snd_out_path_type set_audio_out_path_dep_on_headset_jack(); struct snd_soc_codec *GetRt5624CodecData(); static void rt5624_turn_off_codec_hw(); static void rt5624_turn_on_codec_hw(); //#include //extern int as090b00_board_id; typedef enum { /*Speaker*/ SND_HEADSET_3_PIN=0, /*Headset*/ SND_HEADSET_4_PIN, SND_HEADSET_PIN_ULOWN }snd_headset_pin_type; snd_headset_pin_type g_btHeadsetPinType = SND_HEADSET_4_PIN; typedef enum { SND_LOOPBACK_NONE, SND_LOOPBACK_BOARD_SPK_MIC1, SND_LOOPBACK_HEADSET_RECIVER_MIC2 }loopback_type; static loopback_type loopback_setting = SND_LOOPBACK_NONE; static loopback_type pre_loopback_setting = SND_LOOPBACK_NONE; /* * Debug */ #ifdef CONFIG_SND_DEBUG #define s3cdbg(x...) printk(x) #else #define s3cdbg(x...) #endif #define RT5624_DEBUG 0 #ifdef RT5624_DEBUG #define dbg(format, arg...) \ printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg) #else #define dbg(format, arg...) do {} while (0) #endif #define err(format, arg...) \ printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg) #define info(format, arg...) \ printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg) #define warn(format, arg...) \ printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg) static int caps_charge = 2000; module_param(caps_charge, int, 0); MODULE_PARM_DESC(caps_charge, "RT5624 cap charge time (msecs)"); /* codec private data */ struct rt5624_priv { unsigned int sysclk; }; static struct snd_soc_device *rt5624_socdev=NULL; unsigned long rt5624_vol_value = 6; /* * rt5624 register cache * We can't read the RT5624 register space when we * are using 2 wire for device control, so we cache them instead. */ static const u16 rt5624_reg[0x7E/2]; /* virtual HP mixers regs */ #define HPL_MIXER 0x80 #define HPR_MIXER 0x82 static u16 reg80=0,reg82=0; //HIKO: For Volume 10 step setting { #define VIRTUAL_REG_FOR_VOLUME 0x86 #define VOLUME_STEP 10//100 static int reg86; static int get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); static struct vol_setting get_real_volume(unsigned long num); static int set_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); static int restore_volume(); //HIKO: For Volume 10 step setting } //Default Register Setting u16 Set_Codec_Reg_Init[][2]={ {RT5624_MAIN_SDP_CTRL ,0x8000},//set I2S codec to slave mode //HIKO: The default Volume {RT5624_STEREO_DAC_VOL ,0x0808},//default stereo DAC volume to 0db // {RT5624_STEREO_DAC_VOL ,0x0000},//default stereo DAC volume to 12db // {RT5624_STEREO_DAC_VOL ,0x0000 | (0x07<<8) | 0x07},//default stereo DAC volume #if defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_E600_DVT1) {RT5624_OUTPUT_MIXER_CTRL,0xA300},//default output mixer control #else {RT5624_OUTPUT_MIXER_CTRL,0x6B00},//default output mixer control #endif {RT5624_ADC_REC_MIXER ,0x3f3f},//set record source is Mic1 by default {RT5624_MIC_CTRL ,0x0500},//set Mic1,Mic2 boost 20db {RT5624_SPK_OUT_VOL ,0x8080},//default speaker volume to 0db {RT5624_HP_OUT_VOL ,0x8888},//default HP volume to -12db // {RT5624_ADC_REC_GAIN ,0xF58B | 0x1F<<7 | 0x1F},//default HP volume to -12db {RT5624_ADC_REC_GAIN ,0xFFBF},//default HP volume to -12db // {RT5624_GEN_CTRL_REG1 ,0x8458}, {RT5624_GEN_CTRL_REG1 ,0x0428}, }; #define SET_CODEC_REG_INIT_NUM ARRAY_SIZE(Set_Codec_Reg_Init) //HIKO: For Volume 10 step setting { /*kit.add 2009/12/21*/ struct vol_setting{ unsigned long dac_val; unsigned long output_vol; }; /*kit.end*/ static struct vol_setting speaker_vol_tab[11] = { /*kit.mod 2009/12/21*/ {((0x08<<8) | 0x08), ((0x80<<8) | 0x80)}, {((0x08<<8) | 0x08), ((0x0C<<8) | 0x0C)}, {((0x08<<8) | 0x08), ((0x0A<<8) | 0x0A)}, {((0x08<<8) | 0x08), ((0x07<<8) | 0x07)}, {((0x08<<8) | 0x08), ((0x06<<8) | 0x06)}, {((0x08<<8) | 0x08), ((0x04<<8) | 0x04)}, {((0x08<<8) | 0x08), ((0x03<<8) | 0x03)}, {((0x08<<8) | 0x08), ((0x02<<8) | 0x02)}, {((0x07<<8) | 0x07), ((0x02<<8) | 0x02)}, {((0x07<<8) | 0x07), ((0x01<<8) | 0x01)}, {((0x06<<8) | 0x06), ((0x00<<8) | 0x00)} /*kit.end*/ }; static struct vol_setting headset_vol_tab[11] = { /*kit.mod 2009/12/25*/ {((0x0C<<8) | 0x0C), ((0x9F<<8) | 0x9F)}, {((0x0C<<8) | 0x0C), ((0x1F<<8) | 0x1F)}, {((0x0C<<8) | 0x0C), ((0x1D<<8) | 0x1D)}, {((0x0C<<8) | 0x0C), ((0x1A<<8) | 0x1A)}, {((0x0C<<8) | 0x0C), ((0x16<<8) | 0x16)}, {((0x0C<<8) | 0x0C), ((0x13<<8) | 0x13)}, {((0x0C<<8) | 0x0C), ((0x0F<<8) | 0x0F)}, {((0x0C<<8) | 0x0C), ((0x0D<<8) | 0x0D)}, {((0x0C<<8) | 0x0C), ((0x0B<<8) | 0x0B)}, {((0x0C<<8) | 0x0C), ((0x09<<8) | 0x09)}, {((0x0C<<8) | 0x0C), ((0x07<<8) | 0x07)} /*kit.end*/ }; static struct vol_setting headset_vol_asus_after_A02_tab[11] = { /*kit.mod 2009/12/21*/ {((0x0C<<8) | 0x0C), ((0x80<<8) | 0x80)}, {((0x0C<<8) | 0x0C), ((0x1F<<8) | 0x1F)}, {((0x0C<<8) | 0x0C), ((0x19<<8) | 0x19)}, {((0x0C<<8) | 0x0C), ((0x16<<8) | 0x16)}, {((0x0C<<8) | 0x0C), ((0x13<<8) | 0x13)}, {((0x0C<<8) | 0x0C), ((0x0F<<8) | 0x0F)}, {((0x0C<<8) | 0x0C), ((0x0B<<8) | 0x0B)}, {((0x0C<<8) | 0x0C), ((0x09<<8) | 0x09)}, {((0x0C<<8) | 0x0C), ((0x07<<8) | 0x07)}, {((0x0C<<8) | 0x0C), ((0x05<<8) | 0x05)}, {((0x0C<<8) | 0x0C), ((0x03<<8) | 0x03)} /*kit.end*/ }; //HIKO: For Volume 10 step setting } //////////////////////// //For Headset IRQ //////////////////////// static irqreturn_t rt5624_headset_irq(int irq, void *data); static void rt5624_set_irq(void *int_dat, void *mic_int_dat); static void rt5624_headset_int_setup(); static void rt5624_mic_setup(snd_in_path_type mic_in_type); static void audio_realtime_setting(); static void audio_realtime_headset_type_setting(); static void audio_realtime_board_type_setting(); static void loopback_setting_active(); //For Earpiece INT data using void *g_headset_plugin_int_dat=NULL; void *g_headset_mic_int_dat=NULL; struct snd_soc_codec *g_codecRt5624 = NULL; #define RT5624_DEVICE_NAME "rt5624-codec-dev" #define RT5624_MIC_DEVICE_NAME "rt5624-headset_mic-codec-dev" static struct work_struct g_wqReadData; static struct work_struct g_wqMicata; static void rt5624_headset_det_path_route_workq(); static void rt5624_mic_det_path_route_workq(); static snd_headset_pin_type rt5624_get_headset_type(); //Qisda, Asaku Chen, 2009/08/12, for EM test { static int rt5624_fops_open(struct inode *inode, struct file *file) { //printk("\nA3U fops open\n"); return 0; } static void print_codec_regs(); #define RT5624_FOPS_IOCTL_READ_VENDOR_ID 1 #define RT5624_FOPS_IOCTL_HEADPHONE_INSERT 2 #define RT5624_FOPS_IOCTL_BOARD_LOOPBACK 3 #define RT5624_FOPS_IOCTL_HEADPHONE_LOOPBACK 4 #define RT5624_FOPS_IOCTL_REG_STATUS_READ 5 #define RT5624_FOPS_IOCTL_REG_STATUS_WRITE 6 #define RT5624_FOPS_IOCTL_AUDIO_IF_ENABLE 7 #define RT5624_FOPS_IOCTL_AUDIO_POWER_STATE 8 /*kit.add 2010/01/29*/ #define RT5624_FOPS_IOCTL_AUDIO_VOICE_ENABLE 9 /*kit.end*/ //Qisda, Asaku Chen, 2009/08/12, for EM test } /* * read rt5624 register cache */ static inline unsigned int rt5624_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { printk("[kit]: rt5624_read_reg_cache()\n"); u16 *cache = codec->reg_cache; if (reg < 1 || reg > (ARRAY_SIZE(rt5624_reg) + 1)) return -1; return cache[reg/2]; } /* * write rt5624 register cache */ static inline void rt5624_write_reg_cache(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { printk("[kit]: rt5624_write_reg_cache()\n"); u16 *cache = codec->reg_cache; if (reg < 0 || reg > 0x7e) return; cache[reg/2] = value; } static int rt5624_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { u8 data[3]; if(reg>0x7E) { if(reg==HPL_MIXER) reg80=value; else if(reg==HPR_MIXER) reg82=value; else return -EIO; return 0; } printk("rt5624 write reg=%x,value=%x\n",reg,value); data[0] = reg; data[1] = (0xFF00 & value) >> 8; data[2] = 0x00FF & value; if (codec->hw_write(codec->control_data, data, 3) == 3) { rt5624_write_reg_cache (codec, reg, value); // printk("rt5624 write OK\n"); return 0; } else { printk("rt5624 write faile\n"); return -EIO; } } static unsigned int rt5624_read(struct snd_soc_codec *codec, unsigned int reg) { u8 data[2]={0}; unsigned int value=0x0; if(reg>0x7E) { if(reg==HPL_MIXER) return reg80; else if(reg==HPR_MIXER) return reg82; else return -EIO; return -EIO; } data[0] = reg; if(codec->hw_write(codec->control_data, data, 1) ==1) { codec->hw_read(codec->control_data, data, 2); value = (data[0]<<8) | data[1]; printk("rt5624 read reg%x=%x\n",reg,value); return value; } else { printk("rt5624 read faile\n"); return -EIO; } } static int rt5624_write_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask) { unsigned char RetVal=0; unsigned int CodecData; if(!mask) return 0; if(mask!=0xffff) { CodecData=rt5624_read(codec,reg); CodecData&=~mask; CodecData|=(value&mask); RetVal=rt5624_write(codec,reg,CodecData); } else { RetVal=rt5624_write(codec,reg,value); } return RetVal; } //***************************************************************************** // //function:Change audio codec power status // //***************************************************************************** static int rt5624_ChangeCodecPowerStatus(struct snd_soc_codec *codec,int power_state) { printk("[kit]: rt5624_ChangeCodecPowerStatus()\n"); unsigned short int PowerDownState=0; unsigned char curr_micbias_num=PWR_MIC_BIAS1; if (g_snd_in_path == SND_IN_PATH_MIC2) { curr_micbias_num = PWR_MIC_BIAS2; } //HIKO DEBUG printk("[HIKO RT5624] power_state==0x%X, curr_micbias_num==0x%X\n", power_state, curr_micbias_num); switch(power_state) { case POWER_STATE_D0: //FULL ON-----power on all power rt5624_write(codec,RT5624_PWR_MANAG_ADD1,~PowerDownState); rt5624_write(codec,RT5624_PWR_MANAG_ADD2,~PowerDownState); rt5624_write(codec,RT5624_PWR_MANAG_ADD3,~PowerDownState); break; case POWER_STATE_D1: //LOW ON----- rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,PWR_DAC_REF | PWR_MAIN_BIAS | curr_micbias_num/*PWR_MIC_BIAS1*/ | PWR_MAIN_I2S | PWR_HI_R_LOAD_HP ,PWR_DAC_REF | PWR_MAIN_BIAS | curr_micbias_num/*PWR_MIC_BIAS1*/ | PWR_MAIN_I2S | PWR_HI_R_LOAD_HP); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2,PWR_R_ADC_REC_MIXER | PWR_L_ADC_REC_MIXER | PWR_R_HP_MIXER | PWR_L_HP_MIXER | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_CLK_GAIN | PWR_R_DAC_CLK | PWR_L_DAC_CLK | PWR_MIXER_VREF | PWR_CLASS_AB ,PWR_R_ADC_REC_MIXER | PWR_L_ADC_REC_MIXER | PWR_R_HP_MIXER | PWR_L_HP_MIXER | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_CLK_GAIN | PWR_R_DAC_CLK | PWR_L_DAC_CLK | PWR_MIXER_VREF | PWR_CLASS_AB); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD3,PWR_MIC1_BOOST | PWR_SPK_R_OUT | PWR_SPK_L_OUT |PWR_HP_R_OUT | PWR_HP_L_OUT | PWR_SPK_RN_OUT | PWR_SPK_LN_OUT ,PWR_MIC1_BOOST | PWR_SPK_R_OUT | PWR_SPK_L_OUT |PWR_HP_R_OUT | PWR_HP_L_OUT | PWR_SPK_RN_OUT | PWR_SPK_LN_OUT); break; case POWER_STATE_D1_PLAYBACK: //Low on of Playback rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,PWR_DAC_REF | PWR_MAIN_BIAS | PWR_MAIN_I2S /*| PWR_HI_R_LOAD_HP flove012610*/ ,PWR_DAC_REF | PWR_MAIN_BIAS | PWR_MAIN_I2S/* | PWR_HI_R_LOAD_HP flove012610*/); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2,PWR_R_HP_MIXER | PWR_L_HP_MIXER | PWR_R_DAC_CLK | PWR_L_DAC_CLK | PWR_MIXER_VREF | PWR_CLASS_AB ,PWR_R_HP_MIXER | PWR_L_HP_MIXER | PWR_R_DAC_CLK | PWR_L_DAC_CLK | PWR_MIXER_VREF | PWR_CLASS_AB); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD3,PWR_SPK_R_OUT | PWR_SPK_L_OUT | PWR_HP_R_OUT | PWR_HP_L_OUT | PWR_SPK_RN_OUT | PWR_SPK_LN_OUT ,PWR_SPK_R_OUT | PWR_SPK_L_OUT | PWR_HP_R_OUT | PWR_HP_L_OUT |PWR_SPK_RN_OUT | PWR_SPK_LN_OUT); break; case POWER_STATE_D1_RECORD: //Low on of Record rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,curr_micbias_num/*PWR_MIC_BIAS1*/ | PWR_MAIN_BIAS | PWR_MAIN_I2S,curr_micbias_num/*PWR_MIC_BIAS1*/ | PWR_MAIN_BIAS | PWR_MAIN_I2S); // rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2,PWR_R_ADC_REC_MIXER | PWR_L_ADC_REC_MIXER | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_CLK_GAIN | PWR_MIXER_VREF ,PWR_R_ADC_REC_MIXER | PWR_L_ADC_REC_MIXER | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_CLK_GAIN | PWR_MIXER_VREF); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD3,PWR_MIC1_BOOST,PWR_MIC1_BOOST); break; case POWER_STATE_D2: //STANDBY---- rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD3,0,PWR_MIC1_BOOST | PWR_SPK_R_OUT | PWR_SPK_L_OUT /*|PWR_HP_R_OUT | PWR_HP_L_OUT flove012710*/ | PWR_SPK_RN_OUT | PWR_SPK_LN_OUT); // rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,0,PWR_DAC_REF | curr_micbias_num/*PWR_MIC_BIAS1*/ | PWR_HI_R_LOAD_HP | PWR_MAIN_I2S); // rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2,0,PWR_R_ADC_REC_MIXER | PWR_L_ADC_REC_MIXER | PWR_R_HP_MIXER | PWR_L_HP_MIXER | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_CLK_GAIN | PWR_R_DAC_CLK | PWR_L_DAC_CLK | PWR_CLASS_AB); break; case POWER_STATE_D2_PLAYBACK: //STANDBY of playback rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD3,0,PWR_SPK_R_OUT | PWR_SPK_L_OUT | PWR_HP_R_OUT | PWR_HP_L_OUT | PWR_SPK_RN_OUT | PWR_SPK_LN_OUT); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,0,PWR_DAC_REF | PWR_HI_R_LOAD_HP); // rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2,0,PWR_R_HP_MIXER | PWR_L_HP_MIXER | PWR_R_DAC_CLK | PWR_L_DAC_CLK | PWR_CLASS_AB); break; case POWER_STATE_D2_RECORD: //STANDBY of record rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD3,0,PWR_MIC1_BOOST); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,0,curr_micbias_num/*PWR_MIC_BIAS1*/); // rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2,0,PWR_R_ADC_REC_MIXER | PWR_L_ADC_REC_MIXER | PWR_R_ADC_CLK_GAIN | PWR_L_ADC_CLK_GAIN); break; case POWER_STATE_D3: //SLEEP case POWER_STATE_D4: //OFF----power off all power rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,0,PWR_HI_R_LOAD_HP); rt5624_write(codec,RT5624_PWR_MANAG_ADD3,PowerDownState); rt5624_write(codec,RT5624_PWR_MANAG_ADD1,PowerDownState); rt5624_write(codec,RT5624_PWR_MANAG_ADD2,PowerDownState); PowerDownState=RT_PWR_PR0 | RT_PWR_PR1 | RT_PWR_PR2 | RT_PWR_PR3 | RT_PWR_PR5 | RT_PWR_PR6 | RT_PWR_PR7; rt5624_write(codec,RT5624_PD_CTRL_STAT,PowerDownState); break; default: break; } return 0; } //***************************************************************************** // //function AudioOutEnable:Mute/Unmute audio out channel // WavOutPath:output channel // Mute :Mute/Unmute output channel // //***************************************************************************** static int rt5624_AudioOutEnable(struct snd_soc_codec *codec,unsigned short int WavOutPath,int Mute) { printk("[kit]: rt5624_AudioOutEnable()\n"); int RetVal=0; if(Mute) { switch(WavOutPath) { case RT_WAVOUT_ALL_ON: //Mute Speaker right/left channel RetVal=rt5624_write_mask(codec,RT5624_SPK_OUT_VOL, RT_L_MUTE|RT_R_MUTE, RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel RetVal=rt5624_write_mask(codec,RT5624_HP_OUT_VOL, RT_L_MUTE|RT_R_MUTE, RT_L_MUTE|RT_R_MUTE); //Mute Mono channel RetVal=rt5624_write_mask(codec,RT5624_PHONEIN_MONO_OUT_VOL, RT_R_MUTE, RT_R_MUTE); //Mute DAC to HP,Speaker,Mono Mixer RetVal=rt5624_write_mask(codec,RT5624_STEREO_DAC_VOL, RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER, RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); break; case RT_WAVOUT_HP: //Mute headphone right/left channel RetVal=rt5624_write_mask(codec,RT5624_HP_OUT_VOL, RT_L_MUTE|RT_R_MUTE, RT_L_MUTE|RT_R_MUTE); break; case RT_WAVOUT_SPK: //Mute Speaker right/left channel RetVal=rt5624_write_mask(codec,RT5624_SPK_OUT_VOL, RT_L_MUTE|RT_R_MUTE, RT_L_MUTE|RT_R_MUTE); break; case RT_WAVOUT_MONO: //Mute MonoOut channel RetVal=rt5624_write_mask(codec, RT5624_PHONEIN_MONO_OUT_VOL, RT_R_MUTE,RT_R_MUTE); break; case RT_WAVOUT_DAC: //Mute DAC to HP,Speaker,Mono Mixer RetVal=rt5624_write_mask(codec,RT5624_STEREO_DAC_VOL,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER ,RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); break; default: return 0; } } else { switch(WavOutPath) { case RT_WAVOUT_ALL_ON: //Mute Speaker right/left channel RetVal = rt5624_write_mask(codec, RT5624_SPK_OUT_VOL, 0, RT_L_MUTE|RT_R_MUTE); //Mute headphone right/left channel RetVal = rt5624_write_mask(codec, RT5624_HP_OUT_VOL, 0, RT_L_MUTE|RT_R_MUTE); //Mute Mono channel RetVal = rt5624_write_mask(codec, RT5624_PHONEIN_MONO_OUT_VOL, 0, RT_L_MUTE|RT_R_MUTE); //Mute DAC to HP,Speaker,Mono Mixer RetVal = rt5624_write_mask(codec, RT5624_STEREO_DAC_VOL, 0, RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); break; case RT_WAVOUT_HP: //unMute headphone right/left channel RetVal = rt5624_write_mask(codec, RT5624_HP_OUT_VOL, 0, RT_L_MUTE|RT_R_MUTE); break; case RT_WAVOUT_SPK: //unMute Speaker right/left channel RetVal = rt5624_write_mask(codec, RT5624_SPK_OUT_VOL, 0, RT_L_MUTE|RT_R_MUTE); break; case RT_WAVOUT_MONO: //unMute MonoOut channel RetVal = rt5624_write_mask(codec, RT5624_PHONEIN_MONO_OUT_VOL, 0, RT_R_MUTE); break; case RT_WAVOUT_DAC: //unMute DAC to HP,Speaker,Mono Mixer RetVal = rt5624_write_mask(codec, RT5624_STEREO_DAC_VOL, 0, RT_M_HP_MIXER|RT_M_SPK_MIXER|RT_M_MONO_MIXER); break; default: return 0; } } return RetVal; } //***************************************************************************** // //function:Enable/Disable ADC input source control // //***************************************************************************** static int Enable_ADC_Input_Source(struct snd_soc_codec *codec,unsigned short int ADC_Input_Sour,int Enable) { printk("[kit]: Enable_ADC_Input_Source()\n"); int bRetVal=0; if(Enable) { //Enable ADC source bRetVal=rt5624_write_mask(codec,RT5624_ADC_REC_MIXER,0,ADC_Input_Sour); } else { //Disable ADC source bRetVal=rt5624_write_mask(codec,RT5624_ADC_REC_MIXER,ADC_Input_Sour,ADC_Input_Sour); } return bRetVal; } #define rt5624_reset(c) rt5624_write(c, 0x0, 0) /* * RT5624 Controls */ static const char *rt5624_spkl_pga[] = {"Vmid","HPL mixer","SPK mixer","Mono Mixer"}; static const char *rt5624_spkr_pga[] = {"Vmid","HPR mixer","SPK mixer","Mono Mixer"}; static const char *rt5624_hpl_pga[] = {"Vmid","HPL mixer"}; static const char *rt5624_hpr_pga[] = {"Vmid","HPR mixer"}; static const char *rt5624_mono_pga[] = {"Vmid","HP mixer","SPK mixer","Mono Mixer"}; static const char *rt5624_amp_type_sel[] = {"Class AB","Class D"}; static const char *rt5624_mic_boost_sel[] = {"Bypass","20db","30db","40db"}; static const struct soc_enum rt5624_enum[] = { SOC_ENUM_SINGLE(RT5624_OUTPUT_MIXER_CTRL,14, 4, rt5624_spkl_pga), /* spk left input sel 0 */ SOC_ENUM_SINGLE(RT5624_OUTPUT_MIXER_CTRL,11, 4, rt5624_spkr_pga), /* spk right input sel 1 */ SOC_ENUM_SINGLE(RT5624_OUTPUT_MIXER_CTRL,9, 2, rt5624_hpl_pga), /* hp left input sel 2 */ SOC_ENUM_SINGLE(RT5624_OUTPUT_MIXER_CTRL,8, 2, rt5624_hpr_pga), /* hp right input sel 3 */ SOC_ENUM_SINGLE(RT5624_OUTPUT_MIXER_CTRL,6, 4, rt5624_mono_pga), /* mono input sel 4 */ SOC_ENUM_SINGLE(RT5624_MIC_CTRL ,10, 4, rt5624_mic_boost_sel), /*Mic1 boost sel 5 */ SOC_ENUM_SINGLE(RT5624_MIC_CTRL ,8, 4,rt5624_mic_boost_sel), /*Mic2 boost sel 6 */ SOC_ENUM_SINGLE(RT5624_OUTPUT_MIXER_CTRL,12, 2,rt5624_amp_type_sel), /*Speaker AMP sel 7 */ }; static const struct snd_kcontrol_new rt5624_snd_controls[] = { SOC_DOUBLE("Speaker Playback Volume", RT5624_SPK_OUT_VOL, 8, 0, 31, 1), //SOC_SINGLE_EXT("Speaker Playback Volume", VIRTUAL_REG_FOR_VOLUME, 0, VOLUME_STEP-1, 1, get_volume, set_volume), SOC_DOUBLE("Speaker Playback Switch", RT5624_SPK_OUT_VOL, 15, 7, 1, 1), //HIKO: For Volume 10 step setting { //SOC_DOUBLE("Headphone Playback Volume", RT5624_HP_OUT_VOL, 8, 0, 31, 1), //SOC_SINGLE_EXT("Headphone Playback Volume", VIRTUAL_REG_FOR_VOLUME, 0, VOLUME_STEP-1, 1, get_volume, set_volume), SOC_SINGLE_EXT("Headphone Playback Volume", VIRTUAL_REG_FOR_VOLUME, 0, VOLUME_STEP, 1, get_volume, set_volume), //SOC_SINGLE_EXT("Headphone Playback Volume", VIRTUAL_REG_FOR_VOLUME, 0, VOLUME_STEP-1, 1, get_volume, set_volume), //HIKO: For Volume 10 step setting } SOC_DOUBLE("Headphone Playback Switch", RT5624_HP_OUT_VOL, 15, 7, 1, 1), SOC_SINGLE("Mono Playback Volume", RT5624_PHONEIN_MONO_OUT_VOL, 0, 31, 1), SOC_SINGLE("Mono Playback Switch", RT5624_PHONEIN_MONO_OUT_VOL, 7, 1, 1), //HIKO: For Volume 10 step setting { //SOC_DOUBLE("PCM Playback Volume", RT5624_STEREO_DAC_VOL, 8, 0, 31, 1), //SOC_SINGLE_EXT("PCM Playback Volume", VIRTUAL_REG_FOR_VOLUME, 0, VOLUME_STEP-1, 1, get_volume, set_volume), SOC_SINGLE_EXT("PCM Playback Volume", VIRTUAL_REG_FOR_VOLUME, 0, VOLUME_STEP, 1, get_volume, set_volume), //SOC_SINGLE_EXT("PCM Playback Volume", VIRTUAL_REG_FOR_VOLUME, 0, VOLUME_STEP-1, 1, get_volume, set_volume), //HIKO: For Volume 10 step setting } SOC_DOUBLE("PCM Playback Switch", RT5624_STEREO_DAC_VOL, 15, 7, 1, 1), SOC_DOUBLE("Line In Volume", RT5624_LINE_IN_VOL, 8, 0, 31, 1), SOC_SINGLE("Mic 1 Volume", RT5624_MIC_VOL, 8, 31, 1), SOC_SINGLE("Mic 2 Volume", RT5624_MIC_VOL, 0, 31, 1), SOC_ENUM("Mic 1 Boost", rt5624_enum[5]), SOC_ENUM("Mic 2 Boost", rt5624_enum[6]), SOC_ENUM("Speaker Amp Type", rt5624_enum[7]), SOC_SINGLE("Phone In Volume", RT5624_PHONEIN_MONO_OUT_VOL, 8, 31, 1), SOC_DOUBLE("Capture Volume", RT5624_ADC_REC_GAIN, 7, 0, 31, 0), }; /* add non dapm controls */ static int rt5624_add_controls(struct snd_soc_codec *codec) { printk("[kit]: rt5624_add_controls()\n"); int err, i; for (i = 0; i < ARRAY_SIZE(rt5624_snd_controls); i++) { err = snd_ctl_add(codec->card, snd_soc_cnew(&rt5624_snd_controls[i],codec, NULL)); if (err < 0) return err; } return 0; } /* * _DAPM_ Controls */ /* We have to create a fake left and right HP mixers because * the codec only has a single control that is shared by both channels. * This makes it impossible to determine the audio path using the current * register map, thus we add a new (virtual) register to help determine the * audio route within the device. */ static int mixer_event (struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { printk("[kit]: mixer_event()\n"); u16 l, r, lineIn,mic1,mic2, phone, pcm,voice; l = rt5624_read(w->codec, HPL_MIXER); r = rt5624_read(w->codec, HPR_MIXER); lineIn = rt5624_read(w->codec, RT5624_LINE_IN_VOL); mic1 = rt5624_read(w->codec, RT5624_MIC_ROUTING_CTRL); mic2 = rt5624_read(w->codec, RT5624_MIC_ROUTING_CTRL); phone = rt5624_read(w->codec,RT5624_PHONEIN_MONO_OUT_VOL); pcm = rt5624_read(w->codec, RT5624_STEREO_DAC_VOL); voice = rt5624_read(w->codec, RT5624_VOICE_DAC_OUT_VOL); if (event & SND_SOC_DAPM_PRE_REG) return 0; if (l & 0x1 || r & 0x1) rt5624_write(w->codec, RT5624_VOICE_DAC_OUT_VOL, voice & 0x7fff); else rt5624_write(w->codec, RT5624_VOICE_DAC_OUT_VOL, voice | 0x8000); if (l & 0x2 || r & 0x2) rt5624_write(w->codec, RT5624_STEREO_DAC_VOL, pcm & 0x7fff); else rt5624_write(w->codec, RT5624_STEREO_DAC_VOL, pcm | 0x8000); if (l & 0x4 || r & 0x4) rt5624_write(w->codec, RT5624_MIC_ROUTING_CTRL, mic2 & 0xff7f); else rt5624_write(w->codec, RT5624_MIC_ROUTING_CTRL, mic2 | 0x0080); if (l & 0x8 || r & 0x8) rt5624_write(w->codec, RT5624_MIC_ROUTING_CTRL, mic1 & 0x7fff); else rt5624_write(w->codec, RT5624_MIC_ROUTING_CTRL, mic1 | 0x8000); if (l & 0x10 || r & 0x10) rt5624_write(w->codec, RT5624_PHONEIN_MONO_OUT_VOL, phone & 0x7fff); else rt5624_write(w->codec, RT5624_PHONEIN_MONO_OUT_VOL, phone | 0x8000); if (l & 0x20 || r & 0x20) rt5624_write(w->codec, RT5624_LINE_IN_VOL, lineIn & 0x7fff); else rt5624_write(w->codec, RT5624_LINE_IN_VOL, lineIn | 0x8000); return 0; } /* Left Headphone Mixers */ static const struct snd_kcontrol_new rt5624_hpl_mixer_controls[] = { SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 5, 1, 0), SOC_DAPM_SINGLE("PhoneIn Playback Switch", HPL_MIXER, 4, 1, 0), SOC_DAPM_SINGLE("Mic1 Playback Switch", HPL_MIXER, 3, 1, 0), SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 2, 1, 0), SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 0, 1, 0), SOC_DAPM_SINGLE("RecordL Playback Switch", RT5624_ADC_REC_GAIN, 15, 1,1), }; /* Right Headphone Mixers */ static const struct snd_kcontrol_new rt5624_hpr_mixer_controls[] = { SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 5, 1, 0), SOC_DAPM_SINGLE("PhoneIn Playback Switch", HPR_MIXER, 4, 1, 0), SOC_DAPM_SINGLE("Mic1 Playback Switch", HPR_MIXER, 3, 1, 0), SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 2, 1, 0), SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 0, 1, 0), SOC_DAPM_SINGLE("RecordR Playback Switch", RT5624_ADC_REC_GAIN, 14, 1,1), }; //Left Record Mixer static const struct snd_kcontrol_new rt5624_captureL_mixer_controls[] = { SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5624_ADC_REC_MIXER, 14, 1, 1), SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5624_ADC_REC_MIXER, 13, 1, 1), SOC_DAPM_SINGLE("LineInL Capture Switch",RT5624_ADC_REC_MIXER,12, 1, 1), SOC_DAPM_SINGLE("Phone Capture Switch", RT5624_ADC_REC_MIXER, 11, 1, 1), SOC_DAPM_SINGLE("HPMixerL Capture Switch", RT5624_ADC_REC_MIXER,10, 1, 1), SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5624_ADC_REC_MIXER,9, 1, 1), SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5624_ADC_REC_MIXER,8, 1, 1), }; //Right Record Mixer static const struct snd_kcontrol_new rt5624_captureR_mixer_controls[] = { SOC_DAPM_SINGLE("Mic1 Capture Switch", RT5624_ADC_REC_MIXER, 6, 1, 1), SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5624_ADC_REC_MIXER, 5, 1, 1), SOC_DAPM_SINGLE("LineInR Capture Switch",RT5624_ADC_REC_MIXER,4, 1, 1), SOC_DAPM_SINGLE("Phone Capture Switch", RT5624_ADC_REC_MIXER, 3, 1, 1), SOC_DAPM_SINGLE("HPMixer Capture Switch", RT5624_ADC_REC_MIXER,2, 1, 1), SOC_DAPM_SINGLE("SPKMixer Capture Switch",RT5624_ADC_REC_MIXER,1, 1, 1), SOC_DAPM_SINGLE("MonoMixer Capture Switch",RT5624_ADC_REC_MIXER,0, 1, 1), }; /* Speaker Mixer */ static const struct snd_kcontrol_new rt5624_speaker_mixer_controls[] = { SOC_DAPM_SINGLE("LineIn Playback Switch", RT5624_LINE_IN_VOL, 14, 1, 1), SOC_DAPM_SINGLE("PhoneIn Playback Switch", RT5624_PHONEIN_MONO_OUT_VOL, 14, 1, 1), SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5624_MIC_ROUTING_CTRL, 14, 1, 1), SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5624_MIC_ROUTING_CTRL, 6, 1, 1), SOC_DAPM_SINGLE("PCM Playback Switch", RT5624_STEREO_DAC_VOL, 14, 1, 1), SOC_DAPM_SINGLE("Voice Playback Switch", RT5624_VOICE_DAC_OUT_VOL, 14, 1, 1), }; /* Mono Mixer */ static const struct snd_kcontrol_new rt5624_mono_mixer_controls[] = { SOC_DAPM_SINGLE("LineIn Playback Switch", RT5624_LINE_IN_VOL, 13, 1, 1), SOC_DAPM_SINGLE("Mic1 Playback Switch", RT5624_MIC_ROUTING_CTRL, 13, 1, 1), SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5624_MIC_ROUTING_CTRL, 5, 1, 1), SOC_DAPM_SINGLE("PCM Playback Switch", RT5624_STEREO_DAC_VOL, 13, 1, 1), SOC_DAPM_SINGLE("RecL Playback Switch", RT5624_ADC_REC_GAIN, 13, 1, 1), SOC_DAPM_SINGLE("RecR Playback Switch", RT5624_ADC_REC_GAIN, 12, 1, 1), SOC_DAPM_SINGLE("Voice Playback Switch", RT5624_VOICE_DAC_OUT_VOL, 13, 1, 1), SOC_DAPM_SINGLE("RecordL Playback Switch", RT5624_ADC_REC_GAIN, 13, 1,1), SOC_DAPM_SINGLE("RecordR Playback Switch", RT5624_ADC_REC_GAIN, 12, 1,1), }; /* mono output mux */ static const struct snd_kcontrol_new rt5624_mono_mux_controls = SOC_DAPM_ENUM("Route", rt5624_enum[4]); /* speaker left output mux */ static const struct snd_kcontrol_new rt5624_hp_spkl_mux_controls = SOC_DAPM_ENUM("Route", rt5624_enum[0]); /* speaker right output mux */ static const struct snd_kcontrol_new rt5624_hp_spkr_mux_controls = SOC_DAPM_ENUM("Route", rt5624_enum[1]); /* headphone left output mux */ static const struct snd_kcontrol_new rt5624_hpl_out_mux_controls = SOC_DAPM_ENUM("Route", rt5624_enum[2]); /* headphone right output mux */ static const struct snd_kcontrol_new rt5624_hpr_out_mux_controls = SOC_DAPM_ENUM("Route", rt5624_enum[3]); static const struct snd_soc_dapm_widget rt5624_dapm_widgets[] = { SND_SOC_DAPM_MUX("Mono Out Mux", SND_SOC_NOPM, 0, 0, &rt5624_mono_mux_controls), SND_SOC_DAPM_MUX("Left Speaker Out Mux", SND_SOC_NOPM, 0, 0, &rt5624_hp_spkl_mux_controls), SND_SOC_DAPM_MUX("Right Speaker Out Mux", SND_SOC_NOPM, 0, 0, &rt5624_hp_spkr_mux_controls), SND_SOC_DAPM_MUX("Left Headphone Out Mux", SND_SOC_NOPM, 0, 0, &rt5624_hpl_out_mux_controls), SND_SOC_DAPM_MUX("Right Headphone Out Mux", SND_SOC_NOPM, 0, 0, &rt5624_hpr_out_mux_controls), SND_SOC_DAPM_MIXER_E("Left HP Mixer",RT5624_PWR_MANAG_ADD2, 5, 0, &rt5624_hpl_mixer_controls[0], ARRAY_SIZE(rt5624_hpl_mixer_controls), mixer_event, SND_SOC_DAPM_POST_REG), SND_SOC_DAPM_MIXER_E("Right HP Mixer",RT5624_PWR_MANAG_ADD2, 4, 0, &rt5624_hpr_mixer_controls[0], ARRAY_SIZE(rt5624_hpr_mixer_controls), mixer_event, SND_SOC_DAPM_POST_REG), SND_SOC_DAPM_MIXER("Mono Mixer", RT5624_PWR_MANAG_ADD2, 2, 0, &rt5624_mono_mixer_controls[0], ARRAY_SIZE(rt5624_mono_mixer_controls)), SND_SOC_DAPM_MIXER("Speaker Mixer", RT5624_PWR_MANAG_ADD2,3,0, &rt5624_speaker_mixer_controls[0], ARRAY_SIZE(rt5624_speaker_mixer_controls)), SND_SOC_DAPM_MIXER("Left Record Mixer", RT5624_PWR_MANAG_ADD2,1,0, &rt5624_captureL_mixer_controls[0], ARRAY_SIZE(rt5624_captureL_mixer_controls)), SND_SOC_DAPM_MIXER("Right Record Mixer", RT5624_PWR_MANAG_ADD2,0,0, &rt5624_captureR_mixer_controls[0], ARRAY_SIZE(rt5624_captureR_mixer_controls)), SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback", RT5624_PWR_MANAG_ADD2,9, 0), SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback", RT5624_PWR_MANAG_ADD2, 8, 0), SND_SOC_DAPM_MIXER("IIS Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER("HP Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_ADC("Left ADC", "Left HiFi Capture", RT5624_PWR_MANAG_ADD2, 7, 0), SND_SOC_DAPM_ADC("Right ADC", "Right HiFi Capture", RT5624_PWR_MANAG_ADD2, 6, 0), SND_SOC_DAPM_PGA("Left Headphone", RT5624_PWR_MANAG_ADD3, 11, 1, NULL, 0), SND_SOC_DAPM_PGA("Right Headphone", RT5624_PWR_MANAG_ADD3, 10, 1, NULL, 0), SND_SOC_DAPM_PGA("Left Speaker", RT5624_PWR_MANAG_ADD3, 8, 1, NULL, 0), SND_SOC_DAPM_PGA("Right Speaker", RT5624_PWR_MANAG_ADD3, 7, 1, NULL, 0), SND_SOC_DAPM_PGA("Mono Out", RT5624_PWR_MANAG_ADD3, 13, 1, NULL, 0), SND_SOC_DAPM_PGA("Left Line In", RT5624_PWR_MANAG_ADD3, 6, 1, NULL, 0), SND_SOC_DAPM_PGA("Right Line In", RT5624_PWR_MANAG_ADD3, 5, 1, NULL, 0), SND_SOC_DAPM_PGA("Phone In PGA", RT5624_PWR_MANAG_ADD3, 4, 1, NULL, 0), SND_SOC_DAPM_PGA("Phone In Mixer", RT5624_PWR_MANAG_ADD3, 5, 1, NULL, 0), SND_SOC_DAPM_PGA("Mic 1 PGA", RT5624_PWR_MANAG_ADD3, 3, 1, NULL, 0), SND_SOC_DAPM_PGA("Mic 2 PGA", RT5624_PWR_MANAG_ADD3, 2, 1, NULL, 0), SND_SOC_DAPM_PGA("Mic 1 Pre Amp", RT5624_PWR_MANAG_ADD3, 1, 1, NULL, 0), SND_SOC_DAPM_PGA("Mic 2 Pre Amp", RT5624_PWR_MANAG_ADD3, 0, 1, NULL, 0), SND_SOC_DAPM_MICBIAS("Mic Bias1", RT5624_PWR_MANAG_ADD1, 3, 0), SND_SOC_DAPM_MICBIAS("Mic Bias2", RT5624_PWR_MANAG_ADD1, 2, 0), SND_SOC_DAPM_OUTPUT("MONO"), SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), SND_SOC_DAPM_OUTPUT("SPKL"), SND_SOC_DAPM_OUTPUT("SPKR"), SND_SOC_DAPM_INPUT("LINEL"), SND_SOC_DAPM_INPUT("LINER"), SND_SOC_DAPM_INPUT("PHONEIN"), SND_SOC_DAPM_INPUT("MIC1"), SND_SOC_DAPM_INPUT("MIC2"), SND_SOC_DAPM_INPUT("PCMIN"), SND_SOC_DAPM_VMID("VMID"), }; static const char *audio_map[][3] = { /* left HP mixer */ {"Left HP Mixer", "LineIn Playback Switch", "LINEL"}, {"Left HP Mixer", "PhoneIn Playback Switch","PHONEIN"}, {"Left HP Mixer", "Mic1 Playback Switch","MIC1"}, {"Left HP Mixer", "Mic2 Playback Switch","MIC2"}, {"Left HP Mixer", "PCM Playback Switch","Left DAC"}, {"Left HP Mixer", "Voice Playback Switch","Voice DAC"}, {"Left HP Mixer", "RecordL Playback Switch","Left Record Mixer"}, /* right HP mixer */ {"Right HP Mixer", "LineIn Playback Switch", "LINER"}, {"Right HP Mixer", "PhoneIn Playback Switch","PHONEIN"}, {"Right HP Mixer", "Mic1 Playback Switch","MIC1"}, {"Right HP Mixer", "Mic2 Playback Switch","MIC2"}, {"Right HP Mixer", "PCM Playback Switch","Right DAC"}, {"Right HP Mixer", "Voice Playback Switch","Voice DAC"}, {"Right HP Mixer", "RecordR Playback Switch","Right Record Mixer"}, /* virtual mixer - mixes left & right channels for spk and mono */ {"IIS Mixer", NULL, "Left DAC"}, {"IIS Mixer", NULL, "Right DAC"}, {"Line Mixer", NULL, "Right Line In"}, {"Line Mixer", NULL, "Left Line In"}, {"HP Mixer", NULL, "Left HP Mixer"}, {"HP Mixer", NULL, "Right HP Mixer"}, /* speaker mixer */ {"Speaker Mixer", "LineIn Playback Switch","Line Mixer"}, {"Speaker Mixer", "PhoneIn Playback Switch","PHONEIN"}, {"Speaker Mixer", "Mic1 Playback Switch","MIC1"}, {"Speaker Mixer", "Mic2 Playback Switch","MIC2"}, {"Speaker Mixer", "PCM Playback Switch","IIS Mixer"}, {"Speaker Mixer", "Voice Playback Switch","Voice DAC"}, /* mono mixer */ {"Mono Mixer", "LineIn Playback Switch","Line Mixer"}, {"Mono Mixer", "PhoneIn Playback Switch","PHONEIN"}, {"Mono Mixer", "Mic1 Playback Switch","MIC1"}, {"Mono Mixer", "Mic2 Playback Switch","MIC2"}, {"Mono Mixer", "PCM Playback Switch","IIS Mixer"}, {"Mono Mixer", "Voice Playback Switch","Voice DAC"}, {"Mono Mixer", "RecordL Playback Switch","Left Record Mixer"}, {"Mono Mixer", "RecordR Playback Switch","Right Record Mixer"}, /*Left record mixer */ {"Left Record Mixer", "Mic1 Capture Switch","Mic 1 Pre Amp"}, {"Left Record Mixer", "Mic2 Capture Switch","Mic 2 Pre Amp"}, {"Left Record Mixer", "LineInL Capture Switch","LINEL"}, {"Left Record Mixer", "Phone Capture Switch","PHONEIN"}, {"Left Record Mixer", "HPMixerL Capture Switch","Left HP Mixer"}, {"Left Record Mixer", "SPKMixer Capture Switch","Speaker Mixer"}, {"Left Record Mixer", "MonoMixer Capture Switch","Mono Mixer"}, /*Right record mixer */ {"Right Record Mixer", "Mic1 Capture Switch","Mic 1 Pre Amp"}, {"Right Record Mixer", "Mic2 Capture Switch","Mic 2 Pre Amp"}, {"Right Record Mixer", "LineInR Capture Switch","LINER"}, {"Right Record Mixer", "Phone Capture Switch","PHONEIN"}, {"Right Record Mixer", "HPMixerR Capture Switch","Right HP Mixer"}, {"Right Record Mixer", "SPKMixer Capture Switch","Speaker Mixer"}, {"Right Record Mixer", "MonoMixer Capture Switch","Mono Mixer"}, /* headphone left mux */ {"Left Headphone Out Mux", "HPL mixer", "Left HP Mixer"}, /* headphone right mux */ {"Right Headphone Out Mux", "HPR mixer", "Right HP Mixer"}, /* speaker left mux */ {"Left Speaker Out Mux", "HPL mixer", "Left HP Mixer"}, {"Left Speaker Out Mux", "SPK mixer", "Speaker Mixer"}, {"Left Speaker Out Mux", "Mono Mixer", "Mono Mixer"}, /* speaker right mux */ {"Right Speaker Out Mux", "HPR mixer", "Right HP Mixer"}, {"Right Speaker Out Mux", "SPK mixer", "Speaker Mixer"}, {"Right Speaker Out Mux", "Mono Mixer", "Mono Mixer"}, /* mono mux */ {"Mono Out Mux", "HP mixer", "HP Mixer"}, {"Mono Out Mux", "SPK mixer", "Speaker Mixer"}, {"Mono Out Mux", "Mono Mixer", "Mono Mixer"}, /* output pga */ {"HPL", NULL, "Left Headphone"}, {"Left Headphone", NULL, "Left Headphone Out Mux"}, {"HPR", NULL, "Right Headphone"}, {"Right Headphone", NULL, "Right Headphone Out Mux"}, {"SPKL", NULL, "Left Speaker"}, {"Left Speaker", NULL, "Left Speaker Out Mux"}, {"SPKR", NULL, "Right Speaker"}, {"Right Speaker", NULL, "Right Speaker Out Mux"}, {"MONO", NULL, "Mono Out"}, {"Mono Out", NULL, "Mono Out Mux"}, /* input pga */ {"Left Line In", NULL, "LINEL"}, {"Right Line In", NULL, "LINER"}, {"Phone In PGA", NULL, "PHONEIN"}, {"Phone In Mixer", NULL, "PHONEIN"}, {"Mic 1 Pre Amp", NULL, "MIC1"}, {"Mic 2 Pre Amp", NULL, "MIC2"}, {"Mic 1 PGA", NULL, "Mic 1 Pre Amp"}, {"Mic 2 PGA", NULL, "Mic 2 Pre Amp"}, /* left ADC */ {"Left ADC", NULL, "Left Record Mixer"}, /* right ADC */ {"Right ADC", NULL, "Right Record Mixer"}, {NULL, NULL, NULL}, }; static int rt5624_add_widgets(struct snd_soc_codec *codec) { printk("[kit]: rt5624_add_widgets()\n"); int i; // for (i = 0; i < ARRAY_SIZE(rt5624_dapm_widgets); i++) // snd_soc_dapm_new_control(codec, &rt5624_dapm_widgets[i]); /* set up the RT5624 audio map */ for (i = 0; audio_map[i][0] != NULL; i++) { snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1], audio_map[i][2]); } snd_soc_dapm_new_widgets(codec); return 0; } /* PLL divisors */ struct _pll_div { u32 pll_in; u32 pll_out; u16 regvalue; }; static const struct _pll_div codec_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}, }; static int rt5624_set_dai_pll(struct snd_soc_codec_dai *codec_dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { printk("[kit]: rt5624_set_dai_pll()\n"); int i; struct snd_soc_codec *codec = codec_dai->codec; rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2, 0x0000,0x1000); //disable PLL power if (!freq_in || !freq_out) { return 0; } for (i = 0; i < ARRAY_SIZE(codec_pll_div); i++) { if (codec_pll_div[i].pll_in == freq_in && codec_pll_div[i].pll_out == freq_out) { rt5624_write(codec,RT5624_PLL_CTRL,codec_pll_div[i].regvalue);//set PLL parameter rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD2, 0x1000,0x1000); //enable PLL power rt5624_write_mask(codec,RT5624_GEN_CTRL_REG1,0x8000,0x8000);//Codec sys-clock from PLL break; } } return 0; } struct _coeff_div { u32 mclk; u32 rate; u16 fs; u16 regvalue1; u16 regvalue2; }; /* codec hifi mclk (after PLL) clock divider coefficients */ static const struct _coeff_div coeff_div[] = { /* 8k */ { 8192000, 8000, 256*4, 0x3272,0x1212}, {12288000, 8000, 384*4, 0x5272,0x2222}, /* 11.025k */ {11289600, 11025, 256*4, 0x3272,0x1212}, {16934400, 11025, 384*4, 0x5272,0x2222}, /* 16k */ {12288000, 16000, 384*2, 0x2272,0x2020}, {16384000, 16000, 256*4, 0x3272,0x1212}, {24576000, 16000, 384*4, 0x5272,0x2222}, /* 22.05k */ {11289600, 22050, 256*2, 0x3172,0x1010}, {16934400, 22050, 384*2, 0x2272,0x2020}, /* 32k */ {12288000, 32000, 384*2, 0x2172,0x2121}, {16384000, 32000, 256*2, 0x3172,0x1010}, {24576000, 32000, 384*2, 0x2272,0x2020}, /* 44.1k */ {11289600, 44100, 256*1, 0x3072,0x0000}, {22579200, 44100, 256*2, 0x3172,0x1010}, /* 48k */ {12288000, 48000, 256*1, 0x3072,0x0000}, {24576000, 48000, 256*2, 0x3172,0x1010}, }; static int get_coeff(int mclk, int rate) { printk("[kit]: get_coeff()\n"); int i; printk("get_coeff mclk=%d,rate=%d\n",mclk,rate); for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) return i; } return -EINVAL; } /* * Clock after PLL and dividers */ static int rt5624_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, int clk_id, unsigned int freq, int dir) { printk("[kit]: rt5624_set_dai_sysclk()\n"); struct snd_soc_codec *codec = codec_dai->codec; struct rt5624_priv *rt5624 = codec->private_data; printk("[HIKO RT5624]Entered %s : clk_id = %d, freq = %d\n", __FUNCTION__, clk_id, freq); switch (freq) { case 8192000: case 11289600: case 12288000: case 16384000: case 16934400: case 18432000: case 22579200: case 24576000: rt5624->sysclk = freq; return 0; } return -EINVAL; } static int rt5624_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, unsigned int fmt) { printk("[kit]: rt5624_set_dai_fmt()\n"); struct snd_soc_codec *codec = codec_dai->codec; u16 iface = 0; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: iface = 0x0000; break; case SND_SOC_DAIFMT_CBS_CFS: iface = 0x8000; break; default: return -EINVAL; } /* interface format */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: iface |= 0x0000; break; case SND_SOC_DAIFMT_RIGHT_J: iface |= 0x0001; break; case SND_SOC_DAIFMT_LEFT_J: iface |= 0x0002; break; case SND_SOC_DAIFMT_DSP_A: iface |= 0x0003; break; case SND_SOC_DAIFMT_DSP_B: iface |= 0x0043; break; default: return -EINVAL; } /* clock inversion */ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: iface |= 0x0000; break; case SND_SOC_DAIFMT_IB_IF: iface |= 0x1040; break; case SND_SOC_DAIFMT_IB_NF: iface |= 0x1000; break; case SND_SOC_DAIFMT_NB_IF: iface |= 0x0040; break; default: return -EINVAL; } rt5624_write_mask(codec,RT5624_MAIN_SDP_CTRL,iface,0x9043); return 0; } static int rt5624_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { printk("[kit]: rt5624_pcm_hw_params()\n"); struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct rt5624_priv *rt5624 = codec->private_data; u16 iface=rt5624_read(codec,RT5624_MAIN_SDP_CTRL)&0xfff3; int coeff = get_coeff(rt5624->sysclk, params_rate(params)); printk("rt5624_pcm_hw_params\n"); /* bit size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: iface |= 0x0000; break; case SNDRV_PCM_FORMAT_S20_3LE: iface |= 0x0004; break; case SNDRV_PCM_FORMAT_S24_LE: iface |= 0x0008; break; case SNDRV_PCM_FORMAT_S32_LE: iface |= 0x000c; break; } /* set iface & srate */ rt5624_write(codec, RT5624_MAIN_SDP_CTRL, iface); if (coeff >= 0) { rt5624_write(codec, RT5624_STEREO_DAC_CLK_CTRL1,coeff_div[coeff].regvalue1); rt5624_write(codec, RT5624_STEREO_DAC_CLK_CTRL2,coeff_div[coeff].regvalue2); } return 0; } static void audio_realtime_headset_type_setting() { printk("[kit]: audio_realtime_headset_type_setting()\n"); unsigned long data; struct snd_soc_codec *codec = GetRt5624CodecData(); printk("\n===[HIKO RT5624]HEADSET TYPE REALTIME SETTING===\n"); //Rewrite the Reg0C STEREO DAC Volume // data = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~(0x1F<<8) & ~0x1F; // data |= ((0x08<<8) | 0x08); // rt5624_write(codec, RT5624_STEREO_DAC_VOL, data); #if defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_E600_DVT1) #else //Rewrite the POWER MANAGEMENT ADDITION 2 data = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); data = data & ~(0x01<<3); rt5624_write(codec, RT5624_PWR_MANAG_ADD2, data); #endif // data = rt5624_read(codec, RT5624_STEREO_DAC_CLK_CTRL2) & ~(0x1000); // data |= (0x2000); // rt5624_write(codec, RT5624_STEREO_DAC_CLK_CTRL2, data); /* //Rewrite the RT5624_OUTPUT_MIXER_CTRL data = rt5624_read(codec, RT5624_OUTPUT_MIXER_CTRL); data = 0x2300; rt5624_write(codec, RT5624_OUTPUT_MIXER_CTRL, data); */ //[HIKO] Original #if 0 //Rewrite the POWER MANAGEMENT ADDITION 2 data = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); data = data & ~(0x01<<3); rt5624_write(codec, RT5624_PWR_MANAG_ADD2, data); //[HIKO] Realtek Charles suggestion for CPU Master mode #elif 1 data = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); data = 0x7338; rt5624_write(codec, RT5624_PWR_MANAG_ADD2, data); data = rt5624_read(codec, RT5624_GEN_CTRL_REG1); data = 0x84C8; rt5624_write(codec, RT5624_GEN_CTRL_REG1, data); data = rt5624_read(codec, RT5624_GEN_CTRL_REG2); data = 0x4000; rt5624_write(codec, RT5624_GEN_CTRL_REG2, data); data = rt5624_read(codec, RT5624_PLL_CTRL); data = 0x2E90; rt5624_write(codec, RT5624_PLL_CTRL, data); data = rt5624_read(codec, RT5624_MAIN_SDP_CTRL); data |= 0x8000; rt5624_write(codec, RT5624_MAIN_SDP_CTRL, data); //[HIKO] Realtek Charles suggestion for CPU Slave mode #elif 0 //Rewrite the POWER MANAGEMENT ADDITION 2 data = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); data = data & ~(0x01<<3); rt5624_write(codec, RT5624_PWR_MANAG_ADD2, data); //Slave mode data = rt5624_read(codec, RT5624_MAIN_SDP_CTRL); data = 0x0000; rt5624_write(codec, RT5624_MAIN_SDP_CTRL, data); data = rt5624_read(codec, RT5624_GEN_CTRL_REG1); data = 0x84c8; rt5624_write(codec, RT5624_GEN_CTRL_REG1, data); #endif } static void audio_realtime_board_type_setting() { printk("[kit]: audio_realtime_board_type_setting()\n"); unsigned long data; struct snd_soc_codec *codec = GetRt5624CodecData(); printk("\n===[HIKO RT5624]BOARD TYPE REALTIME SETTING===\n"); //Rewrite the Reg0C STEREO DAC Volume //(Board Side Loud Speaker type must been degrated, becaused it is singld end, and using SPK_OUT_L pin) // data = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~(0x1F<<8) & ~0x1F; // data |= ((0x0A<<8) | 0x0A); // rt5624_write(codec, RT5624_STEREO_DAC_VOL, data); // data = rt5624_read(codec, RT5624_STEREO_DAC_CLK_CTRL2) & ~(0x1000); // data |= (0x2000); // rt5624_write(codec, RT5624_STEREO_DAC_CLK_CTRL2, data); /* //Rewrite the RT5624_OUTPUT_MIXER_CTRL data = rt5624_read(codec, RT5624_OUTPUT_MIXER_CTRL); // data = 0xB000; data = 0x2300; rt5624_write(codec, RT5624_OUTPUT_MIXER_CTRL, data); */ //[HIKO] Original #if 0 //Rewrite the POWER MANAGEMENT ADDITION 2 data = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); data = data | (0x01<<3); rt5624_write(codec, RT5624_PWR_MANAG_ADD2, data); //[HIKO] Realtek Charles suggestion for CPU Master mode #elif 1 data = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); data = 0x7338; rt5624_write(codec, RT5624_PWR_MANAG_ADD2, data); data = rt5624_read(codec, RT5624_GEN_CTRL_REG1); data = 0x84C8; rt5624_write(codec, RT5624_GEN_CTRL_REG1, data); data = rt5624_read(codec, RT5624_GEN_CTRL_REG2); data = 0x4000; rt5624_write(codec, RT5624_GEN_CTRL_REG2, data); data = rt5624_read(codec, RT5624_PLL_CTRL); data = 0x2E90; rt5624_write(codec, RT5624_PLL_CTRL, data); data = rt5624_read(codec, RT5624_MAIN_SDP_CTRL); data |= 0x8000; rt5624_write(codec, RT5624_MAIN_SDP_CTRL, data); //[HIKO] Realtek Charles suggestion for CPU Slave mode #elif 0 //Rewrite the POWER MANAGEMENT ADDITION 2 data = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); data = data | (0x01<<3); rt5624_write(codec, RT5624_PWR_MANAG_ADD2, data); //Slave mode data = rt5624_read(codec, RT5624_MAIN_SDP_CTRL); data = 0x0000; rt5624_write(codec, RT5624_MAIN_SDP_CTRL, data); data = rt5624_read(codec, RT5624_GEN_CTRL_REG1); data = 0x84c8; rt5624_write(codec, RT5624_GEN_CTRL_REG1, data); #endif } //Default Register Setting static void audio_realtime_setting() { printk("[kit]: audio_realtime_setting()\n"); switch (g_snd_out_path) { case SND_OUT_PATH_SPEAKER: audio_realtime_board_type_setting(); break; case SND_OUT_PATH_HEADSET: audio_realtime_headset_type_setting(); break; } //setup the volume restore_volume(); //do not use this way, this must be configured in smdk2416-rt5624.c //or this would be side effect that LRCK failured in abnormal output // reset_realtime_clk_div_dep_on_flag(); //HIKO DEBUG // print_codec_regs(); // s3c_i2s_set_iispcr_clkdiv_rt5624(5); } static int rt5624_pcm_hw_trigger(struct snd_pcm_substream *substream,int cmd) { printk("[kit]: rt5624_pcm_hw_trigger()\n"); // struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; int ret = 0; printk("[HIKO rt5624] rt5624_pcm_hw_trigger()\n"); switch (cmd) { case SNDRV_PCM_TRIGGER_START: printk("[HIKO rt5624] SNDRV_PCM_TRIGGER_START substream->stream==%d \n", substream->stream); if(substream->stream==SNDRV_PCM_STREAM_PLAYBACK) { rt5624_ChangeCodecPowerStatus(codec,POWER_STATE_D1_PLAYBACK); // rt5624_AudioOutEnable(codec,RT_WAVOUT_SPK,0); // rt5624_AudioOutEnable(codec,RT_WAVOUT_HP,0); set_audio_out_path_dep_on_headset_jack(); msleep(600);//flove012710 rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,PWR_HI_R_LOAD_HP,PWR_HI_R_LOAD_HP); //flove012710 } else { #if defined(CONFIG_QISDA_AS090B00_EVT1)||defined(CONFIG_QISDA_AS090B00_EVT1_1) || defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_QD090B00_EVT1) || defined(CONFIG_QISDA_E600_DVT1) //Enable_ADC_Input_Source(codec,RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,1); rt5624_mic_setup(set_audio_in_path_dep_on_headset_jack()); //set_audio_in_path_dep_on_out_variable(); printk("[HIKO rt5624] AS090B00 MIC Gain Setting\n"); //rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,0,PWR_MIC_BIAS1); // rt5624_write(codec, RT5624_MIC_VOL, 0x0080/*0x0808*/); // rt5624_write(codec, RT5624_MIC_ROUTING_CTRL, 0xE0E0); //rt5624_write(codec, RT5624_ADC_REC_GAIN, 0xF58B); /// rt5624_write(codec, RT5624_ADC_REC_GAIN, 0xF58B | 0x1F<<7 | 0x1F); // rt5624_write(codec, RT5624_ADC_REC_GAIN, 0xF58B | 0x0F<<7 | 0x0F); // rt5624_write(codec, RT5624_MIC_CTRL, 0x0F00/*0x0000*/); // rt5624_write(codec, RT5624_ADC_REC_MIXER, 0x3F3F/*0x7F7F*/); #endif //CONFIG_QISDA_AS090B00_EVT1 rt5624_ChangeCodecPowerStatus(codec,POWER_STATE_D1_RECORD); } //HIKO DEBUG //print_codec_regs(); audio_realtime_setting(); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: break; case SNDRV_PCM_TRIGGER_RESUME: break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: break; default: ret = -EINVAL; } return ret; } static int rt5624_mute(struct snd_soc_codec_dai *dai, int mute) { printk("[kit]: rt5624_mute()\n"); struct snd_soc_codec *codec = dai->codec; printk("[HIKO RT5624]rt5624_mute(0x%X)\n", mute); u16 mute_reg = rt5624_read(codec, RT5624_MISC_CTRL) & 0xfff3; #if 0 if (mute) { rt5624_write(codec, RT5624_MISC_CTRL, mute_reg | 0xc); } else { rt5624_write(codec, RT5624_MISC_CTRL, mute_reg); } #else if (mute) { rt5624_write(codec, RT5624_MISC_CTRL, (rt5624_read(codec, RT5624_MISC_CTRL) | (0x3<<5))); } else { rt5624_write(codec, RT5624_MISC_CTRL, (rt5624_read(codec, RT5624_MISC_CTRL) & ~(0x3<<5))); } #endif //0 return 0; } static int rt5624_dapm_event(struct snd_soc_codec *codec, int event) { printk("[kit]: rt5624_dapm_event()\n"); switch (event) { case SNDRV_CTL_POWER_D0: /* full On */ printk("rt5624_dapm_event_POWER_D0\n"); break; case SNDRV_CTL_POWER_D1: /* partial On */ printk("rt5624_dapm_event_POWER_D1\n"); break; case SNDRV_CTL_POWER_D2: /* partial On */ printk("rt5624_dapm_event_POWER_D2\n"); break; case SNDRV_CTL_POWER_D3hot: /* Off, with power */ printk("rt5624_dapm_event_POWER_D3\n"); rt5624_write_mask(codec,RT5624_PWR_MANAG_ADD1,0,PWR_HI_R_LOAD_HP); //flove012710 rt5624_write_mask(codec,RT5624_HP_OUT_VOL,0x8080,0x8080); //flove012710 //HIKO: after played music, turn off some codec voltage for power consumption rt5624_ChangeCodecPowerStatus(GetRt5624CodecData(), POWER_STATE_D2); break; case SNDRV_CTL_POWER_D3cold: /* Off, without power */ printk("rt5624_dapm_event_POWER_D4\n"); break; } codec->dapm_state = event; return 0; } #define RT5624_RATES SNDRV_PCM_RATE_48000 #define RT5624_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) struct snd_soc_codec_dai rt5624_dai = { .name = "RT5624", .playback = { .stream_name = "Playback", .channels_min = 1, .channels_max = 2, .rates = RT5624_RATES, .formats = RT5624_FORMATS,}, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 2, .rates = RT5624_RATES, .formats = RT5624_FORMATS,}, .ops = { .hw_params = rt5624_pcm_hw_params, .trigger = rt5624_pcm_hw_trigger, }, .dai_ops = { .digital_mute = rt5624_mute, .set_fmt = rt5624_set_dai_fmt, .set_sysclk = rt5624_set_dai_sysclk, .set_pll = rt5624_set_dai_pll, }, }; EXPORT_SYMBOL_GPL(rt5624_dai); static void rt5624_work(struct work_struct *work) { printk("[kit]: rt5624_work()\n"); struct snd_soc_codec *codec = container_of(work, struct snd_soc_codec, delayed_work.work); rt5624_dapm_event(codec, codec->dapm_state); } static int rt5624_suspend(struct platform_device *pdev, pm_message_t state) { printk("[kit]: rt5624_suspend()\n"); struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; /* we only need to suspend if we are a valid card */ if(!codec->card) return 0; rt5624_dapm_event(codec, SNDRV_CTL_POWER_D3cold); //HIKO: for RT5624 audio power management process { rt5624_power(false); rt5624_i2s_release(); // rt5624_audio_reset_off(); // mdelay(10); printk("[HIKO RT5624] power source OFF!"); //HIKO: for RT5624 audio power management process } return 0; } static int rt5624_resume(struct platform_device *pdev) { printk("[kit]: rt5624_resume()\n"); struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; int i; u8 data[3]; u16 *cache = codec->reg_cache; //HIKO: for RT5624 audio power management process { rt5624_i2s_init(); mdelay(10); rt5624_power(true); //Reinit the CODEC using Audio Reset pin rt5624_audio_reset_off(); mdelay(1); rt5624_audio_reset_on(); printk("\n[HIKO RT5624] power source ON!\n"); //HIKO: for RT5624 audio power management process } /* we only need to resume if we are a valid card */ if(!codec->card) { printk("\n=========[HIKO RT5624] ERROR! RT5624 codec index NOT EXIST!=========\n"); return 0; } /* Sync reg_cache with the hardware */ /* for (i = 0; i < ARRAY_SIZE(rt5624_reg); i++) { if (i == RT5624_RESET) continue; data[0] =i*2; data[1] = (0xFF00 & cache[i]) >> 8; data[2] = 0x00FF & cache[i]; codec->hw_write(codec->control_data, data, 3); } */ //If less then 10ms, the I2C would be unstable // we take 30ms for make sure that above Audio Interface was done! mdelay(30); rt5624_reset(codec); mdelay(1); rt5624_write(codec, RT5624_PD_CTRL_STAT, 0x0000);//enable all PR bit rt5624_write(codec, RT5624_PWR_MANAG_ADD3, 0x8000);//enable Main bias rt5624_write(codec, RT5624_PWR_MANAG_ADD2, 0x2000);//enable Vref for(i=0;isuspend_dapm_state == SNDRV_CTL_POWER_D0) { rt5624_dapm_event(codec, SNDRV_CTL_POWER_D2); codec->dapm_state = SNDRV_CTL_POWER_D0; schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(caps_charge)); } return 0; } /* * initialise the RT5624 driver * register the mixer and dsp interfaces with the kernel */ static int rt5624_init(struct snd_soc_device *socdev) { printk("[kit]: rt5624_init()\n"); struct snd_soc_codec *codec = socdev->codec; int ret = 0,i=0; u16 u16value; codec->name = "RT5624"; codec->owner = THIS_MODULE; codec->read = rt5624_read; codec->write = rt5624_write; codec->dapm_event = rt5624_dapm_event; codec->dai = &rt5624_dai; codec->num_dai = 1; codec->reg_cache_size = sizeof(rt5624_reg); codec->reg_cache = kmemdup(rt5624_reg, sizeof(rt5624_reg), GFP_KERNEL); if (codec->reg_cache == NULL) return -ENOMEM; printk("\n[HIKO AUDIO]rt5624_init()\n"); //This has been set in i2c common-smkd.c before this rt5624_i2s_init(); mdelay(10); rt5624_power(true); //This has been set in other drivers, like touch rt5624_audio_reset_off(); mdelay(1); rt5624_audio_reset_on(); //Store the RT5624 point SetRt5624CodecData(codec); //If less then 10ms, the I2C would be unstable // we take 30ms for make sure that above Audio Interface was done! mdelay(30); rt5624_reset(codec); mdelay(1); /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "rt5624: failed to create pcms\n"); goto pcm_err; } rt5624_write(codec, RT5624_PD_CTRL_STAT, 0x0000);//enable all PR bit rt5624_write(codec, RT5624_MISC_CTRL, 0x8000);//disable Fast Vref //flove012710 rt5624_write(codec, RT5624_PWR_MANAG_ADD1, 0x0002);//enable Main bias //flove012710 rt5624_write(codec, RT5624_PWR_MANAG_ADD3, 0x0c02);//enable HP volume power //flove012710 rt5624_write(codec, RT5624_PWR_MANAG_ADD2, 0x2000);//enable Vref /* charge output caps */ rt5624_dapm_event(codec, SNDRV_CTL_POWER_D2); codec->dapm_state = SNDRV_CTL_POWER_D3hot; schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(caps_charge)); //initize codec register for(i=0;ireg_cache); return ret; } /* If the i2c layer weren't so broken, we could pass this kind of data around */ #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) /* * RT5624 2 wire address is determined by A1 pin * state during powerup. * low = 0x18 * high = 0x19 */ static unsigned short normal_i2c[] = { 0, I2C_CLIENT_END }; /* Magic definition of all other variables and things */ I2C_CLIENT_INSMOD; static struct i2c_driver rt5624_i2c_driver; static struct i2c_client client_template; static int rt5624_codec_probe(struct i2c_adapter *adap, int addr, int kind) { printk("[kit]: rt5624_codec_probe()\n"); struct snd_soc_device *socdev = rt5624_socdev; struct rt5624_setup_data *setup = socdev->codec_data; struct snd_soc_codec *codec = socdev->codec; struct i2c_client *i2c; int ret; if (addr != setup->i2c_address) return -ENODEV; client_template.adapter = adap; client_template.addr = addr; i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL); if (i2c == NULL){ kfree(codec); return -ENOMEM; } i2c_set_clientdata(i2c, codec); codec->control_data = i2c; ret = i2c_attach_client(i2c); if (ret < 0) { err("failed to attach codec at addr %x\n", addr); goto err; } ret = rt5624_init(socdev); if (ret < 0) { err("failed to initialise RT5624\n"); goto err; } return ret; err: kfree(codec); kfree(i2c); return ret; } static int rt5624_i2c_detach(struct i2c_client *client) { printk("[kit]: rt5624_i2c_detach()\n"); struct snd_soc_codec *codec = i2c_get_clientdata(client); i2c_detach_client(client); kfree(codec->reg_cache); kfree(client); return 0; } static int rt5624_i2c_attach(struct i2c_adapter *adap) { printk("[kit]: rt5624_i2c_attach()\n"); return i2c_probe(adap, &addr_data, rt5624_codec_probe); } /* corgi i2c codec control layer */ static struct i2c_driver rt5624_i2c_driver = { .driver = { .name = "RT5624 I2C Codec", .owner = THIS_MODULE, }, .id = I2C_DRIVERID_I2CDEV, .attach_adapter = rt5624_i2c_attach, .detach_client = rt5624_i2c_detach, .command = NULL, }; static struct i2c_client client_template = { .name = "RT5624", .driver = &rt5624_i2c_driver, }; #endif //Qisda, Asaku Chen, 2009/08/12, for EM test { static int rt5624_fops_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { printk("[kit]: rt5624_fops_ioctl()\n"); u16 vender_id_1, vender_id_2; u32 read_pin; printk("\n[HIKO RT5624 IOCTL]rt5624_fops_ioctl, cmd: 0x%X, arg: 0x%X\n", cmd, arg); if (!rt5624_socdev) { printk("{HIKO RT5624] rt5624_socdev not yet assigned in rt5624_fops_ioctl()"); } switch(cmd){ case RT5624_FOPS_IOCTL_READ_VENDOR_ID: vender_id_1 = rt5624_read(rt5624_socdev->codec, RT5624_VENDOR_ID1); vender_id_2 = rt5624_read(rt5624_socdev->codec, RT5624_VENDOR_ID2); printk("READ_VENDOR_ID: 0x%x 0x%x\n", vender_id_1, vender_id_2); if((vender_id_1 != 0x10ec) || (vender_id_2 != 0x2003)){ printk("RT5624: read ID error!!!"); return -1; } return RT5624_FOPS_IOCTL_READ_VENDOR_ID; case RT5624_FOPS_IOCTL_HEADPHONE_INSERT: read_pin = readl(S3C2410_GPFDAT) & (1<<4); //printk("HEADPHONE_INSERT: %d\n", read_pin?0:1); return read_pin?0:1; case RT5624_FOPS_IOCTL_BOARD_LOOPBACK: // read_pin = rt5624_read(GetRt5624CodecData(), RT5624_MIC_ROUTING_CTRL); switch (arg) { case 1: // read_pin |= 0x4000; loopback_setting = SND_LOOPBACK_BOARD_SPK_MIC1; loopback_setting_active(); printk("\n[HIKO RT5624] BOARD LOOPBACK ON\n"); return 1; case 2: // read_pin &= ~(0x4000); loopback_setting = SND_LOOPBACK_NONE; loopback_setting_active(); printk("\n[HIKO RT5624] BOARD LOOPBACK OFF\n"); return 1; }; // rt5624_write(GetRt5624CodecData(), RT5624_MIC_ROUTING_CTRL, read_pin); break; case RT5624_FOPS_IOCTL_HEADPHONE_LOOPBACK: // read_pin = rt5624_read(GetRt5624CodecData(), RT5624_MIC_ROUTING_CTRL); switch (arg) { case 1: // read_pin |= 0x0080; loopback_setting = SND_LOOPBACK_HEADSET_RECIVER_MIC2; loopback_setting_active(); printk("\n[HIKO RT5624] HEADSET LOOPBACK ON\n"); return 1; case 2: // read_pin &= ~(0x0080); loopback_setting = SND_LOOPBACK_NONE; loopback_setting_active(); printk("\n[HIKO RT5624] HEADSET LOOPBACK OFF\n"); return 1; }; // rt5624_write(GetRt5624CodecData(), RT5624_MIC_ROUTING_CTRL, read_pin); break; //For RT5624 Inner Test case RT5624_FOPS_IOCTL_REG_STATUS_READ: { print_codec_regs(); } return 1; //For RT5624 Inner Test case RT5624_FOPS_IOCTL_REG_STATUS_WRITE: { u32 write_reg = arg>>16; u32 write_val = (arg&0x0000FFFF); rt5624_write(GetRt5624CodecData(), write_reg, write_val); } return 1; case RT5624_FOPS_IOCTL_AUDIO_IF_ENABLE: { switch (arg) { case 0: rt5624_turn_off_codec_hw(); printk("\n[HIKO RT5624] RT5624_FOPS_IOCTL_AUDIO_IF_ENABLE OFF\n"); return 1; case 1: rt5624_turn_on_codec_hw(); printk("\n[HIKO RT5624] RT5624_FOPS_IOCTL_AUDIO_IF_ENABLE ON\n"); return 1; default: printk("\n[HIKO RT5624] unknown RT5624_FOPS_IOCTL_AUDIO_IF_ENABLE arg:\n", arg); } } return -1; case RT5624_FOPS_IOCTL_AUDIO_POWER_STATE: { switch (arg) { case 0: rt5624_ChangeCodecPowerStatus(GetRt5624CodecData(), POWER_STATE_D0); printk("\n===[HIKO RT5624]IOCTL POWER STATE TO POWER_STATE_D0===\n"); break; case 1: rt5624_ChangeCodecPowerStatus(GetRt5624CodecData(), POWER_STATE_D1); printk("\n===[HIKO RT5624]IOCTL POWER STATE TO POWER_STATE_D1===\n"); break; case 2: rt5624_ChangeCodecPowerStatus(GetRt5624CodecData(), POWER_STATE_D2); printk("\n===[HIKO RT5624]IOCTL POWER STATE TO POWER_STATE_D2===\n"); break; case 3: rt5624_ChangeCodecPowerStatus(GetRt5624CodecData(), POWER_STATE_D3); printk("\n===[HIKO RT5624]IOCTL POWER STATE TO POWER_STATE_D3===\n"); break; case 4: rt5624_ChangeCodecPowerStatus(GetRt5624CodecData(), POWER_STATE_D4); printk("\n===[HIKO RT5624]IOCTL POWER STATE TO POWER_STATE_D4===\n"); break; default: printk("\n===[HIKO RT5624]IOCTL POWER STATE TO ARGUMENT error (arg==0x%X)===\n", arg); return -1; }; } return 1; default: printk("no this command\n"); } return 0; } /* File operations struct for character device */ static const struct file_operations rt5624_fops = { .owner = THIS_MODULE, .ioctl = rt5624_fops_ioctl, .open = rt5624_fops_open, .release = NULL }; //Qisda, Asaku Chen, 2009/08/12, for EM test } static int rt5624_probe(struct platform_device *pdev) { printk("[kit]: rt5624_probe()\n"); struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct rt5624_setup_data *setup; struct snd_soc_codec *codec; struct rt5624_priv *rt5624; int ret = 0; info("RT5624 Audio Codec %s",RT5624_VERSION); setup = socdev->codec_data; codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; rt5624 = kzalloc(sizeof(struct rt5624_priv), GFP_KERNEL); if (rt5624 == NULL) { kfree(codec); return -ENOMEM; } codec->private_data = rt5624; socdev->codec = codec; mutex_init(&codec->mutex); INIT_LIST_HEAD(&codec->dapm_widgets); INIT_LIST_HEAD(&codec->dapm_paths); rt5624_socdev = socdev; INIT_DELAYED_WORK(&codec->delayed_work, rt5624_work); #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) if (setup->i2c_address) { normal_i2c[0] = setup->i2c_address; codec->hw_write = (hw_write_t)i2c_master_send; codec->hw_read = (hw_read_t)i2c_master_recv; ret = i2c_add_driver(&rt5624_i2c_driver); if (ret != 0) printk(KERN_ERR "can't add i2c driver"); } #else /* Add other interfaces here */ #endif //Qisda, Asaku Chen, 2009/08/12, for EM test { //printk("\nA3U register\n"); if (register_chrdev (AUDIO_MAJOR, "audio_cmd", &rt5624_fops)) { printk("unable to get major %d\n", AUDIO_MAJOR); } //Qisda, Asaku Chen, 2009/08/12, for EM test } return ret; } /* * This function forces any delayed work to be queued and run. */ static int run_delayed_work(struct delayed_work *dwork) { printk("[kit]: run_delayed_work()\n"); int ret; /* cancel any work waiting to be queued. */ ret = cancel_delayed_work(dwork); /* if there was any work waiting then we run it now and * wait for it's completion */ if (ret) { schedule_delayed_work(dwork, 0); flush_scheduled_work(); } return ret; } /* power down chip */ static int rt5624_remove(struct platform_device *pdev) { printk("[kit]: rt5624_remove()\n"); struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->codec; if (codec->control_data) rt5624_dapm_event(codec, SNDRV_CTL_POWER_D3cold); run_delayed_work(&codec->delayed_work); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) i2c_del_driver(&rt5624_i2c_driver); #endif kfree(codec->private_data); kfree(codec); return 0; } struct snd_soc_codec *GetRt5624CodecData() { printk("[kit]: GetRt5624CodecData()\n"); return g_codecRt5624; } EXPORT_SYMBOL_GPL(GetRt5624CodecData); void SetRt5624CodecData(struct snd_soc_codec *codec) { printk("[kit]: SetRt5624CodecData()\n"); g_codecRt5624 = &(*codec); } EXPORT_SYMBOL_GPL(SetRt5624CodecData); static irqreturn_t rt5624_headset_irq(int irq, void *data) { printk("[kit]: rt5624_headset_irq()\n"); static struct timespec last_timespec; static bool first_init = true; struct timespec curr_timespec; s64 time_dist; if (first_init) { last_timespec = current_kernel_time(); } curr_timespec = current_kernel_time(); time_dist = timespec_to_ns(&curr_timespec) - timespec_to_ns(&last_timespec); // printk("[HIKO] ==================== time_dist = 0x%X", time_dist); #if defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_E600_DVT1) if (time_dist < 400000000 && !first_init) { #else // if (time_dist < 200000000 && !first_init) { // if (time_dist < 50000000 && !first_init) { if (0) { #endif return IRQ_HANDLED; } else { last_timespec = current_kernel_time(); } //Would be reset after queue done in queue function disable_irq(IRQ_EINT4); schedule_work(&g_wqReadData); if (first_init) { first_init = false; } return IRQ_HANDLED; } static irqreturn_t rt5624_mic_irq(int irq, void *data) { printk("[kit]: rt5624_mic_irq()\n"); schedule_work(&g_wqMicata); return IRQ_HANDLED; } //Setting the Mic source static snd_in_path_type set_audio_in_path_dep_on_headset_jack() { printk("[kit]: set_audio_in_path_dep_on_headset_jack()\n"); u32 headset_pin_stat = get_headset_jack_status(); snd_in_path_type ret_type = SND_IN_PATH_UNKNOWN; if (headset_pin_stat == SND_OUT_PATH_UNKNOWN) return ret_type; //SPEAKER MODE #if defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_E600_DVT1) if (headset_pin_stat) { #else if (headset_pin_stat == 0) { #endif //Disable MIC 2 Enable_ADC_Input_Source(GetRt5624CodecData(),RT_WAVIN_L_MIC2|RT_WAVIN_R_MIC2,0); //Enable MIC 1 Enable_ADC_Input_Source(GetRt5624CodecData(), RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,1); g_snd_in_path = ret_type = SND_IN_PATH_MIC1; //HEADSET MODE } else { //Disable MIC 1 Enable_ADC_Input_Source(GetRt5624CodecData(), RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,0); //Enable MIC 2 Enable_ADC_Input_Source(GetRt5624CodecData(), RT_WAVIN_L_MIC2|RT_WAVIN_R_MIC2,1); g_snd_in_path = ret_type = SND_IN_PATH_MIC2; } printk("[HIKO rt5624] headset_pin_stat=0x%X set_audio_in_path_dep_on_headset_jack()\n", headset_pin_stat); return ret_type; } //Setting the Mic source which depends on g_snd_out_path for reference static snd_in_path_type set_audio_in_path_dep_on_out_variable() { printk("[kit]: set_audio_in_path_dep_on_out_variable()\n"); snd_in_path_type ret_type = SND_IN_PATH_UNKNOWN; switch (g_snd_out_path) { case SND_OUT_PATH_SPEAKER: //Disable MIC 2 Enable_ADC_Input_Source(GetRt5624CodecData(), RT_WAVIN_L_MIC2|RT_WAVIN_R_MIC2,0); //Enable MIC 1 Enable_ADC_Input_Source(GetRt5624CodecData(), RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,1); g_snd_in_path = ret_type = SND_IN_PATH_MIC1; break; case SND_OUT_PATH_HEADSET: //Disable MIC 1 Enable_ADC_Input_Source(GetRt5624CodecData(), RT_WAVIN_L_MIC1|RT_WAVIN_R_MIC1,0); //Enable MIC 2 Enable_ADC_Input_Source(GetRt5624CodecData(), RT_WAVIN_L_MIC2|RT_WAVIN_R_MIC2,1); g_snd_in_path = ret_type = SND_IN_PATH_MIC2; break; } printk("[HIKO rt5624] g_snd_out_path=0x%X set_audio_in_path_dep_on_out_variable()\n", g_snd_out_path); return ret_type; } //Setting the output path (Speaker, Headset....) static snd_out_path_type set_audio_out_path_dep_on_headset_jack() { printk("[kit]: set_audio_out_path_dep_on_headset_jack()\n"); u32 headset_pin_stat = get_headset_jack_status(); snd_out_path_type ret_type = SND_OUT_PATH_UNKNOWN; struct snd_soc_codec *codec = GetRt5624CodecData(); if (headset_pin_stat == SND_OUT_PATH_UNKNOWN) return ret_type; if (rt5624_vol_value == 0) { rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); #if defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_E600_DVT1) if (headset_pin_stat) { #else if (headset_pin_stat == 0) { #endif g_snd_out_path = ret_type = SND_OUT_PATH_SPEAKER; printk("[HIKO]set_audio_out_path_dep_on_headset_jack() SPK ON\n"); } else { g_snd_out_path = ret_type = SND_OUT_PATH_HEADSET; printk("[HIKO]set_audio_out_path_dep_on_headset_jack() HEADSET ON\n"); } } else { #if defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_E600_DVT1) if (headset_pin_stat) { #else if (headset_pin_stat == 0) { #endif rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 0); g_snd_out_path = ret_type = SND_OUT_PATH_SPEAKER; printk("[HIKO]set_audio_out_path_dep_on_headset_jack() SPK ON\n"); } else { rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 0); g_snd_out_path = ret_type = SND_OUT_PATH_HEADSET; printk("[HIKO]set_audio_out_path_dep_on_headset_jack() HEADSET ON\n"); } } return ret_type; } static u32 get_headset_jack_status() { printk("[kit]: get_headset_jack_status()\n"); u32 read_pin; if (!GetRt5624CodecData()) { printk("[HIKO]GetRt5624CodecData()==NULL in get_headset_jack_status()\n"); return SND_OUT_PATH_UNKNOWN; } // mutex_lock(&(GetRt5624CodecData()->mutex)); /*kit.mod 2009/01/19, extend de-bouncing time to detect plun & unplug headset*/ //mdelay(20); msleep(400); /*kie.end*/ read_pin = readl(S3C2410_GPFDAT) & (1<<4)/*GPF4 value*/; // mutex_unlock(&(GetRt5624CodecData()->mutex)); return read_pin; } static u32 get_mic_pin_status() { printk("[kit]: get_mic_pin_status()\n"); u32 read_pin; if (!GetRt5624CodecData()) { printk("[HIKO]GetRt5624CodecData()==NULL in get_mic_pin_status()\n"); return SND_OUT_PATH_UNKNOWN; } // mutex_lock(&(GetRt5624CodecData()->mutex)); mdelay(200); read_pin = readl(S3C2410_GPFDAT) & (1<<6)/*GPF6 value*/; // mutex_unlock(&(GetRt5624CodecData()->mutex)); return read_pin; } //Headset Jack IRQ queue process static void rt5624_headset_det_path_route_workq() { printk("[kit]: rt5624_headset_det_path_route_workq()\n"); u32 shout_curr_reg; int ret; if (SND_OUT_PATH_HEADSET == set_audio_out_path_dep_on_headset_jack()) { #if defined(CONFIG_QISDA_AS090B00_EVT1) ||defined(CONFIG_QISDA_AS090B00_EVT1_1) rt5624_get_headset_type(); #endif //CONFIG_QISDA_AS090B00_EVT1 } //setup the volume restore_volume(); //Reset the IRQ for INT enable_irq(IRQ_EINT4); } static snd_headset_pin_type rt5624_get_headset_type() { printk("[kit]: rt5624_get_headset_type()\n"); u32 shout_curr_reg; snd_headset_pin_type ret_value; shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_OVER_TEMP_CURR_STATUS); if (shout_curr_reg & 0x100) { g_snd_in_path = SND_IN_PATH_MIC1; ret_value = g_btHeadsetPinType = SND_HEADSET_3_PIN; printk("\n\n[HIKO RT5624] 3-pin Headset DETECTED!!\n\n"); } else { g_snd_in_path = SND_IN_PATH_MIC2; ret_value = g_btHeadsetPinType = SND_HEADSET_4_PIN; printk("\n\n[HIKO RT5624] 4-pin Headset DETECTED!!\n\n"); } return ret_value; } //Headset Jack IRQ queue process static void rt5624_mic_det_path_route_workq() { printk("[kit]: rt5624_mic_det_path_route_workq()\n"); u32 shout_curr_reg; if (!GetRt5624CodecData()) { printk("[HIKO]GetRt5624CodecData()==NULL in rt5624_mic_det_path_route_workq()\n"); return; } //Setting the Mic Short current INT setting //Reg54[10]=0'b Write 0 to clear status shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_GPIO_PIN_STATUS); shout_curr_reg &= ~(1<<10); rt5624_write(GetRt5624CodecData(), RT5624_GPIO_PIN_STATUS, shout_curr_reg); g_btHeadsetPinType = SND_HEADSET_3_PIN; printk("\n\n[HIKO RT5624] 3 PIN MIC DETECTED!!!! Reg22[1:0]=0x%X\n\n", shout_curr_reg); } static void rt5624_set_irq(void *int_dat, void *mic_int_dat) { printk("[kit]: rt5624_set_irq()\n"); int ret; u32 shout_curr_reg; if (!GetRt5624CodecData()) { printk("[HIKO]GetRt5624CodecData()==NULL in rt5624_set_irq()\n"); return; } //HEADSET DETECT s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_EINT4/*S3C2410_GPF4_EINT4*/); s3c2410_gpio_pullup(S3C2410_GPF4, 2); // s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_EINT6); // s3c2410_gpio_pullup(S3C2410_GPF6, /*1*/2); //writel((readl(S3C2410_EXTINT0) & ~(1<<27)), S3C2410_EXTINT0); /* EINT6 filter enable */ //writel(((readl(S3C2410_EXTINT0) & ~(7<<24))|(4<<24)), S3C2410_EXTINT0); // Rising edge triggered // writel(((readl(S3C2410_EXTINT0) & ~(1<<25))|(1<<26)), S3C2410_EXTINT0); // Rising edge triggered //writel(((readl(S3C2410_EXTINT0) & ~(3<<25))|(1<<24)), S3C2410_EXTINT0); // Rising edge triggered // set_irq_type(IRQ_EINT6, 0x1); //MIC DETECT //#if 0 //Setting the Mic Short current INT setting //Reg26[3:2] = 1'b shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_PD_CTRL_STAT); shout_curr_reg = shout_curr_reg | (1<<3) | (1<<2); rt5624_write(GetRt5624CodecData(), RT5624_PD_CTRL_STAT, shout_curr_reg);//enable all PR bit //Reg3A[4] and Reg3A[2] = 1'b shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD1); //shout_curr_reg = shout_curr_reg | (1<<2) | (1<<4); shout_curr_reg = 0x003F; //TEST rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD1, shout_curr_reg); //Reg56[2] = 0'b // shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_GPIO_PIN_SHARING); // shout_curr_reg &= ~(1<<2); // rt5624_write(GetRt5624CodecData(), RT5624_GPIO_PIN_SHARING, shout_curr_reg); //Reg50[9] = 1'b // shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_GPIO_PIN_STICKY); // shout_curr_reg = shout_curr_reg | (1<<9); // rt5624_write(GetRt5624CodecData(), RT5624_GPIO_PIN_STICKY, shout_curr_reg); //Reg4C[9]=1,b // shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_GPIO_PIN_CONFIG); // shout_curr_reg = shout_curr_reg | (1<<9); // rt5624_write(GetRt5624CodecData(), RT5624_GPIO_PIN_CONFIG, shout_curr_reg); //Reg52[9]=1'b // shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_GPIO_PIN_WAKEUP); // shout_curr_reg = shout_curr_reg | (1<<9); // rt5624_write(GetRt5624CodecData(), RT5624_GPIO_PIN_WAKEUP, shout_curr_reg); //TEST //Reg3C[9]=0x2000 shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD2); shout_curr_reg = 0x2000; rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD2, shout_curr_reg); //Setting the Mic Short current INT setting //Reg54[10]=0'b Write 0 to clear status // shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_GPIO_PIN_STATUS); // shout_curr_reg &= ~(1<<10); // rt5624_write(GetRt5624CodecData(), RT5624_GPIO_PIN_STATUS, shout_curr_reg); //Reg22[1:0] = <600uA> // shout_curr_reg = rt5624_read(GetRt5624CodecData(), RT5624_MIC_CTRL); // shout_curr_reg &= ~(0x3); // rt5624_write(GetRt5624CodecData(), RT5624_MIC_CTRL, shout_curr_reg); //#endif //0 //HEADSET INT //#if 0 //#if defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_E600_DVT1) //INT_EARDET to be Falling Edge set_irq_type(IRQ_EINT4, 0x3); //#else // //INT_EARDET to be Rising Edge // set_irq_type(IRQ_EINT4, 0x4); //#endif ret = request_irq(IRQ_EINT4, rt5624_headset_irq, SA_INTERRUPT, RT5624_DEVICE_NAME, int_dat); if (ret<0) { printk("[HIKO]request_irq IRQ_EINT4 error\n"); free_irq(IRQ_EINT4, int_dat); } //#endif //0 //MIC DETECT #if 0 //INT_MICDET // set_irq_type(IRQ_EINT6, 0x3/*IRQT_BOTHEDGE*/); set_irq_type(IRQ_EINT6, 0x1/*IRQT_BOTHEDGE*/); ret = request_irq(IRQ_EINT6, rt5624_mic_irq, SA_INTERRUPT, RT5624_DEVICE_NAME/*RT5624_MIC_DEVICE_NAME*/, mic_int_dat); if (ret<0) { printk("[HIKO]request_irq IRQ_EINT6 error\n"); free_irq(IRQ_EINT6, mic_int_dat); } #endif //0 } static void rt5624_headset_int_setup() { printk("[kit]: rt5624_headset_int_setup()\n"); //HEADSET INT if (!g_headset_plugin_int_dat) g_headset_plugin_int_dat = kzalloc(sizeof(unsigned long), GFP_KERNEL); //MIC DETECT //#if 0 if (!g_headset_mic_int_dat) g_headset_mic_int_dat = kzalloc(sizeof(unsigned long), GFP_KERNEL); //#endif //0 // s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_EINT4); // s3c2410_gpio_pullup(S3C2410_GPF4, 2); rt5624_set_irq(g_headset_plugin_int_dat, g_headset_mic_int_dat); } /* ** Mic setting for which mic */ static void rt5624_mic_setup(snd_in_path_type mic_in_type) { printk("[kit]: rt5624_mic_setup()\n"); if (!GetRt5624CodecData()) { printk("[HIKO]GetRt5624CodecData()==NULL in rt5624_mic_setup()\n"); return; } printk("rt5624_mic_setup(0x%X)\n", (unsigned long)mic_in_type); //For Mic 1 if (mic_in_type == SND_IN_PATH_MIC1) { rt5624_write(GetRt5624CodecData(), RT5624_ADC_REC_MIXER, 0x3f3f); // rt5624_write(GetRt5624CodecData(), RT5624_MIC_CTRL, 0x0530); } //For Mic 2 else if (mic_in_type == SND_IN_PATH_MIC2) { rt5624_write(GetRt5624CodecData(), RT5624_ADC_REC_MIXER, 0x5f5f); // rt5624_write(GetRt5624CodecData(), RT5624_ADC_REC_MIXER, 0x5B5B); // rt5624_write(GetRt5624CodecData(), RT5624_MIC_CTRL, 0x0530); } } struct snd_soc_codec_device soc_codec_dev_rt5624 = { .probe = rt5624_probe, .remove = rt5624_remove, .suspend = rt5624_suspend, .resume = rt5624_resume, }; //HIKO: For Volume 10 step setting { static int get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { printk("[kit]: get_volume()\n"); printk("\n[HIKO RT5624] get_volume() rt5624_vol_value=0x%X\n", rt5624_vol_value); ucontrol->value.integer.value[0] = rt5624_vol_value; return 0; } /*this function is define to get a number from 0 to 63 when you give a number from 0-99, can be substitute by your own algorithm*/ static struct vol_setting get_real_volume(unsigned long num) { printk("[kit]: get_real_volume()\n"); struct vol_setting real_vol; if (num > 10) num = 10; // if (num < 0) // num = 0; switch (g_snd_out_path) { /*kit.mod 2009/12/25*/ case SND_OUT_PATH_SPEAKER: printk("\n[HIKO RT5624] Speaker table using\n"); memcpy(&real_vol, &(speaker_vol_tab[num]), sizeof(struct vol_setting)); break; case SND_OUT_PATH_HEADSET: printk("\n[HIKO RT5624] Headset table using\n"); memcpy(&real_vol, &(headset_vol_tab[num]), sizeof(struct vol_setting)); break; defaule: printk("error: in get_real_volume(): no such output path\n"); break; /*kit.end*/ } // printk("\n[HIKO RT5624] real_vol==0x%X in get_real_volume()\n", real_vol); return real_vol; } static int restore_volume() { printk("[kit]: restore_volume()\n"); struct vol_setting real_vol; unsigned long curr_reg; struct snd_soc_codec *codec = GetRt5624CodecData(); printk("\n[HIKO RT5624] restore_volume\n"); #if 1 #if 0 { u16 mute_reg = rt5624_read(codec, RT5624_MISC_CTRL) & 0xfff3; // if (ucontrol->value.integer.value[0] == 0x0) if (new_vol == 0x0) { rt5624_write(codec, RT5624_MISC_CTRL, mute_reg | 0xc); } else { rt5624_write(codec, RT5624_MISC_CTRL, mute_reg); } } #elif 1 if (rt5624_vol_value == 0x0) { rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); } else { switch (g_snd_out_path) { case SND_OUT_PATH_SPEAKER: rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 0); break; case SND_OUT_PATH_HEADSET: rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 0); break; }; } #else // if (ucontrol->value.integer.value[0] == 0x0) { if (rt5624_vol_value == 0x0) { rt5624_write(codec, RT5624_STEREO_DAC_VOL, (rt5624_read(codec, RT5624_STEREO_DAC_VOL) | (0x1<<15))); } else { rt5624_write(codec, RT5624_STEREO_DAC_VOL, (rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~(0x1<<15))); } #endif//0 #endif//0 // mdelay(1); real_vol = get_real_volume(rt5624_vol_value); switch (g_snd_out_path) { //Speaker setting case SND_OUT_PATH_SPEAKER: curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~((0x1F<<8) | 0x1F); mdelay(1); curr_reg |= real_vol.dac_val; rt5624_write(codec, RT5624_STEREO_DAC_VOL, curr_reg); curr_reg = rt5624_read(codec, RT5624_SPK_OUT_VOL) & ~((0x1F<<8) | 0x1F); curr_reg |= real_vol.output_vol; rt5624_write(codec, RT5624_SPK_OUT_VOL, curr_reg); break; //Headset setting case SND_OUT_PATH_HEADSET: curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~((0x1F<<8) | 0x1F); mdelay(1); curr_reg |= real_vol.dac_val; rt5624_write(codec, RT5624_STEREO_DAC_VOL, curr_reg); curr_reg = rt5624_read(codec, RT5624_HP_OUT_VOL) & ~((0x1F<<8) | 0x1F); curr_reg |= real_vol.output_vol; rt5624_write(codec, RT5624_HP_OUT_VOL, curr_reg); break; }; return 1; } static int set_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { printk("[kit]: set_volume()\n"); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned long mode; struct vol_setting real_vol; unsigned long curr_reg; unsigned long new_vol = ucontrol->value.integer.value[0]; static snd_out_path_type last_path; static bool first_setting = true; printk("\n[HIKO RT5624] set_volume() rt5624_vol_value=0x%X new_vol==0x%X\n", rt5624_vol_value, new_vol); ucontrol_store = ucontrol; // // prevent re-setting in the same path and volume // if (first_setting) { last_path = g_snd_out_path; first_setting = false; } else { if (new_vol == rt5624_vol_value && last_path == g_snd_out_path) { return 0; } else { last_path = g_snd_out_path; } } #if 1 #if 0 { u16 mute_reg = rt5624_read(codec, RT5624_MISC_CTRL) & 0xfff3; // if (ucontrol->value.integer.value[0] == 0x0) if (new_vol == 0x0) { rt5624_write(codec, RT5624_MISC_CTRL, mute_reg | 0xc); } else { rt5624_write(codec, RT5624_MISC_CTRL, mute_reg); } } #elif 1 #if 0 if (new_vol == 0x0) { rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); } else { switch (g_snd_out_path) { case SND_OUT_PATH_SPEAKER: rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 0); break; case SND_OUT_PATH_HEADSET: rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 0); break; }; } #endif #else // if (ucontrol->value.integer.value[0] == 0x0) { if (rt5624_vol_value == 0x0) { rt5624_write(codec, RT5624_STEREO_DAC_VOL, (rt5624_read(codec, RT5624_STEREO_DAC_VOL) | (0x1<<15))); } else { rt5624_write(codec, RT5624_STEREO_DAC_VOL, (rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~(0x1<<15))); } #endif//0 #endif//0 // mdelay(1); rt5624_vol_value = new_vol; real_vol = get_real_volume(new_vol); switch (g_snd_out_path) { //Speaker setting case SND_OUT_PATH_SPEAKER: curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~((0x1F<<8) | 0x1F); mdelay(1); curr_reg |= real_vol.dac_val; rt5624_write(codec, RT5624_STEREO_DAC_VOL, curr_reg); curr_reg = rt5624_read(codec, RT5624_SPK_OUT_VOL) & ~((0x1F<<8) | 0x1F); curr_reg |= real_vol.output_vol; rt5624_write(codec, RT5624_SPK_OUT_VOL, curr_reg); break; //Headset setting case SND_OUT_PATH_HEADSET: curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~((0x1F<<8) | 0x1F); mdelay(1); curr_reg |= real_vol.dac_val; rt5624_write(codec, RT5624_STEREO_DAC_VOL, curr_reg); curr_reg = rt5624_read(codec, RT5624_HP_OUT_VOL) & ~((0x1F<<8) | 0x1F); curr_reg |= real_vol.output_vol; rt5624_write(codec, RT5624_HP_OUT_VOL, curr_reg); break; }; if (new_vol == 0x0) { rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); } else { switch (g_snd_out_path) { case SND_OUT_PATH_SPEAKER: rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 0); break; case SND_OUT_PATH_HEADSET: rt5624_AudioOutEnable(codec, RT_WAVOUT_SPK, 1); rt5624_AudioOutEnable(codec, RT_WAVOUT_HP, 0); break; }; } return 1; } //HIKO: For Volume 10 step setting } static void print_codec_regs() { printk("[kit]: print_codec_regs()\n"); u16 shout_curr_reg; struct snd_soc_codec *codec = GetRt5624CodecData(); printk("[HIKO rt5624]===================print_codec_regs()===================\n"); shout_curr_reg = rt5624_read(codec, RT5624_RESET); printk("\n[HIKO DEBUG] (Reg00) = 0x%04X RT5624_RESET\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_SPK_OUT_VOL); printk("[HIKO DEBUG] (Reg02) = 0x%04X RT5624_SPK_OUT_VOL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_HP_OUT_VOL); printk("[HIKO DEBUG] (Reg04) = 0x%04X RT5624_HP_OUT_VOL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_PHONEIN_MONO_OUT_VOL); printk("[HIKO DEBUG] (Reg08) = 0x%04X RT5624_PHONEIN_MONO_OUT_VOL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_LINE_IN_VOL); printk("[HIKO DEBUG] (Reg0A) = 0x%04X RT5624_LINE_IN_VOL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_VOL); printk("[HIKO DEBUG] (Reg0C) = 0x%04X RT5624_STEREO_DAC_VOL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_MIC_VOL); printk("[HIKO DEBUG] (Reg0E) = 0x%04X RT5624_MIC_VOL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_MIC_ROUTING_CTRL); printk("[HIKO DEBUG] (Reg10) = 0x%04X RT5624_MIC_ROUTING_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_ADC_REC_GAIN); printk("[HIKO DEBUG] (Reg12) = 0x%04X RT5624_ADC_REC_GAIN\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_ADC_REC_MIXER); printk("[HIKO DEBUG] (Reg14) = 0x%04X RT5624_ADC_REC_MIXER\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_VOICE_DAC_OUT_VOL); printk("[HIKO DEBUG] (Reg18) = 0x%04X RT5624_VOICE_DAC_OUT_VOL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_OUTPUT_MIXER_CTRL); printk("[HIKO DEBUG] (Reg1C) = 0x%04X RT5624_OUTPUT_MIXER_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_MIC_CTRL); printk("[HIKO DEBUG] (Reg22) = 0x%04X RT5624_MIC_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_PD_CTRL_STAT); printk("[HIKO DEBUG] (Reg26) = 0x%04X RT5624_PD_CTRL_STAT\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_MAIN_SDP_CTRL); printk("[HIKO DEBUG] (Reg34) = 0x%04X RT5624_MAIN_SDP_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_EXTEND_SDP_CTRL); printk("[HIKO DEBUG] (Reg36) = 0x%04X RT5624_EXTEND_SDP_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_PWR_MANAG_ADD1); printk("[HIKO DEBUG] (Reg3A) = 0x%04X RT5624_PWR_MANAG_ADD1\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_PWR_MANAG_ADD2); printk("[HIKO DEBUG] (Reg3C) = 0x%04X RT5624_PWR_MANAG_ADD2\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_PWR_MANAG_ADD3); printk("[HIKO DEBUG] (Reg3E) = 0x%04X RT5624_PWR_MANAG_ADD3\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GEN_CTRL_REG1); printk("[HIKO DEBUG] (Reg40) = 0x%04X RT5624_GEN_CTRL_REG1\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GEN_CTRL_REG2); printk("[HIKO DEBUG] (Reg42) = 0x%04X RT5624_GEN_CTRL_REG2\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_PLL_CTRL); printk("[HIKO DEBUG] (Reg44) = 0x%04X RT5624_PLL_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GPIO_PIN_CONFIG); printk("[HIKO DEBUG] (Reg4C) = 0x%04X RT5624_GPIO_PIN_CONFIG\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GPIO_PIN_POLARITY); printk("[HIKO DEBUG] (Reg4E) = 0x%04X RT5624_GPIO_PIN_POLARITY\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GPIO_PIN_STICKY); printk("[HIKO DEBUG] (Reg50) = 0x%04X RT5624_GPIO_PIN_STICKY\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GPIO_PIN_WAKEUP); printk("[HIKO DEBUG] (Reg52) = 0x%04X RT5624_GPIO_PIN_WAKEUP\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GPIO_PIN_STATUS); printk("[HIKO DEBUG] (Reg54) = 0x%04X RT5624_GPIO_PIN_STATUS\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GPIO_PIN_SHARING); printk("[HIKO DEBUG] (Reg56) = 0x%04X RT5624_GPIO_PIN_SHARING\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_OVER_TEMP_CURR_STATUS); printk("[HIKO DEBUG] (Reg58) = 0x%04X RT5624_OVER_TEMP_CURR_STATUS\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_GPIO_OUT_CTRL); printk("[HIKO DEBUG] (Reg5C) = 0x%04X RT5624_GPIO_OUT_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_MISC_CTRL); printk("[HIKO DEBUG] (Reg5E) = 0x%04X RT5624_MISC_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_CLK_CTRL1); printk("[HIKO DEBUG] (Reg60) = 0x%04X RT5624_STEREO_DAC_CLK_CTRL1\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_CLK_CTRL2); printk("[HIKO DEBUG] (Reg62) = 0x%04X RT5624_STEREO_DAC_CLK_CTRL2\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_VOICE_DAC_PCMCLK_CTRL1); printk("[HIKO DEBUG] (Reg64) = 0x%04X RT5624_VOICE_DAC_PCMCLK_CTRL1\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_VOICE_DAC_PCMCLK_CTRL2); printk("[HIKO DEBUG] (Reg66) = 0x%04X RT5624_VOICE_DAC_PCMCLK_CTRL2\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_PSEDUEO_SPATIAL_CTRL); printk("[HIKO DEBUG] (Reg68) = 0x%04X RT5624_PSEDUEO_SPATIAL_CTRL\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_INDEX_ADDRESS); printk("[HIKO DEBUG] (Reg6A) = 0x%04X RT5624_INDEX_ADDRESS\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_INDEX_DATA); printk("[HIKO DEBUG] (Reg6C) = 0x%04X RT5624_INDEX_DATA\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_EQ_STATUS); printk("[HIKO DEBUG] (Reg6E) = 0x%04X RT5624_EQ_STATUS\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_VENDOR_ID1); printk("[HIKO DEBUG] (Reg7C) = 0x%04X RT5624_VENDOR_ID1\n", shout_curr_reg); shout_curr_reg = rt5624_read(codec, RT5624_VENDOR_ID2); printk("[HIKO DEBUG] (Reg7E) = 0x%04X RT5624_VENDOR_ID2\n", shout_curr_reg); //IIS Registers shout_curr_reg = get_iismod(); printk("[HIKO DEBUG] (IISMOD) = 0x%08X S3C2410_IISMOD\n", shout_curr_reg); shout_curr_reg = get_iiscon(); printk("[HIKO DEBUG] (IISCON) = 0x%08X S3C2410_IISCON\n", shout_curr_reg); shout_curr_reg = get_iisfic(); printk("[HIKO DEBUG] (IISFIC) = 0x%08X S3C2410_IISFIC\n", shout_curr_reg); shout_curr_reg = get_iispsr(); printk("[HIKO DEBUG] (IISPSR) = 0x%08X S3C2410_IISPSR\n", shout_curr_reg); // shout_curr_reg = get_iistxd(); // printk("[HIKO DEBUG] (IISTXD) = 0x%08X S3C2410_IISFIFO\n", shout_curr_reg); // shout_curr_reg = get_iisrxd(); // printk("[HIKO DEBUG] (IISRXD) = 0x%08X S3C2410_IISFIFORX\n", shout_curr_reg); } static void loopback_setting_active() { printk("[kit]: loopback_setting_active()\n"); u32 read_pin; struct snd_soc_codec *codec = GetRt5624CodecData(); printk("\n[HIKO RT5624] LOOPBACK SETTING loopback_setting_active()\n"); if (pre_loopback_setting == loopback_setting) return; else pre_loopback_setting = loopback_setting; switch (loopback_setting) { case SND_LOOPBACK_BOARD_SPK_MIC1: rt5624_write(codec, RT5624_SPK_OUT_VOL, 0x0000); rt5624_write(codec, RT5624_HP_OUT_VOL, 0x8080); rt5624_write(codec, RT5624_STEREO_DAC_VOL, 0x0000); rt5624_write(codec, RT5624_MIC_VOL, 0x0000); rt5624_write(codec, RT5624_MIC_ROUTING_CTRL, 0x60E0); rt5624_write(codec, RT5624_ADC_REC_GAIN, 0x3FBF); rt5624_write(codec, RT5624_ADC_REC_MIXER, 0x3B3B); rt5624_write(codec, RT5624_OUTPUT_MIXER_CTRL, 0x6800); rt5624_write(codec, RT5624_PWR_MANAG_ADD1, 0x483F); rt5624_write(codec, RT5624_PWR_MANAG_ADD2, 0x6330); rt5624_write(codec, RT5624_PWR_MANAG_ADD3, 0x3F00); printk("\n[HIKO RT5624] BOARD LOOPBACK ON loopback_setting_active()\n"); break; case SND_LOOPBACK_HEADSET_RECIVER_MIC2: rt5624_write(codec, RT5624_SPK_OUT_VOL, 0x0A00); rt5624_write(codec, RT5624_HP_OUT_VOL, 0x0000); rt5624_write(codec, RT5624_STEREO_DAC_VOL, 0x0000); rt5624_write(codec, RT5624_MIC_VOL, 0x0000); rt5624_write(codec, RT5624_MIC_ROUTING_CTRL, 0xE060); rt5624_write(codec, RT5624_ADC_REC_GAIN, 0x3FBF); rt5624_write(codec, RT5624_ADC_REC_MIXER, 0x5B5B); rt5624_write(codec, RT5624_PWR_MANAG_ADD1, 0x483F); rt5624_write(codec, RT5624_PWR_MANAG_ADD2, 0x6330); rt5624_write(codec, RT5624_PWR_MANAG_ADD3, 0x3F00); printk("\n[HIKO RT5624] BOARD LOOPBACK ON loopback_setting_active()\n"); break; case SND_LOOPBACK_NONE: read_pin |= 0x4080; printk("\n[HIKO RT5624] BOARD LOOPBACK ALL OFF loopback_setting_active()\n"); break; } } static void rt5624_turn_off_codec_hw() { printk("[kit]: rt5624_turn_off_codec_hw()\n"); printk("\n========[HIKO RT5624 rt5624_turn_off_codec_hw()========\n"); rt5624_write_mask(GetRt5624CodecData(),RT5624_PWR_MANAG_ADD1,0,PWR_HI_R_LOAD_HP); //flove012710 rt5624_write_mask(GetRt5624CodecData(),RT5624_HP_OUT_VOL,0x8080,0x8080); //flove012710 rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD3, 0x0000);//power off all bit rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD1, 0x0000);//power off all bit rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD2, 0x0000);//power off all bit rt5624_write(GetRt5624CodecData(), RT5624_PD_CTRL_STAT, 0xffff);//enable all PR bit rt5624_power(false); rt5624_audio_reset_off(); rt5624_i2s_release(); mdelay(1); } static void rt5624_turn_on_codec_hw() { printk("[kit]: rt5624_turn_on_codec_hw()\n"); int i; printk("\n========[HIKO RT5624 rt5624_turn_on_codec_hw()========\n"); if (!GetRt5624CodecData()) { printk("[HIKO RT5624]GetRt5624CodecData()==NULL in rt5624_turn_on_codec_hw()"); return; } rt5624_i2s_init(); mdelay(10); rt5624_power(true); mdelay(1); rt5624_audio_reset_off(); mdelay(1); rt5624_audio_reset_on(); //If less then 10ms, the I2C would be unstable // we take 30ms for make sure that above Audio Interface was done! mdelay(30); rt5624_reset(GetRt5624CodecData()); mdelay(1); rt5624_write(GetRt5624CodecData(), RT5624_PD_CTRL_STAT, 0x0000);//enable all PR bit rt5624_write(GetRt5624CodecData(), RT5624_MISC_CTRL, 0x8000);//disable Fast Vref //flove012710 rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD3, 0x0c02);//enable hp out volume rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD1, 0x0002);//enable Main bias rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD2, 0x2000);//enable Vref for(i=0;isuspend_dapm_state == SNDRV_CTL_POWER_D0) { rt5624_dapm_event(GetRt5624CodecData(), SNDRV_CTL_POWER_D2); GetRt5624CodecData()->dapm_state = SNDRV_CTL_POWER_D0; schedule_delayed_work(&GetRt5624CodecData()->delayed_work, msecs_to_jiffies(caps_charge)); } } EXPORT_SYMBOL_GPL(soc_codec_dev_rt5624); MODULE_DESCRIPTION("ASoC RT5624 driver"); MODULE_AUTHOR("flove"); MODULE_LICENSE("GPL");