3205 lines
91 KiB
C

/*
* rt5624.c -- RT5624 ALSA Soc Audio driver
*
* Copyright 2008 Realtek Microelectronics
*
* Author: flove <flove@realtek.com>
*
* Based on WM8753.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <asm/div64.h>
////////////////////////
//For Headset IRQ
////////////////////////
#include <asm/arch/regs-irq.h>
#include <asm/irq.h>
#include <linux/irqreturn.h>
#include <asm/arch/regs-gpio.h>
#include <asm-arm/arch-s3c2410/map.h>
#include <linux/interrupt.h>
#include <asm-arm/io.h>
//Qisda, Asaku Chen, 2009/08/12, for EM test {
#include <linux/major.h>
//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();
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 unsigned long get_real_volume(int 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
#ifdef CONFIG_QISDA_QD060N00_DVT1_1
{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 {
static unsigned long speaker_vol_tab[10] =
{
((0x1F<<8) | 0x1F),
((0x10<<8) | 0x10),
((0x0E<<8) | 0x0E),
((0x0C<<8) | 0x0C),
((0x0A<<8) | 0x0A),
((0x08<<8) | 0x08),
((0x06<<8) | 0x06),
((0x04<<8) | 0x04),
((0x02<<8) | 0x02),
((0x00<<8) | 0x00)
};
static unsigned long headset_vol_tab[10] =
{
((0x1F<<8) | 0x1F),
((0x1A<<8) | 0x1A),
((0x18<<8) | 0x18),
((0x16<<8) | 0x16),
((0x14<<8) | 0x14),
((0x12<<8) | 0x12),
((0x0F<<8) | 0x0F),
((0x0B<<8) | 0x0B),
((0x08<<8) | 0x08),
((0x04<<8) | 0x04)
};
//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
//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)
{
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)
{
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)
{
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
,PWR_DAC_REF | PWR_MAIN_BIAS | PWR_MAIN_I2S | PWR_HI_R_LOAD_HP);
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 |
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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()
{
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);
#ifdef CONFIG_QISDA_QD060N00_DVT1_1
#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()
{
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()
{
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)
{
// 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();
}
else
{
#if defined(CONFIG_QISDA_AS090B00_EVT1)||defined(CONFIG_QISDA_AS090B00_EVT1_1) || defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_QD090B00_EVT1)
//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)
{
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)
{
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");
//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)
{
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)
{
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)
{
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("[HIKO RT5624] power source ON!");
//HIKO: for RT5624 audio power management process }
/* we only need to resume if we are a valid card */
if(!codec->card)
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);
}
*/
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;i<SET_CODEC_REG_INIT_NUM;i++)
{
rt5624_write(codec,Set_Codec_Reg_Init[i][0],Set_Codec_Reg_Init[i][1]);
}
rt5624_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
/* charge rt5624 caps */
if (codec->suspend_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)
{
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);
//Waiting for Reset pin ready to be working voltage
mdelay(1);
rt5624_reset(codec);
/* 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_PWR_MANAG_ADD3, 0x8000);//enable Main bias
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;i<SET_CODEC_REG_INIT_NUM;i++)
{
rt5624_write(codec,Set_Codec_Reg_Init[i][0],Set_Codec_Reg_Init[i][1]);
}
rt5624_add_controls(codec);
rt5624_add_widgets(codec);
ret = snd_soc_register_card(socdev);
if (ret < 0) {
printk(KERN_ERR "rt5624: failed to register card\n");
goto card_err;
}
//////////////////////////////////
//INT Setting
//////////////////////////////////
//HEADSET INT
//initial work queue
INIT_WORK(&g_wqReadData,rt5624_headset_det_path_route_workq);
//MIC DETECT
#if 0
//initial work queue
#if 1
INIT_WORK(&g_wqMicata,rt5624_mic_det_path_route_workq);
#endif
/* ret = request_irq(IRQ_EINT9, s3c_cha_sta_irq,
SA_INTERRUPT, "s3c2410-charging status", dev);
*/
#endif //0
//setup Headset INT
rt5624_headset_int_setup();
//HIKO: for determing the out path when boots-up with plugged headset
set_audio_out_path_dep_on_headset_jack();
return ret;
card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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()
{
return g_codecRt5624;
}
EXPORT_SYMBOL_GPL(GetRt5624CodecData);
void SetRt5624CodecData(struct snd_soc_codec *codec)
{
g_codecRt5624 = &(*codec);
}
EXPORT_SYMBOL_GPL(SetRt5624CodecData);
static irqreturn_t rt5624_headset_irq(int irq, void *data)
{
schedule_work(&g_wqReadData);
return IRQ_HANDLED;
}
static irqreturn_t rt5624_mic_irq(int irq, void *data)
{
schedule_work(&g_wqMicata);
return IRQ_HANDLED;
}
//Setting the Mic source
static snd_in_path_type set_audio_in_path_dep_on_headset_jack()
{
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
#ifdef CONFIG_QISDA_QD060N00_DVT1_1
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()
{
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()
{
u32 headset_pin_stat = get_headset_jack_status();
snd_out_path_type ret_type = SND_OUT_PATH_UNKNOWN;
if (headset_pin_stat == SND_OUT_PATH_UNKNOWN)
return ret_type;
#ifdef CONFIG_QISDA_QD060N00_DVT1_1
if (headset_pin_stat) {
#else
if (headset_pin_stat == 0) {
#endif
rt5624_AudioOutEnable(GetRt5624CodecData(), RT_WAVOUT_HP, 1);
rt5624_AudioOutEnable(GetRt5624CodecData(), 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(GetRt5624CodecData(), RT_WAVOUT_SPK, 1);
rt5624_AudioOutEnable(GetRt5624CodecData(), 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()
{
u32 read_pin;
if (!GetRt5624CodecData()) {
printk("[HIKO]GetRt5624CodecData()==NULL in get_headset_jack_status()\n");
return SND_OUT_PATH_UNKNOWN;
}
// mutex_lock(&(GetRt5624CodecData()->mutex));
mdelay(200);
read_pin = readl(S3C2410_GPFDAT) & (1<<4)/*GPF4 value*/;
// mutex_unlock(&(GetRt5624CodecData()->mutex));
return read_pin;
}
static u32 get_mic_pin_status()
{
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()
{
u32 shout_curr_reg;
mdelay(200);
if (SND_OUT_PATH_HEADSET == set_audio_out_path_dep_on_headset_jack()) {
mdelay(200);
#if defined(CONFIG_QISDA_AS090B00_EVT1) ||defined(CONFIG_QISDA_AS090B00_EVT1_1)
rt5624_get_headset_type();
#endif //CONFIG_QISDA_AS090B00_EVT1
}
}
static snd_headset_pin_type rt5624_get_headset_type()
{
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()
{
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)
{
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
//INT_EARDET
set_irq_type(IRQ_EINT4, 0x3/*IRQT_BOTHEDGE*/);
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()
{
//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)
{
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)
{
// struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
// int mode = codec->read(codec, VIRTUAL_REG_FOR_VOLUME) & 0x07;
// int mode = codec->read(codec, VIRTUAL_REG_FOR_VOLUME) & 0x0F;
// int mode = rt5624_vol_value & 0x0F;
// printk("\n[HIKO RT5624] get_volume() mode==0x%X val=0x%X\n", mode, ucontrol->value.integer.value[0]);
printk("\n[HIKO RT5624] get_volume() rt5624_vol_value=0x%X\n", rt5624_vol_value);
// ucontrol->value.integer.value[0] = mode;
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 unsigned long get_real_volume(int num)
{
unsigned long real_vol;
if (num > 10)
num = 10;
if (num < 0)
num = 0;
switch (g_snd_out_path)
{
case SND_OUT_PATH_SPEAKER:
real_vol = speaker_vol_tab[num];
break;
case SND_OUT_PATH_HEADSET:
real_vol = headset_vol_tab[num];
break;
}
printk("\n[HIKO RT5624] real_vol==0x%X in get_real_volume()\n", real_vol);
}
static int restore_volume()
{
// unsigned long mode = GetRt5624CodecData()->read(GetRt5624CodecData(), VIRTUAL_REG_FOR_VOLUME);
unsigned long vol;
unsigned long curr_reg;
struct snd_soc_codec *codec = GetRt5624CodecData();
printk("\n[HIKO RT5624] restore_volume\n");
/*
if (!ucontrol_store) {
printk("\n[HIKO RT5624] ucontrol_store not exist!!\n");
return 0;
}
*/
// if ((mode & 0x0F/*0x07*/) == ucontrol_store->value.integer.value[0])
// if ((mode & 0x0F/*0x07*/) == rt5624_vol_value)
// return 0;
#if 1
#if 0
{
u16 mute_reg = rt5624_read(codec, RT5624_MISC_CTRL) & 0xfff3;
// if (ucontrol->value.integer.value[0] == 0x0)
if (rt5624_vol_value == 0x0)
{
rt5624_write(codec, RT5624_MISC_CTRL, mute_reg | 0xc);
}
else
{
rt5624_write(codec, RT5624_MISC_CTRL, mute_reg);
}
}
#elif 1
// if (ucontrol->value.integer.value[0] == 0x0) {
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);
// mode &= 0xfff8;
// mode &= ~(0x000F);
// mode |= ucontrol->value.ingeger.value[0];
// mode |= rt5624_vol_value;
// codec->write(codec, VIRTUAL_REG_FOR_VOLUME, mode);
// vol = get_real_volume(ucontrol->value.integer.value[0]);
vol = get_real_volume(rt5624_vol_value);
curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~((0x1F<<8) | 0x1F);
mdelay(1);
curr_reg |= vol;
rt5624_write(codec, RT5624_STEREO_DAC_VOL, vol);
}
static int set_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
// snd_soc_codec *codec = GetRt5624CodecData();
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
// int mode = GetRt5624CodecData()->read(GetRt5624CodecData(), VIRTUAL_REG_FOR_VOLUME);
unsigned long mode;
// int vol;
unsigned long real_vol;
unsigned long curr_reg;
unsigned long new_vol = ucontrol->value.integer.value[0];
// mode = codec->read(codec, VIRTUAL_REG_FOR_VOLUME);
// mode = rt5624_vol_value;
// printk("\n[HIKO RT5624] set_volume() mode==0x%X ucontrol->value.integer.value[0]=0x%X\n", mode, ucontrol->value.integer.value[0]);
printk("\n[HIKO RT5624] set_volume() rt5624_vol_value=0x%X new_vol==0x%X\n", rt5624_vol_value, new_vol);
ucontrol_store = ucontrol;
// if ((mode & 0x0F/*0x07*/) == ucontrol->value.integer.value[0])
if (new_vol == rt5624_vol_value)
return 0;
#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 (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;
};
}
#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;
// mode &= 0xfff8;
// mode &= ~(0x000F);
// mode |= ucontrol->value.ingeger.value[0];
// mode |= rt5624_vol_value;
// codec->write(codec, VIRTUAL_REG_FOR_VOLUME, mode);
// real_vol = get_real_volume(ucontrol->value.integer.value[0]);
real_vol = get_real_volume(new_vol);
curr_reg = rt5624_read(codec, RT5624_STEREO_DAC_VOL) & ~((0x1F<<8) | 0x1F);
mdelay(1);
curr_reg |= real_vol;
rt5624_write(codec, RT5624_STEREO_DAC_VOL, real_vol);
}
//HIKO: For Volume 10 step setting }
static void print_codec_regs()
{
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()
{
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("\n========[HIKO RT5624 rt5624_turn_off_codec_hw()========\n");
rt5624_power(false);
rt5624_audio_reset_off();
rt5624_i2s_release();
mdelay(1);
}
static void rt5624_turn_on_codec_hw()
{
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();
rt5624_reset(GetRt5624CodecData());
mdelay(1);
rt5624_write(GetRt5624CodecData(), RT5624_PD_CTRL_STAT, 0x0000);//enable all PR bit
rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD3, 0x8000);//enable Main bias
rt5624_write(GetRt5624CodecData(), RT5624_PWR_MANAG_ADD2, 0x2000);//enable Vref
for(i=0;i<SET_CODEC_REG_INIT_NUM;i++)
{
rt5624_write(GetRt5624CodecData(),Set_Codec_Reg_Init[i][0],Set_Codec_Reg_Init[i][1]);
}
rt5624_dapm_event(GetRt5624CodecData(), SNDRV_CTL_POWER_D3hot);
/* charge rt5624 caps */
if (GetRt5624CodecData()->suspend_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");