3205 lines
91 KiB
C
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");
|