6 RK2 SPKOUT Playback Switch
\r
7 RK3 SPKOUT Playback Volume
\r
8 RK4 PCM Playback Volume
\r
15 RK9 HPOUT Playback Switch
\r
16 RKA HPOUT Playback Volume
\r
18 RKC AUXOUT Playback Switch
\r
19 RKD AUXOUT Playback Volume
\r
22 RKG DAC Mixer Playback Switch
\r
23 RKH HIFI DAC Playback Switch
\r
24 RKI Mic1 Playback Switch
\r
25 RKJ Phone Playback Switch
\r
26 RKK Mic1 Capture Switch
\r
27 RKL Phone Capture Switch
\r
28 RKM Voice DAC Playback Switch
\r
32 #include <linux/module.h>
\r
33 #include <linux/moduleparam.h>
\r
34 #include <linux/kernel.h>
\r
35 #include <linux/init.h>
\r
36 #include <linux/delay.h>
\r
37 #include <linux/pm.h>
\r
38 #include <linux/i2c.h>
\r
39 #include <linux/platform_device.h>
\r
40 #include <linux/spi/spi.h>
\r
41 #include <linux/jiffies.h>
\r
42 #include <asm/delay.h>
\r
43 #include <sound/core.h>
\r
44 #include <sound/pcm.h>
\r
45 #include <sound/pcm_params.h>
\r
46 #include <sound/soc.h>
\r
47 #include <sound/soc-dapm.h>
\r
48 #include <sound/initval.h>
\r
49 #include <sound/tlv.h>
\r
50 #include <asm/div64.h>
\r
56 #include <linux/ioctl.h>
\r
57 #include <linux/types.h>
\r
62 #define DBG(x...) printk(KERN_INFO x)
\r
64 #define DBG(x...) do { } while (0)
\r
67 #define AUDIO_NAME "rt5625"
\r
68 #define RT5625_VERSION "0.03 alsa 1.0.21"
\r
69 #define ALSA_SOC_VERSION "1.0.21"
\r
71 #define RT5625_EQ_FUNC_ENA 0
\r
73 static void hp_depop_mode2(struct snd_soc_codec *codec);
\r
74 static void hp_mute_unmute_depop(struct snd_soc_codec *codec,int mute);
\r
76 struct rt5625_priv {
\r
77 unsigned int stereo_sysclk;
\r
78 unsigned int voice_sysclk;
\r
81 struct rt5625_init_reg {
\r
86 static struct rt5625_init_reg rt5625_init_list[] = {
\r
88 {RT5625_HP_OUT_VOL , 0x8888}, //default is -12db
\r
89 {RT5625_SPK_OUT_VOL , 0x8080}, //default is 0db
\r
90 {RT5625_DAC_AND_MIC_CTRL , 0xee03}, //DAC to hpmixer
\r
91 {RT5625_OUTPUT_MIXER_CTRL , 0x0748}, //all output from hpmixer
\r
92 {RT5625_MIC_CTRL , 0x0500}, //mic boost 20db
\r
93 {RT5625_ADC_REC_MIXER , 0x3f3f}, //record source from mic1
\r
94 {RT5625_GEN_CTRL_REG1 , 0x0c0a}, //speaker vdd ratio is 1
\r
95 {RT5625_ADC_REC_GAIN , 0xd5d5}, //gain 15db of ADC by default
\r
99 #define RT5625_INIT_REG_NUM ARRAY_SIZE(rt5625_init_list)
\r
101 #if (RT5625_EQ_FUNC_ENA==1)
\r
102 //*************************************************************************************************
\r
104 //*************************************************************************************************
\r
118 typedef struct _HW_EQ_PRESET
\r
127 HW_EQ_PRESET HwEq_Preset[]={
\r
128 /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0x6e*/
\r
129 {NORMAL,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x0000},
\r
130 {CLUB ,{0x1C10,0x0000,0xC1CC,0x1E5D,0x0699,0xCD48,0x188D,0x0699,0xC3B6,0x1CD0,0x0699,0x0436,0x0000},0x800E},
\r
131 {DANCE ,{0x1F2C,0x095B,0xC071,0x1F95,0x0616,0xC96E,0x1B11,0xFC91,0xDCF2,0x1194,0xFAF2,0x0436,0x0000},0x800F},
\r
132 {LIVE ,{0x1EB5,0xFCB6,0xC24A,0x1DF8,0x0E7C,0xC883,0x1C10,0x0699,0xDA41,0x1561,0x0295,0x0436,0x0000},0x800F},
\r
133 {POP ,{0x1EB5,0xFCB6,0xC1D4,0x1E5D,0x0E23,0xD92E,0x16E6,0xFCB6,0x0000,0x0969,0xF988,0x0436,0x0000},0x800F},
\r
134 {ROCK ,{0x1EB5,0xFCB6,0xC071,0x1F95,0x0424,0xC30A,0x1D27,0xF900,0x0C5D,0x0FC7,0x0E23,0x0436,0x0000},0x800F},
\r
135 {OPPO ,{0x0000,0x0000,0xCA4A,0x17F8,0x0FEC,0xCA4A,0x17F8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x800F},
\r
136 {TREBLE,{0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x188D,0x1699},0x8010},
\r
137 {BASS ,{0x1A43,0x0C00,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000},0x8001},
\r
142 //*************************************************************************************************
\r
143 //*************************************************************************************************
\r
146 * bit[0] for linein playback switch
\r
153 #define HPL_MIXER 0x80
\r
154 #define HPR_MIXER 0x82
\r
155 static unsigned int reg80 = 0, reg82 = 0;
\r
158 * bit[0][1][2] use for aec control
\r
160 * bit[4] for SPKL pga
\r
161 * bit[5] for SPKR pga
\r
162 * bit[6] for hpl pga
\r
163 * bit[7] for hpr pga
\r
164 * bit[8] for dump dsp
\r
165 * bit[12~15] for eq function
\r
167 #define VIRTUAL_REG_FOR_MISC_FUNC 0x84
\r
168 static unsigned int reg84 = 0;
\r
171 static const u16 rt5625_reg[] = {
\r
172 0x59b4, 0x8080, 0x8080, 0x8080, /*reg00-reg06*/
\r
173 0xc800, 0xe808, 0x1010, 0x0808, /*reg08-reg0e*/
\r
174 0xe0ef, 0xcbcb, 0x7f7f, 0x0000, /*reg10-reg16*/
\r
175 0xe010, 0x0000, 0x8008, 0x2007, /*reg18-reg1e*/
\r
176 0x0000, 0x0000, 0x00c0, 0xef00, /*reg20-reg26*/
\r
177 0x0000, 0x0000, 0x0000, 0x0000, /*reg28-reg2e*/
\r
178 0x0000, 0x0000, 0x0000, 0x0000, /*reg30-reg36*/
\r
179 0x0000, 0x0000, 0x0000, 0x0000, /*reg38-reg3e*/
\r
180 0x0c0a, 0x0000, 0x0000, 0x0000, /*reg40-reg46*/
\r
181 0x0029, 0x0000, 0xbe3e, 0x3e3e, /*reg48-reg4e*/
\r
182 0x0000, 0x0000, 0x803a, 0x0000, /*reg50-reg56*/
\r
183 0x0000, 0x0009, 0x0000, 0x3000, /*reg58-reg5e*/
\r
184 0x3075, 0x1010, 0x3110, 0x0000, /*reg60-reg66*/
\r
185 0x0553, 0x0000, 0x0000, 0x0000, /*reg68-reg6e*/
\r
186 0x0000, 0x0000, 0x0000, 0x0000, /*reg70-reg76*/
\r
187 0x0000, 0x0000, 0x0000, 0x0000, /*reg78-reg7e*/
\r
191 Voice_DSP_Reg VODSP_AEC_Init_Value[]=
\r
227 {0x230C, 0x0000}, //to enable VODSP AEC function
\r
231 #define SET_VODSP_REG_INIT_NUM ARRAY_SIZE(VODSP_AEC_Init_Value)
\r
232 static struct snd_soc_device *rt5625_socdev;
\r
234 static inline unsigned int rt5625_read_reg_cache(struct snd_soc_codec *codec,
\r
237 u16 *cache = codec->reg_cache;
\r
241 return cache[reg / 2];
\r
245 static unsigned int rt5625_read_hw_reg(struct snd_soc_codec *codec, unsigned int reg)
\r
248 unsigned int value = 0x0;
\r
252 i2c_master_reg8_recv(codec->control_data,reg,data,2,100 * 1000);
\r
254 value = (data[0]<<8) | data[1];
\r
256 DBG(KERN_INFO "rt5625_read ok, reg = %x, value = %x\n", reg, value);
\r
262 static unsigned int rt5625_read(struct snd_soc_codec *codec, unsigned int reg)
\r
267 return (reg == 0x80) ? reg80 : ((reg == 0x82) ? reg82 : reg84);
\r
269 return rt5625_read_hw_reg(codec, reg);
\r
273 static inline void rt5625_write_reg_cache(struct snd_soc_codec *codec,
\r
274 unsigned int reg, unsigned int value)
\r
276 u16 *cache = codec->reg_cache;
\r
279 cache[reg / 2] = value;
\r
282 static int rt5625_write(struct snd_soc_codec *codec, unsigned int reg,
\r
283 unsigned int value)
\r
286 unsigned int *regvalue = NULL;
\r
289 data[1] = (value & 0xff00) >> 8;
\r
290 data[2] = value & 0x00ff;
\r
296 regvalue = ((reg == 0x80) ? ®80 : ((reg == 0x82) ? ®82 : ®84));
\r
298 DBG("rt5625_write ok, reg = %x, value = %x\n", reg, value);
\r
301 rt5625_write_reg_cache(codec, reg, value);
\r
303 if (codec->hw_write(codec->control_data, data, 3) == 3)
\r
305 DBG("rt5625_write ok, reg = %x, value = %x\n", reg, value);
\r
310 printk("rt5625_write fail\n");
\r
315 int rt5625_write_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask)
\r
318 unsigned char RetVal=0;
\r
319 unsigned int CodecData;
\r
321 DBG("rt5625_write_mask ok, reg = %x, value = %x ,mask= %x\n", reg, value,mask);
\r
328 CodecData=rt5625_read(codec,reg);
\r
330 CodecData|=(value&mask);
\r
331 RetVal=rt5625_write(codec,reg,CodecData);
\r
335 RetVal=rt5625_write(codec,reg,value);
\r
342 void rt5625_write_index(struct snd_soc_codec *codec, unsigned int reg,
\r
343 unsigned int value)
\r
346 rt5625_write(codec,0x6a,reg);
\r
347 rt5625_write(codec,0x6c,value);
\r
350 unsigned int rt5625_read_index(struct snd_soc_codec *codec, unsigned int reg)
\r
352 unsigned int value = 0x0;
\r
353 rt5625_write(codec,0x6a,reg);
\r
354 value=rt5625_read(codec,0x6c);
\r
359 void rt5625_write_index_mask(struct snd_soc_codec *codec, unsigned int reg,unsigned int value,unsigned int mask)
\r
362 // unsigned char RetVal=0;
\r
363 unsigned int CodecData;
\r
365 DBG("rt5625_write_index_mask ok, reg = %x, value = %x ,mask= %x\n", reg, value,mask);
\r
372 CodecData=rt5625_read_index(codec,reg);
\r
374 CodecData|=(value&mask);
\r
375 rt5625_write_index(codec,reg,CodecData);
\r
379 rt5625_write_index(codec,reg,value);
\r
383 //#define rt5625_write_mask(c, reg, value, mask) snd_soc_update_bits(c, reg, mask, value)
\r
385 #define rt5625_reset(c) rt5625_write(c, RT5625_RESET, 0)
\r
387 /*read/write dsp reg*/
\r
388 static int rt5625_wait_vodsp_i2c_done(struct snd_soc_codec *codec)
\r
390 unsigned int checkcount = 0, vodsp_data;
\r
392 vodsp_data = rt5625_read(codec, RT5625_VODSP_REG_CMD);
\r
393 while(vodsp_data & VODSP_BUSY)
\r
395 if(checkcount > 10)
\r
397 vodsp_data = rt5625_read(codec, RT5625_VODSP_REG_CMD);
\r
403 static int rt5625_write_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg, unsigned int value)
\r
407 if(ret != rt5625_wait_vodsp_i2c_done(codec))
\r
410 rt5625_write(codec, RT5625_VODSP_REG_ADDR, vodspreg);
\r
411 rt5625_write(codec, RT5625_VODSP_REG_DATA, value);
\r
412 rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_WRITE_ENABLE | VODSP_CMD_MW);
\r
418 static unsigned int rt5625_read_vodsp_reg(struct snd_soc_codec *codec, unsigned int vodspreg)
\r
421 unsigned int nDataH, nDataL;
\r
422 unsigned int value;
\r
424 if(ret != rt5625_wait_vodsp_i2c_done(codec))
\r
427 rt5625_write(codec, RT5625_VODSP_REG_ADDR, vodspreg);
\r
428 rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_MR);
\r
430 if (ret != rt5625_wait_vodsp_i2c_done(codec))
\r
432 rt5625_write(codec, RT5625_VODSP_REG_ADDR, 0x26);
\r
433 rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR);
\r
435 if(ret != rt5625_wait_vodsp_i2c_done(codec))
\r
437 nDataH = rt5625_read(codec, RT5625_VODSP_REG_DATA);
\r
438 rt5625_write(codec, RT5625_VODSP_REG_ADDR, 0x25);
\r
439 rt5625_write(codec, RT5625_VODSP_REG_CMD, VODSP_READ_ENABLE | VODSP_CMD_RR);
\r
441 if(ret != rt5625_wait_vodsp_i2c_done(codec))
\r
443 nDataL = rt5625_read(codec, RT5625_VODSP_REG_DATA);
\r
444 value = ((nDataH & 0xff) << 8) |(nDataL & 0xff);
\r
445 DBG("%s vodspreg=0x%x, value=0x%x\n", __func__, vodspreg, value);
\r
449 static int rt5625_reg_init(struct snd_soc_codec *codec)
\r
453 for (i = 0; i < RT5625_INIT_REG_NUM; i++)
\r
454 rt5625_write(codec, rt5625_init_list[i].reg_index, rt5625_init_list[i].reg_value);
\r
459 //*************************************************************************************************
\r
460 //*************************************************************************************************
\r
461 #if (RT5625_EQ_FUNC_ENA==1)
\r
463 static void rt5625_update_eqmode(struct snd_soc_codec *codec, int mode)
\r
469 /*clear EQ parameter*/
\r
470 for(HwEqIndex=0;HwEqIndex<=0x0C;HwEqIndex++)
\r
472 rt5625_write_index(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex]);
\r
475 rt5625_write_mask(codec, 0x6e,0x0,EN_HW_EQ_BLK | EN_HW_EQ_HPF | EN_HW_EQ_BP3 | EN_HW_EQ_BP2 | EN_HW_EQ_BP1 | EN_HW_EQ_LPF); /*disable EQ block*/
\r
479 /*Fill EQ parameter*/
\r
480 for(HwEqIndex=0;HwEqIndex<=0x0C;HwEqIndex++)
\r
482 rt5625_write_index(codec, HwEqIndex, HwEq_Preset[mode].EqValue[HwEqIndex]);
\r
486 rt5625_write_mask(codec, 0x6e,HwEq_Preset[mode].HwEQCtrl,EN_HW_EQ_BLK | EN_HW_EQ_HPF | EN_HW_EQ_BP3 | EN_HW_EQ_BP2 | EN_HW_EQ_BP1 | EN_HW_EQ_LPF);
\r
488 //update EQ parameter
\r
489 rt5625_write_mask(codec, 0x6e,0x0080,0x0080);
\r
494 static int rt5625_eq_sel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
\r
496 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
\r
497 u16 Virtual_reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC);
\r
498 int rt5625_mode=((Virtual_reg)&0xf000)>>12;
\r
500 if ( rt5625_mode == ucontrol->value.integer.value[0])
\r
503 rt5625_update_eqmode(codec, ucontrol->value.enumerated.item[0]);
\r
505 Virtual_reg &= 0x0fff;
\r
506 Virtual_reg |= (ucontrol->value.integer.value[0])<<12;
\r
507 rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, Virtual_reg);
\r
512 //*************************************************************************************************
\r
513 //*************************************************************************************************
\r
514 static const char *rt5625_aec_path_sel[] = {"aec func disable","aec func for pcm in/out",
\r
515 "aec func for iis in/out","aec func for analog in/out"}; /*0*/
\r
516 static const char *rt5625_spk_out_sel[] = {"Class AB", "Class D"}; /*1*/
\r
517 static const char *rt5625_spk_l_source_sel[] = {"LPRN", "LPRP", "LPLN", "MM"}; /*2*/
\r
518 static const char *rt5625_spkmux_source_sel[] = {"VMID", "RK11",
\r
519 "RK12", "RK13"}; /*3*/
\r
520 static const char *rt5625_hplmux_source_sel[] = {"VMID","RK71"}; /*4*/
\r
521 static const char *rt5625_hprmux_source_sel[] = {"VMID","RK81"}; /*5*/
\r
522 static const char *rt5625_auxmux_source_sel[] = {"VMID", "RK11",
\r
523 "RK12", "RK13"}; /*6*/
\r
524 static const char *rt5625_spkamp_ratio_sel[] = {"2.25 Vdd", "2.00 Vdd",
\r
525 "1.75 Vdd", "1.50 Vdd", "1.25 Vdd", "1.00 Vdd"}; /*7*/
\r
526 static const char *rt5625_mic1_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"}; /*8*/
\r
527 static const char *rt5625_mic2_boost_sel[] = {"Bypass", "+20db", "+30db", "+40db"}; /*9*/
\r
528 static const char *rt5625_dmic_boost_sel[] = {"Bypass", "+6db", "+12db", "+18db",
\r
529 "+24db", "+30db", "+36db", "+42db"}; /*10*/
\r
530 static const char *rt5625_adcr_func_sel[] = {"Stereo ADC", "Voice ADC",
\r
531 "VoDSP Interface", "PDM Slave Interface"}; /*11*/
\r
532 #if (RT5625_EQ_FUNC_ENA==1)
\r
533 static const char *rt5625_eq_sel[] = {"NORMAL", "CLUB","DANCE", "LIVE","POP", /*12*/
\r
534 "ROCK", "OPPO", "TREBLE", "BASS"};
\r
537 static const struct soc_enum rt5625_enum[] = {
\r
539 SOC_ENUM_SINGLE(VIRTUAL_REG_FOR_MISC_FUNC, 0, 4, rt5625_aec_path_sel), /*0*/
\r
540 SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 13, 2, rt5625_spk_out_sel), /*1*/
\r
541 SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 14, 4, rt5625_spk_l_source_sel), /*2*/
\r
542 SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 10, 4, rt5625_spkmux_source_sel),/*3*/
\r
543 SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 9, 2, rt5625_hplmux_source_sel), /*4*/
\r
544 SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 8, 2, rt5625_hprmux_source_sel),/*5*/
\r
545 SOC_ENUM_SINGLE(RT5625_OUTPUT_MIXER_CTRL, 6, 4, rt5625_auxmux_source_sel),/*6*/
\r
546 SOC_ENUM_SINGLE(RT5625_GEN_CTRL_REG1, 1, 6, rt5625_spkamp_ratio_sel), /*7*/
\r
547 SOC_ENUM_SINGLE(RT5625_MIC_CTRL, 10, 4, rt5625_mic1_boost_sel), /*8*/
\r
548 SOC_ENUM_SINGLE(RT5625_MIC_CTRL, 8, 4, rt5625_mic2_boost_sel), /*9*/
\r
549 SOC_ENUM_SINGLE(RT5625_DMIC_CTRL, 0, 8, rt5625_dmic_boost_sel), /*10*/
\r
550 SOC_ENUM_SINGLE(RT5625_DAC_ADC_VODAC_FUN_SEL, 4, 4, rt5625_adcr_func_sel), /*11*/
\r
551 #if (RT5625_EQ_FUNC_ENA==1)
\r
552 SOC_ENUM_SINGLE(VIRTUAL_REG_FOR_MISC_FUNC, 12, 9, rt5625_eq_sel), /*EQ mode select mode 12*/
\r
558 //*****************************************************************************
\r
559 //function:Enable the Voice PCM interface Path
\r
560 //*****************************************************************************
\r
561 static int ConfigPcmVoicePath(struct snd_soc_codec *codec,unsigned int bEnableVoicePath,unsigned int mode)
\r
564 if(bEnableVoicePath)
\r
566 //Power on DAC reference
\r
567 rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD1,PWR_DAC_REF|PWR_VOICE_DF2SE,PWR_DAC_REF|PWR_VOICE_DF2SE);
\r
568 //Power on Voice DAC/ADC
\r
569 rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD2,PWR_VOICE_CLOCK,PWR_VOICE_CLOCK);
\r
570 //routing voice to HPMixer
\r
571 rt5625_write_mask(codec,RT5625_VOICE_DAC_OUT_VOL,0,M_V_DAC_TO_HP_MIXER);
\r
575 case PCM_SLAVE_MODE_B: //8kHz sampling rate,16 bits PCM mode and Slave mode,PCM mode is B,MCLK=24.576MHz from Oscillator.
\r
576 //CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08C00000,PSKEY_FORMAT=0x0060
\r
578 //Enable GPIO 1,3,4,5 to voice interface
\r
579 //Set I2S to Slave mode
\r
580 //Voice I2S SYSCLK Source select Main SYSCLK
\r
581 //Set voice I2S VBCLK Polarity to Invert
\r
582 //Set Data length to 16 bit
\r
583 //set Data Fomrat to PCM mode B
\r
584 //the register 0x36 value's should is 0xC083
\r
585 rt5625_write(codec,RT5625_EXTEND_SDP_CTRL,0xC083);
\r
587 //Set LRCK voice select divide 32
\r
588 //set voice blck select divide 6 and 8
\r
589 //voice filter clock divide 3 and 16
\r
590 //the register 0x64 value's should is 0x5524
\r
591 rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524);
\r
595 case PCM_SLAVE_MODE_A: //8kHz sampling rate,16 bits PCM and Slave mode,PCM mode is A,MCLK=24.576MHz from Oscillator.
\r
596 //CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08C00004,PSKEY_FORMAT=0x0060
\r
598 //Enable GPIO 1,3,4,5 to voice interface
\r
599 //Set I2S to Slave mode
\r
600 //Voice I2S SYSCLK Source select Main SYSCLK
\r
601 //Set voice i2s VBCLK Polarity to Invert
\r
602 //Set Data length to 16 bit
\r
603 //set Data Fomrat to PCM mode A
\r
604 //the register 0x36 value's should is 0xC082
\r
605 rt5625_write(codec,RT5625_EXTEND_SDP_CTRL,0xC082);
\r
607 //Set LRCK voice select divide 64
\r
608 //set voice blck select divide 6 and 8
\r
609 //voice filter clock divide 3 and 16
\r
610 //the register 0x64 value's should is 0x5524
\r
611 rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524);
\r
615 case PCM_MASTER_MODE_B: //8kHz sampling rate,16 bits PCM and Master mode,PCM mode is B,Clock from PLL OUT
\r
616 //CSR PSKEY_PCM_CONFIG32 (HEX) = 0x08000002,PSKEY_FORMAT=0x0060
\r
618 //Enable GPIO 1,3,4,5 to voice interface
\r
619 //Set I2S to master mode
\r
620 //Set voice i2s VBCLK Polarity to Invert
\r
621 //Set Data length to 16 bit
\r
622 //set Data Fomrat to PCM mode B
\r
623 //the register 0x36 value's should is 0x8083
\r
624 rt5625_write(codec,RT5625_EXTEND_SDP_CTRL,0x8083);
\r
626 //Set LRCK voice select divide 64
\r
627 //set voice blck select divide 6 and 8
\r
628 //voice filter clock divide 3 and 16
\r
629 //the register 0x64 value's should is 0x5524
\r
630 rt5625_write(codec,RT5625_VOICE_DAC_PCMCLK_CTRL1,0x5524);
\r
642 //Power down Voice Different to sing-end power
\r
643 rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD1,0,PWR_VOICE_DF2SE);
\r
644 //Power down Voice DAC/ADC
\r
645 rt5625_write_mask(codec,RT5625_PWR_MANAG_ADD2,0,PWR_VOICE_CLOCK);
\r
646 //Disable Voice PCM interface
\r
647 rt5625_write_mask(codec,RT5625_EXTEND_SDP_CTRL,0,EXT_I2S_FUNC_ENABLE);
\r
653 static int init_vodsp_aec(struct snd_soc_codec *codec)
\r
658 /*disable LDO power*/
\r
659 rt5625_write_mask(codec, RT5625_LDO_CTRL,0,LDO_ENABLE);
\r
661 rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA);
\r
662 /*enable LDO power and set output voltage to 1.2V*/
\r
663 rt5625_write_mask(codec, RT5625_LDO_CTRL,LDO_ENABLE|LDO_OUT_VOL_CTRL_1_20V,LDO_ENABLE|LDO_OUT_VOL_CTRL_MASK);
\r
665 /*enable power of VODSP I2C interface*/
\r
666 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP);
\r
668 rt5625_write_mask(codec, RT5625_VODSP_CTL,0,VODSP_NO_RST_MODE_ENA); /*Reset VODSP*/
\r
670 rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_NO_RST_MODE_ENA,VODSP_NO_RST_MODE_ENA); /*set VODSP to non-reset status*/
\r
673 /*initize AEC paramter*/
\r
674 for(i = 0; i < SET_VODSP_REG_INIT_NUM; i++)
\r
676 ret = rt5625_write_vodsp_reg(codec, VODSP_AEC_Init_Value[i].VoiceDSPIndex,VODSP_AEC_Init_Value[i].VoiceDSPValue);
\r
681 schedule_timeout_uninterruptible(msecs_to_jiffies(10));
\r
686 //***********************************************************************************************
\r
687 //function:Enable/Disable the vodsp interface Path
\r
688 //For system clock only suport specific clock,realtek suggest customer to use 24.576Mhz or 22.5792Mhz
\r
689 //clock fro MCLK(MCLK=48k*512 or 44.1k*512Mhz)
\r
690 //***********************************************************************************************
\r
691 static int set_vodsp_aec_path(struct snd_soc_codec *codec, unsigned int mode)
\r
697 case PCM_IN_PCM_OUT:
\r
699 ConfigPcmVoicePath(codec,1,PCM_MASTER_MODE_B);
\r
701 rt5625_write_mask(codec, 0x26,0x0300,0x0300);
\r
702 rt5625_write_mask(codec, RT5625_VODSP_PDM_CTL,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_VOICE|VOICE_PCM_S_SEL_AEC_TXDP
\r
703 ,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|VOICE_PCM_S_SEL_MASK);
\r
704 rt5625_write_mask(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|VODAC_SOUR_SEL_VODSP_TXDC
\r
705 ,ADCR_FUNC_SEL_MASK|VODAC_SOUR_SEL_MASK);
\r
706 rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_LRCK_SEL_8K,VODSP_LRCK_SEL_MASK);
\r
707 rt5625_write_mask(codec, 0x26,0x0000,0x0300);
\r
708 //set input&output path and power
\r
709 rt5625_write_mask(codec, 0x3a,0x0c8f,0x0c8f);//power on related bit
\r
710 rt5625_write_mask(codec, 0x3c,0xa4cb,0xa4cb);//power on related bit
\r
711 rt5625_write_mask(codec, 0x3e,0x3302,0xf302);//power on related bit
\r
713 rt5625_write(codec, 0x10, 0xee0f);//mute DAC to hpmixer
\r
714 rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode
\r
715 rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db
\r
716 rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db
\r
717 rt5625_write(codec, 0x14, 0x7f3f);//Mic1->ADCMixer_R
\r
718 rt5625_write(codec, 0x18, 0xa010);//VoDAC to speakerMixer,0db
\r
719 rt5625_write(codec, 0x1c, 0x8808);//speaker source from speakermixer
\r
721 rt5625_write_mask(codec, 0x02,0x0000,0x8080); //unmute speaker
\r
726 case ANALOG_IN_ANALOG_OUT:
\r
727 rt5625_write_mask(codec, 0x26,0x0300,0x0300);
\r
728 rt5625_write_mask(codec, RT5625_VODSP_PDM_CTL,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_ADCL|VOICE_PCM_S_SEL_AEC_TXDP
\r
729 ,VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|VOICE_PCM_S_SEL_MASK);
\r
730 rt5625_write_mask(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|VODAC_SOUR_SEL_VODSP_TXDC|DAC_FUNC_SEL_VODSP_TXDP|ADCL_FUNC_SEL_VODSP
\r
731 ,ADCR_FUNC_SEL_MASK|VODAC_SOUR_SEL_MASK|DAC_FUNC_SEL_MASK|ADCL_FUNC_SEL_MASK);
\r
732 rt5625_write_mask(codec, RT5625_VODSP_CTL,VODSP_LRCK_SEL_16K,VODSP_LRCK_SEL_MASK);
\r
733 rt5625_write_mask(codec, 0x26,0x0000,0x0300);
\r
734 //set input&output path and power
\r
735 rt5625_write_mask(codec, 0x3a,0xcc8f,0xcc8f);//power on related bit
\r
736 rt5625_write_mask(codec, 0x3c,0xa7cf,0xa7cf);//power on related bit
\r
737 rt5625_write_mask(codec, 0x3e,0xf312,0xf312);//power on related bit
\r
739 rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode
\r
740 rt5625_write(codec, 0x08, 0xe800);//set phone in to differential mode
\r
741 rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db
\r
742 rt5625_write(codec, 0x14, 0x773f);//Mic1->ADCMixer_R,phone in-->ADCMixer_L
\r
743 rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db
\r
744 rt5625_write(codec, 0x1c, 0x88c8);//speaker from spkmixer,monoOut from monoMixer
\r
745 rt5625_write(codec, 0x18, 0xA010);//unmute VoDAC to spkmixer
\r
746 rt5625_write(codec, 0x10, 0xee0e);//unmute DAC to monoMixer
\r
747 rt5625_write(codec, 0x62, 0x2222);
\r
748 rt5625_write(codec, 0x64, 0x3122);
\r
749 rt5625_write_mask(codec, 0x02,0x0000,0x8080); //unmute speaker
\r
750 rt5625_write_mask(codec, 0x06,0x0000,0x8080); //unmute auxout
\r
753 case DAC_IN_ADC_OUT:
\r
754 rt5625_write_mask(codec, 0x26,0x0300,0x0300);
\r
755 rt5625_write_mask(codec,RT5625_DAC_ADC_VODAC_FUN_SEL,ADCR_FUNC_SEL_PDM|DAC_FUNC_SEL_VODSP_TXDC
\r
756 ,ADCR_FUNC_SEL_MASK|DAC_FUNC_SEL_MASK);
\r
757 rt5625_write_mask(codec,RT5625_VODSP_PDM_CTL,VODSP_SRC1_PWR|VODSP_SRC2_PWR|VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_SRC1|REC_S_SEL_SRC2,
\r
758 VODSP_SRC1_PWR|VODSP_SRC2_PWR|VODSP_RXDP_PWR|VODSP_RXDP_S_SEL_MASK|REC_S_SEL_MASK);
\r
759 rt5625_write_mask(codec,RT5625_VODSP_CTL,VODSP_LRCK_SEL_16K,VODSP_LRCK_SEL_MASK);
\r
760 rt5625_write_mask(codec, 0x26,0x0000,0x0300);
\r
761 //set input&output path and power
\r
762 rt5625_write_mask(codec, 0x3a,0xcc0f,0xcc0f);//power on related bit
\r
763 rt5625_write_mask(codec, 0x3c,0xa7cb,0xa7cb);//power on related bit
\r
764 rt5625_write_mask(codec, 0x3e,0x3302,0x3302);//power on related bit
\r
766 rt5625_write(codec, 0x0e, 0x8808);//set Mic1 to differential mode
\r
767 rt5625_write(codec, 0x22, 0x0000);//Mic boost 0db
\r
768 rt5625_write(codec, 0x14, 0x7f3f);//Mic1->ADCMixer_R
\r
769 rt5625_write(codec, 0x12, 0xCBD3);//ADC_Mixer_R boost 10.5 db
\r
770 rt5625_write(codec, 0x1c, 0x8808);//speaker out from spkMixer
\r
771 rt5625_write(codec, 0x10, 0xee0d);//unmute DAC to spkMixer
\r
772 rt5625_write(codec, 0x60, 0x3075);
\r
773 rt5625_write(codec, 0x62, 0x1010);
\r
774 rt5625_write_mask(codec, 0x02,0x0000,0x8080); //unmute speaker
\r
778 case VODSP_AEC_DISABLE:
\r
780 rt5625_write_mask(codec, 0x02,0x8080,0x8080);//mute speaker out
\r
781 rt5625_write_mask(codec, 0x06,0x8080,0x8080);//mute auxout
\r
782 rt5625_write(codec, 0x22, 0x0500);//Mic boost 20db by default
\r
783 rt5625_write(codec, 0x14, 0x3f3f);//record from Mic1 by default
\r
784 rt5625_write(codec, 0x12, 0xD5D5);//ADC_Mixer_R boost 15 db by default
\r
785 rt5625_write(codec, 0x1c, 0x0748);//all output from HPmixer by default
\r
786 rt5625_write(codec, 0x10, 0xee03);//DAC to HPmixer by default
\r
787 rt5625_write(codec, 0x18, 0xe010);//mute VoDAC to mixer by default
\r
788 rt5625_write_mask(codec, 0x26,0x0300,0x0300);
\r
789 /*set stereo DAC&Voice DAC&Stereo ADC function select to default*/
\r
790 rt5625_write(codec, RT5625_DAC_ADC_VODAC_FUN_SEL,0);
\r
791 /*set VODSP&PDM Control to default*/
\r
792 rt5625_write(codec, RT5625_VODSP_PDM_CTL,0);
\r
793 rt5625_write_mask(codec, 0x26,0x0000,0x0300);
\r
794 rt5625_write_mask(codec, 0x3e,0x0000,0xf312);//power down related bit
\r
795 rt5625_write_mask(codec, 0x3a,0x0000,0xcc8d);//power down related bit
\r
796 rt5625_write_mask(codec, 0x3c,0x0000,0x07cf);//power down related bit
\r
805 static int enable_vodsp_aec(struct snd_soc_codec *codec, unsigned int VodspAEC_En, unsigned int AEC_mode)
\r
810 if (VodspAEC_En != 0)
\r
813 //enable power of VODSP I2C interface & VODSP interface
\r
814 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP);
\r
815 //enable power of VODSP I2S interface
\r
816 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1,PWR_I2S_INTERFACE,PWR_I2S_INTERFACE);
\r
817 //select input/output of VODSP AEC
\r
818 set_vodsp_aec_path(codec, AEC_mode);
\r
823 //disable VODSP AEC path
\r
824 set_vodsp_aec_path(codec, VODSP_AEC_DISABLE);
\r
825 //set VODSP AEC to power down mode
\r
826 rt5625_write_mask(codec, RT5625_VODSP_CTL,0,VODSP_NO_PD_MODE_ENA);
\r
827 //disable power of VODSP I2C interface & VODSP interface
\r
828 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3,0,PWR_VODSP_INTERFACE|PWR_I2C_FOR_VODSP);
\r
834 static void rt5625_aec_config(struct snd_soc_codec *codec, unsigned int mode)
\r
836 DBG("rt5625_aec_config %d\n",mode);
\r
838 if (mode == VODSP_AEC_DISABLE)
\r
840 enable_vodsp_aec(codec,0, mode);
\r
841 /*disable LDO power*/
\r
842 rt5625_write_mask(codec, RT5625_LDO_CTRL,0,LDO_ENABLE);
\r
846 init_vodsp_aec(codec);
\r
848 enable_vodsp_aec(codec,1, mode);
\r
851 //****************************************************************************************************************
\r
853 //*function:disable rt5625's function.
\r
856 //****************************************************************************************************************
\r
857 static int rt5625_func_aec_disable(struct snd_soc_codec *codec,int mode)
\r
862 case RT5625_AEC_PCM_IN_OUT:
\r
863 case RT5625_AEC_IIS_IN_OUT:
\r
864 case RT5625_AEC_ANALOG_IN_OUT:
\r
866 rt5625_aec_config(codec,VODSP_AEC_DISABLE); //disable AEC function and path
\r
879 static int rt5625_get_dsp_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
\r
881 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
\r
882 /*cause we choose bit[0][1] to store the mode type*/
\r
883 int mode = (rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC)) & 0x03;
\r
885 ucontrol->value.integer.value[0] = mode;
\r
890 static int rt5625_set_dsp_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
\r
892 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
\r
893 u16 Virtual_reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC);
\r
894 int rt5625_mode=(Virtual_reg)&0x03;
\r
896 DBG("rt5625_mode=%d,value[0]=%ld,Virtual_reg=%x\n",rt5625_mode,ucontrol->value.integer.value[0],Virtual_reg);
\r
898 if ( rt5625_mode == ucontrol->value.integer.value[0])
\r
901 switch(ucontrol->value.integer.value[0])
\r
903 case RT5625_AEC_PCM_IN_OUT:
\r
905 rt5625_aec_config(codec,PCM_IN_PCM_OUT);//enable AEC PCM in/out function and path
\r
909 case RT5625_AEC_IIS_IN_OUT:
\r
911 rt5625_aec_config(codec,DAC_IN_ADC_OUT);//enable AEC IIS in/out function and path
\r
915 case RT5625_AEC_ANALOG_IN_OUT:
\r
917 rt5625_aec_config(codec,ANALOG_IN_ANALOG_OUT);//enable AEC analog in/out function and path
\r
921 case RT5625_AEC_DISABLE:
\r
923 rt5625_func_aec_disable(codec,rt5625_mode); //disable previous select function.
\r
932 Virtual_reg &= 0xfffc;
\r
933 Virtual_reg |= (ucontrol->value.integer.value[0]);
\r
934 rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, Virtual_reg);
\r
936 DBG("2rt5625_mode=%d,value[0]=%ld,Virtual_reg=%x\n",rt5625_mode,ucontrol->value.integer.value[0],Virtual_reg);
\r
940 static int rt5625_dump_dsp_reg(struct snd_soc_codec *codec)
\r
944 rt5625_write_mask(codec, RT5625_VODSP_CTL, VODSP_NO_PD_MODE_ENA,VODSP_NO_PD_MODE_ENA);
\r
945 for (i = 0; i < SET_VODSP_REG_INIT_NUM; i++) {
\r
946 rt5625_read_vodsp_reg(codec, VODSP_AEC_Init_Value[i].VoiceDSPIndex);
\r
952 static int rt5625_dump_dsp_put(struct snd_kcontrol *kcontrol,
\r
953 struct snd_ctl_elem_value *ucontrol)
\r
955 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
\r
956 int mode = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC);
\r
958 mode &= ~(0x01 << 8);
\r
959 mode |= (ucontrol->value.integer.value[0] << 8);
\r
960 rt5625_write(codec, VIRTUAL_REG_FOR_MISC_FUNC, mode);
\r
961 rt5625_dump_dsp_reg(codec);
\r
966 static const struct snd_kcontrol_new rt5625_snd_controls[] = {
\r
967 SOC_ENUM_EXT("rt5625 aec mode sel", rt5625_enum[0], rt5625_get_dsp_mode, rt5625_set_dsp_mode),
\r
968 SOC_ENUM("SPK Amp Type", rt5625_enum[1]),
\r
969 SOC_ENUM("Left SPK Source", rt5625_enum[2]),
\r
970 SOC_ENUM("SPK Amp Ratio", rt5625_enum[7]),
\r
971 SOC_ENUM("Mic1 Boost", rt5625_enum[8]),
\r
972 SOC_ENUM("Mic2 Boost", rt5625_enum[9]),
\r
973 SOC_ENUM("Dmic Boost", rt5625_enum[10]),
\r
974 SOC_ENUM("ADCR Func", rt5625_enum[11]),
\r
975 SOC_DOUBLE("RK4", RT5625_STEREO_DAC_VOL, 8, 0, 63, 1),
\r
976 SOC_DOUBLE("LineIn Playback Volume", RT5625_LINE_IN_VOL, 8, 0, 31, 1),
\r
977 SOC_SINGLE("Phone Playback Volume", RT5625_PHONEIN_VOL, 8, 31, 1),
\r
978 SOC_SINGLE("Mic1 Playback Volume", RT5625_MIC_VOL, 8, 31, 1),
\r
979 SOC_SINGLE("Mic2 Playback Volume", RT5625_MIC_VOL, 0, 31, 1),
\r
980 SOC_DOUBLE("PCM Capture Volume", RT5625_ADC_REC_GAIN, 8, 0, 31, 1),
\r
981 SOC_DOUBLE("RK3", RT5625_SPK_OUT_VOL, 8, 0, 31, 1),
\r
982 SOC_DOUBLE("RK2", RT5625_SPK_OUT_VOL, 15, 7, 1, 1),
\r
983 SOC_DOUBLE("RKA", RT5625_HP_OUT_VOL, 8, 0, 31, 1),
\r
984 SOC_DOUBLE("RK9", RT5625_HP_OUT_VOL, 15, 7, 1, 1),
\r
985 SOC_DOUBLE("RKD", RT5625_AUX_OUT_VOL, 8, 0, 31, 1),
\r
986 SOC_DOUBLE("RKC", RT5625_AUX_OUT_VOL, 15, 7, 1, 1),
\r
987 SOC_DOUBLE("ADC Record Gain", RT5625_ADC_REC_GAIN, 8, 0, 31, 0),
\r
988 SOC_SINGLE_EXT("VoDSP Dump", VIRTUAL_REG_FOR_MISC_FUNC, 8, 1, 0,
\r
989 snd_soc_get_volsw, rt5625_dump_dsp_put),
\r
990 #if (RT5625_EQ_FUNC_ENA==1)
\r
991 SOC_ENUM_EXT("EQ Mode", rt5625_enum[12], snd_soc_get_enum_double, rt5625_eq_sel_put),
\r
995 static int rt5625_add_controls(struct snd_soc_codec *codec)
\r
999 for (i = 0; i < ARRAY_SIZE(rt5625_snd_controls); i++){
\r
1000 err = snd_ctl_add(codec->card,
\r
1001 snd_soc_cnew(&rt5625_snd_controls[i],
\r
1009 static void hp_depop_mode2(struct snd_soc_codec *codec)
\r
1011 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN);
\r
1012 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD3, PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL,
\r
1013 PWR_HP_R_OUT_VOL|PWR_HP_L_OUT_VOL);
\r
1014 rt5625_write(codec, RT5625_MISC_CTRL,HP_DEPOP_MODE2_EN);
\r
1016 DBG("delay 500 msec\n");
\r
1018 schedule_timeout_uninterruptible(msecs_to_jiffies(500));
\r
1021 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_HP_OUT_AMP|PWR_HP_OUT_ENH_AMP,
\r
1022 PWR_HP_OUT_AMP|PWR_HP_OUT_ENH_AMP);
\r
1023 //rt5625_write_mask(codec, RT5625_MISC_CTRL, 0, HP_DEPOP_MODE2_EN);
\r
1027 //enable depop function for mute/unmute
\r
1028 static void hp_mute_unmute_depop(struct snd_soc_codec *codec,int mute)
\r
1032 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN);
\r
1033 rt5625_write(codec, RT5625_MISC_CTRL,M_UM_DEPOP_EN|HP_R_M_UM_DEPOP_EN|HP_L_M_UM_DEPOP_EN);
\r
1034 //Mute headphone right/left channel
\r
1035 rt5625_write_mask(codec,RT5625_HP_OUT_VOL,RT_L_MUTE|RT_R_MUTE,RT_L_MUTE|RT_R_MUTE);
\r
1040 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD1, PWR_SOFTGEN_EN, PWR_SOFTGEN_EN);
\r
1041 rt5625_write(codec, RT5625_MISC_CTRL, M_UM_DEPOP_EN|HP_R_M_UM_DEPOP_EN|HP_L_M_UM_DEPOP_EN);
\r
1042 //unMute headphone right/left channel
\r
1043 rt5625_write_mask(codec,RT5625_HP_OUT_VOL,0,RT_L_MUTE|RT_R_MUTE);
\r
1053 /*Left ADC Rec mixer*/
\r
1054 /*Left ADC Rec mixer*/
\r
1055 static const struct snd_kcontrol_new rt5625_left_adc_rec_mixer_controls[] = {
\r
1056 SOC_DAPM_SINGLE("RKK", RT5625_ADC_REC_MIXER, 14, 1, 1),
\r
1057 SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, 13, 1, 1),
\r
1058 SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, 12, 1, 1),
\r
1059 SOC_DAPM_SINGLE("RKL", RT5625_ADC_REC_MIXER, 11, 1, 1),
\r
1060 SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, 10, 1, 1),
\r
1061 SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, 9, 1, 1),
\r
1062 SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, 8, 1, 1),
\r
1066 /*Left ADC Rec mixer*/
\r
1067 static const struct snd_kcontrol_new rt5625_right_adc_rec_mixer_controls[] = {
\r
1068 SOC_DAPM_SINGLE("RKK", RT5625_ADC_REC_MIXER, 6, 1, 1),
\r
1069 SOC_DAPM_SINGLE("Mic2 Capture Switch", RT5625_ADC_REC_MIXER, 5, 1, 1),
\r
1070 SOC_DAPM_SINGLE("LineIn Capture Switch", RT5625_ADC_REC_MIXER, 4, 1, 1),
\r
1071 SOC_DAPM_SINGLE("RKL", RT5625_ADC_REC_MIXER, 3, 1, 1),
\r
1072 SOC_DAPM_SINGLE("HP Mixer Capture Switch", RT5625_ADC_REC_MIXER, 2, 1, 1),
\r
1073 SOC_DAPM_SINGLE("SPK Mixer Capture Switch", RT5625_ADC_REC_MIXER, 1, 1, 1),
\r
1074 SOC_DAPM_SINGLE("MoNo Mixer Capture Switch", RT5625_ADC_REC_MIXER, 0, 1, 1),
\r
1077 /*Left hpmixer mixer*/
\r
1078 static const struct snd_kcontrol_new rt5625_left_hp_mixer_controls[] = {
\r
1079 SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_ADC_REC_GAIN, 15, 1, 1),
\r
1080 SOC_DAPM_SINGLE("LineIn Playback Switch", HPL_MIXER, 0, 1, 0),
\r
1081 SOC_DAPM_SINGLE("RKJ", HPL_MIXER, 1, 1, 0),
\r
1082 SOC_DAPM_SINGLE("RKI", HPL_MIXER, 2, 1, 0),
\r
1083 SOC_DAPM_SINGLE("Mic2 Playback Switch", HPL_MIXER, 3, 1, 0),
\r
1084 SOC_DAPM_SINGLE("RKM", HPL_MIXER, 4, 1, 0),
\r
1085 SOC_DAPM_SINGLE("RKH", RT5625_DAC_AND_MIC_CTRL, 3, 1, 1),
\r
1089 /*Right hpmixer mixer*/
\r
1090 static const struct snd_kcontrol_new rt5625_right_hp_mixer_controls[] = {
\r
1091 SOC_DAPM_SINGLE("ADC Playback Switch", RT5625_ADC_REC_GAIN, 7, 1, 1),
\r
1092 SOC_DAPM_SINGLE("LineIn Playback Switch", HPR_MIXER, 0, 1, 0),
\r
1093 SOC_DAPM_SINGLE("RKJ", HPR_MIXER, 1, 1, 0),
\r
1094 SOC_DAPM_SINGLE("RKI", HPR_MIXER, 2, 1, 0),
\r
1095 SOC_DAPM_SINGLE("Mic2 Playback Switch", HPR_MIXER, 3, 1, 0),
\r
1096 SOC_DAPM_SINGLE("RKM", HPR_MIXER, 4, 1, 0),
\r
1097 SOC_DAPM_SINGLE("RKH", RT5625_DAC_AND_MIC_CTRL, 2, 1, 1),
\r
1102 static const struct snd_kcontrol_new rt5625_mono_mixer_controls[] = {
\r
1103 SOC_DAPM_SINGLE("ADCL Playback Switch", RT5625_ADC_REC_GAIN, 14, 1, 1),
\r
1104 SOC_DAPM_SINGLE("ADCR Playback Switch", RT5625_ADC_REC_GAIN, 6, 1, 1),
\r
1105 SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, 13, 1, 1),
\r
1106 SOC_DAPM_SINGLE("RKI", RT5625_DAC_AND_MIC_CTRL, 13, 1, 1),
\r
1107 SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 9, 1, 1),
\r
1108 SOC_DAPM_SINGLE("RKG", RT5625_DAC_AND_MIC_CTRL, 0, 1, 1),
\r
1109 SOC_DAPM_SINGLE("RKM", RT5625_VOICE_DAC_OUT_VOL, 13, 1, 1),
\r
1113 static const struct snd_kcontrol_new rt5625_spk_mixer_controls[] = {
\r
1114 SOC_DAPM_SINGLE("Line Mixer Playback Switch", RT5625_LINE_IN_VOL, 14, 1, 1),
\r
1115 SOC_DAPM_SINGLE("RKJ", RT5625_PHONEIN_VOL, 14, 1, 1),
\r
1116 SOC_DAPM_SINGLE("RKI", RT5625_DAC_AND_MIC_CTRL, 14, 1, 1),
\r
1117 SOC_DAPM_SINGLE("Mic2 Playback Switch", RT5625_DAC_AND_MIC_CTRL, 10, 1, 1),
\r
1118 SOC_DAPM_SINGLE("RKG", RT5625_DAC_AND_MIC_CTRL, 1, 1, 1),
\r
1119 SOC_DAPM_SINGLE("RKM", RT5625_VOICE_DAC_OUT_VOL, 14, 1, 1),
\r
1122 static int mixer_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
\r
1124 struct snd_soc_codec *codec = w->codec;
\r
1125 unsigned int l, r;
\r
1127 DBG("enter %s\n", __func__);
\r
1129 l= rt5625_read(codec, HPL_MIXER);
\r
1130 r = rt5625_read(codec, HPR_MIXER);
\r
1132 if ((l & 0x1) || (r & 0x1))
\r
1133 rt5625_write_mask(codec, 0x0a, 0x0000, 0x8000);
\r
1135 rt5625_write_mask(codec, 0x0a, 0x8000, 0x8000);
\r
1137 if ((l & 0x2) || (r & 0x2))
\r
1138 rt5625_write_mask(codec, 0x08, 0x0000, 0x8000);
\r
1140 rt5625_write_mask(codec, 0x08, 0x8000, 0x8000);
\r
1142 if ((l & 0x4) || (r & 0x4))
\r
1143 rt5625_write_mask(codec, 0x10, 0x0000, 0x8000);
\r
1145 rt5625_write_mask(codec, 0x10, 0x8000, 0x8000);
\r
1147 if ((l & 0x8) || (r & 0x8))
\r
1148 rt5625_write_mask(codec, 0x10, 0x0000, 0x0800);
\r
1150 rt5625_write_mask(codec, 0x10, 0x0800, 0x0800);
\r
1152 if ((l & 0x10) || (r & 0x10))
\r
1153 rt5625_write_mask(codec, 0x18, 0x0000, 0x8000);
\r
1155 rt5625_write_mask(codec, 0x18, 0x8000, 0x8000);
\r
1162 * bit[0][1] use for aec control
\r
1163 * bit[2][3] for ADCR func
\r
1164 * bit[4] for SPKL pga
\r
1165 * bit[5] for SPKR pga
\r
1166 * bit[6] for hpl pga
\r
1167 * bit[7] for hpr pga
\r
1169 static int spk_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
\r
1171 struct snd_soc_codec *codec = w->codec;
\r
1174 DBG("enter %s\n", __func__);
\r
1175 reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 4);
\r
1176 if ((reg >> 4) != 0x3 && reg != 0)
\r
1181 case SND_SOC_DAPM_POST_PMU:
\r
1182 DBG("after virtual spk power up!\n");
\r
1183 rt5625_write_mask(codec, 0x3e, 0x3000, 0x3000);
\r
1184 rt5625_write_mask(codec, 0x02, 0x0000, 0x8080);
\r
1185 rt5625_write_mask(codec, 0x3a, 0x0400, 0x0400);//power on spk amp
\r
1187 case SND_SOC_DAPM_POST_PMD:
\r
1188 DBG("aftet virtual spk power down!\n");
\r
1189 rt5625_write_mask(codec, 0x3a, 0x0000, 0x0400);//power off spk amp
\r
1190 rt5625_write_mask(codec, 0x02, 0x8080, 0x8080);
\r
1191 rt5625_write_mask(codec, 0x3e, 0x0000, 0x3000);
\r
1202 static int hp_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
\r
1204 struct snd_soc_codec *codec = w->codec;
\r
1207 DBG("enter %s\n", __func__);
\r
1209 reg = rt5625_read(codec, VIRTUAL_REG_FOR_MISC_FUNC) & (0x3 << 6);
\r
1210 if ((reg >> 6) != 0x3 && reg != 0)
\r
1215 case SND_SOC_DAPM_POST_PMD:
\r
1217 DBG("aftet virtual hp power down!\n");
\r
1219 hp_mute_unmute_depop(codec,1);//mute hp
\r
1220 rt5625_write_mask(codec, 0x3a, 0x0000, 0x0300);
\r
1221 rt5625_write_mask(codec, 0x3e, 0x0000, 0x0c00);
\r
1224 case SND_SOC_DAPM_POST_PMU:
\r
1226 DBG("after virtual hp power up!\n");
\r
1227 hp_depop_mode2(codec);
\r
1228 hp_mute_unmute_depop(codec,0);//unmute hp
\r
1240 static int aux_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event)
\r
1246 static const struct snd_kcontrol_new rt5625_spkout_mux_out_controls =
\r
1247 SOC_DAPM_ENUM("Route", rt5625_enum[3]);
\r
1250 static const struct snd_kcontrol_new rt5625_hplout_mux_out_controls =
\r
1251 SOC_DAPM_ENUM("Route", rt5625_enum[4]);
\r
1254 static const struct snd_kcontrol_new rt5625_hprout_mux_out_controls =
\r
1255 SOC_DAPM_ENUM("Route", rt5625_enum[5]);
\r
1257 static const struct snd_kcontrol_new rt5625_auxout_mux_out_controls =
\r
1258 SOC_DAPM_ENUM("Route", rt5625_enum[6]);
\r
1260 static const struct snd_soc_dapm_widget rt5625_dapm_widgets[] = {
\r
1261 SND_SOC_DAPM_INPUT("Left LineIn"),
\r
1262 SND_SOC_DAPM_INPUT("Right LineIn"),
\r
1263 SND_SOC_DAPM_INPUT("Phone"),
\r
1264 SND_SOC_DAPM_INPUT("Mic1"),
\r
1265 SND_SOC_DAPM_INPUT("Mic2"),
\r
1267 SND_SOC_DAPM_PGA("Mic1 Boost", RT5625_PWR_MANAG_ADD3, 1, 0, NULL, 0),
\r
1268 SND_SOC_DAPM_PGA("Mic2 Boost", RT5625_PWR_MANAG_ADD3, 0, 0, NULL, 0),
\r
1270 SND_SOC_DAPM_DAC("Left DAC", "Left HiFi Playback DAC", RT5625_PWR_MANAG_ADD2, 9, 0),
\r
1271 SND_SOC_DAPM_DAC("Right DAC", "Right HiFi Playback DAC", RT5625_PWR_MANAG_ADD2, 8, 0),
\r
1272 SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback DAC", RT5625_PWR_MANAG_ADD2, 10, 0),
\r
1274 SND_SOC_DAPM_PGA("Left LineIn PGA", RT5625_PWR_MANAG_ADD3, 7, 0, NULL, 0),
\r
1275 SND_SOC_DAPM_PGA("Right LineIn PGA", RT5625_PWR_MANAG_ADD3, 6, 0, NULL, 0),
\r
1276 SND_SOC_DAPM_PGA("Phone PGA", RT5625_PWR_MANAG_ADD3, 5, 0, NULL, 0),
\r
1277 SND_SOC_DAPM_PGA("Mic1 PGA", RT5625_PWR_MANAG_ADD3, 3, 0, NULL, 0),
\r
1278 SND_SOC_DAPM_PGA("Mic2 PGA", RT5625_PWR_MANAG_ADD3, 2, 0, NULL, 0),
\r
1279 SND_SOC_DAPM_PGA("VoDAC PGA", RT5625_PWR_MANAG_ADD1, 7, 0, NULL, 0),
\r
1280 SND_SOC_DAPM_MIXER("RKE", RT5625_PWR_MANAG_ADD2, 1, 0,
\r
1281 &rt5625_left_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5625_left_adc_rec_mixer_controls)),
\r
1282 SND_SOC_DAPM_MIXER("RKF", RT5625_PWR_MANAG_ADD2, 0, 0,
\r
1283 &rt5625_right_adc_rec_mixer_controls[0], ARRAY_SIZE(rt5625_right_adc_rec_mixer_controls)),
\r
1284 SND_SOC_DAPM_MIXER_E("RK5", RT5625_PWR_MANAG_ADD2, 5, 0,
\r
1285 &rt5625_left_hp_mixer_controls[0], ARRAY_SIZE(rt5625_left_hp_mixer_controls),
\r
1286 mixer_event, SND_SOC_DAPM_POST_REG),
\r
1287 SND_SOC_DAPM_MIXER_E("RK6", RT5625_PWR_MANAG_ADD2, 4, 0,
\r
1288 &rt5625_right_hp_mixer_controls[0], ARRAY_SIZE(rt5625_right_hp_mixer_controls),
\r
1289 mixer_event, SND_SOC_DAPM_POST_REG),
\r
1290 SND_SOC_DAPM_MIXER("RK13", RT5625_PWR_MANAG_ADD2, 2, 0,
\r
1291 &rt5625_mono_mixer_controls[0], ARRAY_SIZE(rt5625_mono_mixer_controls)),
\r
1292 SND_SOC_DAPM_MIXER("RK12", RT5625_PWR_MANAG_ADD2, 3, 0,
\r
1293 &rt5625_spk_mixer_controls[0], ARRAY_SIZE(rt5625_spk_mixer_controls)),
\r
1294 SND_SOC_DAPM_MIXER("RK11", SND_SOC_NOPM, 0, 0, NULL, 0),
\r
1295 SND_SOC_DAPM_MIXER("DAC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
\r
1296 SND_SOC_DAPM_MIXER("Line Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
\r
1298 SND_SOC_DAPM_MUX("RK1", SND_SOC_NOPM, 0, 0, &rt5625_spkout_mux_out_controls),
\r
1299 SND_SOC_DAPM_MUX("RK7", SND_SOC_NOPM, 0, 0, &rt5625_hplout_mux_out_controls),
\r
1300 SND_SOC_DAPM_MUX("RK8", SND_SOC_NOPM, 0, 0, &rt5625_hprout_mux_out_controls),
\r
1301 SND_SOC_DAPM_MUX("RKB", SND_SOC_NOPM, 0, 0, &rt5625_auxout_mux_out_controls),
\r
1303 SND_SOC_DAPM_PGA_E("SPKL Out PGA", VIRTUAL_REG_FOR_MISC_FUNC, 4, 0, NULL, 0,
\r
1304 spk_pga_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
\r
1305 SND_SOC_DAPM_PGA_E("SPKR Out PGA", VIRTUAL_REG_FOR_MISC_FUNC, 5, 0, NULL, 0,
\r
1306 spk_pga_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
\r
1307 SND_SOC_DAPM_PGA_E("HPL Out PGA",VIRTUAL_REG_FOR_MISC_FUNC, 6, 0, NULL, 0,
\r
1308 hp_pga_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
\r
1309 SND_SOC_DAPM_PGA_E("HPR Out PGA",VIRTUAL_REG_FOR_MISC_FUNC, 7, 0, NULL, 0,
\r
1310 hp_pga_event, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
\r
1311 SND_SOC_DAPM_PGA_E("AUX Out PGA",RT5625_PWR_MANAG_ADD3, 14, 0, NULL, 0,
\r
1312 aux_pga_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
\r
1314 SND_SOC_DAPM_ADC("Left ADC", "Left ADC HiFi Capture", RT5625_PWR_MANAG_ADD2, 7, 0),
\r
1315 SND_SOC_DAPM_ADC("Right ADC", "Right ADC HiFi Capture", RT5625_PWR_MANAG_ADD2, 6, 0),
\r
1316 SND_SOC_DAPM_OUTPUT("SPKL"),
\r
1317 SND_SOC_DAPM_OUTPUT("SPKR"),
\r
1318 SND_SOC_DAPM_OUTPUT("HPL"),
\r
1319 SND_SOC_DAPM_OUTPUT("HPR"),
\r
1320 SND_SOC_DAPM_OUTPUT("AUX"),
\r
1321 SND_SOC_DAPM_MICBIAS("Mic1 Bias", RT5625_PWR_MANAG_ADD1, 3, 0),
\r
1322 SND_SOC_DAPM_MICBIAS("Mic2 Bias", RT5625_PWR_MANAG_ADD1, 2, 0),
\r
1325 static const struct snd_soc_dapm_route audio_map[] = {
\r
1327 {"SPKL", NULL, "SPKL Out PGA"},
\r
1328 {"SPKR", NULL, "SPKR Out PGA"},
\r
1329 {"HPL", NULL, "HPL Out PGA"},
\r
1330 {"HPR", NULL, "HPR Out PGA"},
\r
1331 {"AUX", NULL, "AUX Out PGA"},
\r
1334 {"Left LineIn PGA", NULL, "Left LineIn"},
\r
1335 {"Right LineIn PGA", NULL, "Right LineIn"},
\r
1336 {"Phone PGA", NULL, "Phone"},
\r
1337 {"Mic1 Boost", NULL, "Mic1"},
\r
1338 {"Mic2 Boost", NULL, "Mic2"},
\r
1339 {"Mic1 PGA", NULL, "Mic1"},
\r
1340 {"Mic2 PGA", NULL, "Mic2"},
\r
1341 {"VoDAC PGA", NULL, "Voice DAC"},
\r
1343 /*Left ADC mixer*/
\r
1344 {"RKE", "LineIn Capture Switch", "Left LineIn"},
\r
1345 {"RKE", "RKL", "Phone"},
\r
1346 {"RKE", "RKK", "Mic1 Boost"},
\r
1347 {"RKE", "Mic2 Capture Switch", "Mic2 Boost"},
\r
1348 {"RKE", "HP Mixer Capture Switch", "RK5"},
\r
1349 {"RKE", "SPK Mixer Capture Switch", "RK12"},
\r
1350 {"RKE", "MoNo Mixer Capture Switch", "RK13"},
\r
1352 /*Right ADC Mixer*/
\r
1353 {"RKF", "LineIn Capture Switch", "Right LineIn"},
\r
1354 {"RKF", "RKL", "Phone"},
\r
1355 {"RKF", "RKK", "Mic1 Boost"},
\r
1356 {"RKF", "Mic2 Capture Switch", "Mic2 Boost"},
\r
1357 {"RKF", "HP Mixer Capture Switch", "RK6"},
\r
1358 {"RKF", "SPK Mixer Capture Switch", "RK12"},
\r
1359 {"RKF", "MoNo Mixer Capture Switch", "RK13"},
\r
1362 {"RK5", "ADC Playback Switch", "RKE"},
\r
1363 {"RK5", "LineIn Playback Switch", "Left LineIn PGA"},
\r
1364 {"RK5", "RKJ", "Phone PGA"},
\r
1365 {"RK5", "RKI", "Mic1 PGA"},
\r
1366 {"RK5", "Mic2 Playback Switch", "Mic2 PGA"},
\r
1367 {"RK5", "RKH", "Left DAC"},
\r
1368 {"RK5", "RKM", "VoDAC PGA"},
\r
1371 {"DAC Mixer", NULL, "Left DAC"},
\r
1372 {"DAC Mixer", NULL, "Right DAC"},
\r
1375 {"Line Mixer", NULL, "Left LineIn PGA"},
\r
1376 {"Line Mixer", NULL, "Right LineIn PGA"},
\r
1379 {"RK6", "ADC Playback Switch", "RKF"},
\r
1380 {"RK6", "LineIn Playback Switch", "Right LineIn PGA"},
\r
1381 {"RK6", "RKH", "Right DAC"},
\r
1382 {"RK6", "RKJ", "Phone PGA"},
\r
1383 {"RK6", "RKI", "Mic1 PGA"},
\r
1384 {"RK6", "Mic2 Playback Switch", "Mic2 PGA"},
\r
1385 {"RK6", "RKM", "VoDAC PGA"},
\r
1388 {"RK12", "Line Mixer Playback Switch", "Line Mixer"},
\r
1389 {"RK12", "RKJ", "Phone PGA"},
\r
1390 {"RK12", "RKI", "Mic1 PGA"},
\r
1391 {"RK12", "Mic2 Playback Switch", "Mic2 PGA"},
\r
1392 {"RK12", "RKG", "DAC Mixer"},
\r
1393 {"RK12", "RKM", "VoDAC PGA"},
\r
1396 {"RK13", "Line Mixer Playback Switch", "Line Mixer"},
\r
1397 {"RK13", "ADCL Playback Switch","RKE"},
\r
1398 {"RK13", "ADCR Playback Switch","RKF"},
\r
1399 {"RK13", "RKI", "Mic1 PGA"},
\r
1400 {"RK13", "Mic2 Playback Switch", "Mic2 PGA"},
\r
1401 {"RK13", "RKG", "DAC Mixer"},
\r
1402 {"RK13", "RKM", "VoDAC PGA"},
\r
1405 {"RK11", NULL, "RK5"},
\r
1406 {"RK11", NULL, "RK6"},
\r
1409 {"RK1", "RK11", "RK11"},
\r
1410 {"RK1", "RK12", "RK12"},
\r
1411 {"RK1", "RK13", "RK13"},
\r
1414 {"RK7", "RK71", "RK5"},
\r
1417 {"RK8", "RK81", "RK6"},
\r
1420 {"RKB", "RK11", "RK11"},
\r
1421 {"RKB", "RK12", "RK12"},
\r
1422 {"RKB", "RK13", "RK13"},
\r
1425 {"SPKL Out PGA", NULL, "RK1"},
\r
1428 {"SPKR Out PGA", NULL, "RK1"},
\r
1431 {"HPL Out PGA", NULL, "RK7"},
\r
1434 {"HPR Out PGA", NULL, "RK8"},
\r
1437 {"AUX Out PGA", NULL, "RKB"},
\r
1440 {"Left ADC", NULL, "RKE"},
\r
1443 {"Right ADC", NULL, "RKF"},
\r
1449 static int rt5625_add_widgets(struct snd_soc_codec *codec)
\r
1451 snd_soc_dapm_new_controls(codec, rt5625_dapm_widgets,
\r
1452 ARRAY_SIZE(rt5625_dapm_widgets));
\r
1453 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
\r
1454 snd_soc_dapm_new_widgets(codec);
\r
1466 /**************************************************************
\r
1468 * our codec support you to select different source as pll input, but if you
\r
1469 * use both of the I2S audio interface and pcm interface instantially.
\r
1470 * The two DAI must have the same pll setting params, so you have to offer
\r
1471 * the same pll input, and set our codec's sysclk the same one, we suggest
\r
1473 **************************************************************/
\r
1474 static const struct _pll_div codec_master_pll1_div[] = {
\r
1476 { 2048000, 8192000, 0x0ea0},
\r
1477 { 3686400, 8192000, 0x4e27},
\r
1478 { 12000000, 8192000, 0x456b},
\r
1479 { 13000000, 8192000, 0x495f},
\r
1480 { 13100000, 8192000, 0x0320},
\r
1481 { 2048000, 11289600, 0xf637},
\r
1482 { 3686400, 11289600, 0x2f22},
\r
1483 { 12000000, 11289600, 0x3e2f},
\r
1484 { 13000000, 11289600, 0x4d5b},
\r
1485 { 13100000, 11289600, 0x363b},
\r
1486 { 2048000, 16384000, 0x1ea0},
\r
1487 { 3686400, 16384000, 0x9e27},
\r
1488 { 12000000, 16384000, 0x452b},
\r
1489 { 13000000, 16384000, 0x542f},
\r
1490 { 13100000, 16384000, 0x03a0},
\r
1491 { 2048000, 16934400, 0xe625},
\r
1492 { 3686400, 16934400, 0x9126},
\r
1493 { 12000000, 16934400, 0x4d2c},
\r
1494 { 13000000, 16934400, 0x742f},
\r
1495 { 13100000, 16934400, 0x3c27},
\r
1496 { 2048000, 22579200, 0x2aa0},
\r
1497 { 3686400, 22579200, 0x2f20},
\r
1498 { 12000000, 22579200, 0x7e2f},
\r
1499 { 13000000, 22579200, 0x742f},
\r
1500 { 13100000, 22579200, 0x3c27},
\r
1501 { 2048000, 24576000, 0x2ea0},
\r
1502 { 3686400, 24576000, 0xee27},
\r
1503 { 11289600, 24576000, 0x950F},
\r
1504 { 12000000, 24576000, 0x2915},
\r
1505 { 12288000, 24576000, 0x0600},
\r
1506 { 13000000, 24576000, 0x772e},
\r
1507 { 13100000, 24576000, 0x0d20},
\r
1508 { 26000000, 24576000, 0x2027},
\r
1509 { 26000000, 22579200, 0x392f},
\r
1510 { 24576000, 22579200, 0x0921},
\r
1511 { 24576000, 24576000, 0x02a0},
\r
1514 static const struct _pll_div codec_bclk_pll1_div[] = {
\r
1516 { 256000, 4096000, 0x3ea0},
\r
1517 { 352800, 5644800, 0x3ea0},
\r
1518 { 512000, 8192000, 0x3ea0},
\r
1519 { 705600, 11289600, 0x3ea0},
\r
1520 { 1024000, 16384000, 0x3ea0},
\r
1521 { 1411200, 22579200, 0x3ea0},
\r
1522 { 1536000, 24576000, 0x3ea0},
\r
1523 { 2048000, 16384000, 0x1ea0},
\r
1524 { 2822400, 22579200, 0x1ea0},
\r
1525 { 3072000, 24576000, 0x1ea0},
\r
1526 { 705600, 11289600, 0x3ea0},
\r
1527 { 705600, 8467200, 0x3ab0},
\r
1528 { 2822400, 11289600, 0x1ee0},
\r
1529 { 3072000, 12288000, 0x1ee0},
\r
1532 static const struct _pll_div codec_vbclk_pll1_div[] = {
\r
1534 { 256000, 4096000, 0x3ea0},
\r
1535 { 352800, 5644800, 0x3ea0},
\r
1536 { 512000, 8192000, 0x3ea0},
\r
1537 { 705600, 11289600, 0x3ea0},
\r
1538 { 1024000, 16384000, 0x3ea0},
\r
1539 { 1411200, 22579200, 0x3ea0},
\r
1540 { 1536000, 24576000, 0x3ea0},
\r
1541 { 2048000, 16384000, 0x1ea0},
\r
1542 { 2822400, 22579200, 0x1ea0},
\r
1543 { 3072000, 24576000, 0x1ea0},
\r
1544 { 705600, 11289600, 0x3ea0},
\r
1545 { 705600, 8467200, 0x3ab0},
\r
1549 struct _coeff_div_stereo {
\r
1550 unsigned int mclk;
\r
1551 unsigned int rate;
\r
1552 unsigned int reg60;
\r
1553 unsigned int reg62;
\r
1556 struct _coeff_div_voice {
\r
1557 unsigned int mclk;
\r
1558 unsigned int rate;
\r
1559 unsigned int reg64;
\r
1562 static const struct _coeff_div_stereo coeff_div_stereo[] = {
\r
1564 /*bclk is config to 32fs, if codec is choose to be slave mode , input bclk should be 32*fs */
\r
1565 {24576000, 48000, 0x3174, 0x1010},
\r
1566 {12288000, 48000, 0x1174, 0x0000},
\r
1567 {18432000, 48000, 0x2174, 0x1111},
\r
1568 {36864000, 48000, 0x2274, 0x2020},
\r
1569 {49152000, 48000, 0xf074, 0x3030},
\r
1570 {24576000, 48000, 0x3172, 0x1010},
\r
1571 {24576000, 8000, 0xB274, 0x2424},
\r
1572 {24576000, 16000, 0xB174, 0x2222},
\r
1573 {24576000, 32000, 0xB074, 0x2121},
\r
1574 {22579200, 11025, 0X3374, 0x1414},
\r
1575 {22579200, 22050, 0X3274, 0x1212},
\r
1576 {22579200, 44100, 0X3174, 0x1010},
\r
1580 static const struct _coeff_div_voice coeff_div_voice[] = {
\r
1582 /*bclk is config to 32fs, if codec is choose to be slave mode , input bclk should be 32*fs */
\r
1583 {24576000, 16000, 0x2622},
\r
1584 {24576000, 8000, 0x2824},
\r
1588 static int get_coeff(unsigned int mclk, unsigned int rate, int mode)
\r
1592 DBG("get_coeff mclk = %d, rate = %d, mode = %d\n", mclk, rate, mode);
\r
1595 for (i = 0; i < ARRAY_SIZE(coeff_div_stereo); i++) {
\r
1596 if ((coeff_div_stereo[i].rate == rate) && (coeff_div_stereo[i].mclk == mclk))
\r
1600 for (i = 0; i< ARRAY_SIZE(coeff_div_voice); i++) {
\r
1601 if ((coeff_div_voice[i].rate == rate) && (coeff_div_voice[i].mclk == mclk))
\r
1606 printk("can't find a matched mclk and rate in %s\n",
\r
1607 (mode ? "coeff_div_voice[]" : "coeff_div_audio[]"));
\r
1613 static int rt5625_codec_set_dai_pll(struct snd_soc_dai *codec_dai,
\r
1614 int pll_id, unsigned int freq_in, unsigned int freq_out)
\r
1617 int ret = -EINVAL;
\r
1618 struct snd_soc_codec *codec = codec_dai->codec;
\r
1620 DBG("enter %s pll_id = %d freq_in = %d freq_out = %d\n",
\r
1621 __func__, pll_id, freq_in, freq_out);
\r
1623 if (pll_id < RT5625_PLL1_FROM_MCLK || pll_id > RT5625_PLL1_FROM_VBCLK)
\r
1626 if (!freq_in || !freq_out)
\r
1629 if (RT5625_PLL1_FROM_MCLK == pll_id) {
\r
1631 for (i = 0; i < ARRAY_SIZE(codec_master_pll1_div); i ++)
\r
1633 if ((freq_in == codec_master_pll1_div[i].pll_in) && (freq_out == codec_master_pll1_div[i].pll_out))
\r
1635 rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x0000); /*PLL source from MCLK*/
\r
1636 rt5625_write(codec, RT5625_PLL_CTRL, codec_master_pll1_div[i].regvalue); /*set pll code*/
\r
1637 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/
\r
1638 rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000);
\r
1642 } else if (RT5625_PLL1_FROM_BCLK == pll_id) {
\r
1644 for (i = 0; i < ARRAY_SIZE(codec_bclk_pll1_div); i ++)
\r
1646 if ((freq_in == codec_bclk_pll1_div[i].pll_in) && (freq_out == codec_bclk_pll1_div[i].pll_out))
\r
1648 rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x2000); /*PLL source from BCLK*/
\r
1649 rt5625_write(codec, RT5625_PLL_CTRL, codec_bclk_pll1_div[i].regvalue); /*set pll1 code*/
\r
1650 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/
\r
1651 rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000);
\r
1655 } else if (RT5625_PLL1_FROM_VBCLK == pll_id) {
\r
1657 for (i = 0; i < ARRAY_SIZE(codec_vbclk_pll1_div); i ++)
\r
1659 if ((freq_in == codec_vbclk_pll1_div[i].pll_in) && (freq_out == codec_vbclk_pll1_div[i].pll_out))
\r
1661 rt5625_write(codec, RT5625_GEN_CTRL_REG2, 0x3000); /*PLL source from VBCLK*/
\r
1662 rt5625_write(codec, RT5625_PLL_CTRL, codec_vbclk_pll1_div[i].regvalue); /*set pll1 code*/
\r
1663 rt5625_write_mask(codec, RT5625_PWR_MANAG_ADD2, 0x8000, 0x8000); /*enable pll1 power*/
\r
1664 rt5625_write_mask(codec, RT5625_GEN_CTRL_REG1, 0x8000, 0x8000);
\r
1673 static int rt5625_hifi_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
\r
1674 int clk_id, unsigned int freq, int dir)
\r
1676 struct snd_soc_codec *codec = codec_dai->codec;
\r
1677 struct rt5625_priv * rt5625 = codec->private_data;
\r
1679 DBG("sysclk freq %u for audio i2s\n", freq);
\r
1681 if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
\r
1682 rt5625->stereo_sysclk = freq;
\r
1686 printk("unsupported sysclk freq %u for audio i2s\n", freq);
\r
1687 rt5625->stereo_sysclk=24576000;
\r
1692 static int rt5625_voice_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
\r
1693 int clk_id, unsigned int freq, int dir)
\r
1695 struct snd_soc_codec *codec = codec_dai->codec;
\r
1696 struct rt5625_priv * rt5625 = codec->private_data;
\r
1698 DBG("sysclk freq %u for voice pcm\n", freq);
\r
1700 if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
\r
1701 rt5625->voice_sysclk = freq;
\r
1705 printk("unsupported sysclk freq %u for voice pcm\n", freq);
\r
1706 rt5625->voice_sysclk = 24576000;
\r
1712 static int rt5625_hifi_pcm_hw_params(struct snd_pcm_substream *substream,
\r
1713 struct snd_pcm_hw_params *params,
\r
1714 struct snd_soc_dai *dai)
\r
1716 struct snd_soc_pcm_runtime *rtd = substream->private_data;
\r
1717 struct snd_soc_device *socdev = rtd->socdev;
\r
1718 struct snd_soc_codec *codec = socdev->card->codec;
\r
1719 struct rt5625_priv *rt5625 = codec->private_data;
\r
1721 unsigned int iface = rt5625_read(codec, RT5625_MAIN_SDP_CTRL) & 0xfff3;
\r
1722 int rate = params_rate(params);
\r
1723 int coeff = get_coeff(rt5625->stereo_sysclk, rate, 0);
\r
1725 DBG("enter %s rate = %d \n", __func__, rate);
\r
1727 switch (params_format(params))
\r
1729 case SNDRV_PCM_FORMAT_S16_LE:
\r
1731 case SNDRV_PCM_FORMAT_S20_3LE:
\r
1733 case SNDRV_PCM_FORMAT_S24_LE:
\r
1735 case SNDRV_PCM_FORMAT_S8:
\r
1739 rt5625_write(codec, RT5625_MAIN_SDP_CTRL, iface);
\r
1740 rt5625_write_mask(codec, 0x3a, 0xc801, 0xc801); /*power i2s and dac ref*/
\r
1742 rt5625_write(codec, RT5625_STEREO_DAC_CLK_CTRL1, coeff_div_stereo[coeff].reg60);
\r
1743 rt5625_write(codec, RT5625_STEREO_DAC_CLK_CTRL2, coeff_div_stereo[coeff].reg62);
\r
1749 static int rt5625_voice_pcm_hw_params(struct snd_pcm_substream *substream,
\r
1750 struct snd_pcm_hw_params *params,
\r
1751 struct snd_soc_dai *dai)
\r
1753 struct snd_soc_pcm_runtime *rtd = substream->private_data;
\r
1754 struct snd_soc_device *socdev = rtd->socdev;
\r
1755 struct snd_soc_codec *codec = socdev->card->codec;
\r
1756 struct rt5625_priv *rt5625 = codec->private_data;
\r
1757 struct snd_soc_dapm_widget *w;
\r
1758 unsigned int iface = rt5625_read(codec, RT5625_EXTEND_SDP_CTRL) & 0xfff3;
\r
1759 int rate = params_rate(params);
\r
1760 int coeff = get_coeff(rt5625->voice_sysclk, rate, 1);
\r
1762 DBG("enter %s rate = %d \n", __func__, rate);
\r
1764 list_for_each_entry(w, &codec->dapm_widgets, list)
\r
1768 if (!strcmp(w->name, "Right ADC"))
\r
1769 strcpy(w->sname, "Right ADC Voice Capture");
\r
1772 switch (params_format(params))
\r
1774 case SNDRV_PCM_FORMAT_S16_LE:
\r
1776 case SNDRV_PCM_FORMAT_S20_3LE:
\r
1778 case SNDRV_PCM_FORMAT_S24_LE:
\r
1780 case SNDRV_PCM_FORMAT_S8:
\r
1783 rt5625_write_mask(codec, 0x3a, 0x0801, 0x0801); /*power i2s and dac ref*/
\r
1784 rt5625_write(codec, RT5625_EXTEND_SDP_CTRL, iface);
\r
1786 rt5625_write(codec, RT5625_VOICE_DAC_PCMCLK_CTRL1, coeff_div_voice[coeff].reg64);
\r
1792 static int rt5625_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
\r
1795 struct snd_soc_codec *codec = codec_dai->codec;
\r
1798 DBG("enter %s fmt = %d\n", __func__, fmt);
\r
1800 /*set master/slave interface*/
\r
1801 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK)
\r
1803 case SND_SOC_DAIFMT_CBM_CFM:
\r
1806 case SND_SOC_DAIFMT_CBS_CFS:
\r
1813 /*interface format*/
\r
1814 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
\r
1816 case SND_SOC_DAIFMT_I2S:
\r
1819 case SND_SOC_DAIFMT_LEFT_J:
\r
1822 case SND_SOC_DAIFMT_DSP_A:
\r
1825 case SND_SOC_DAIFMT_DSP_B:
\r
1832 /*clock inversion*/
\r
1833 switch (fmt & SND_SOC_DAIFMT_INV_MASK)
\r
1835 case SND_SOC_DAIFMT_NB_NF:
\r
1838 case SND_SOC_DAIFMT_IB_NF:
\r
1845 rt5625_write(codec, RT5625_MAIN_SDP_CTRL, iface);
\r
1849 static int rt5625_voice_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
\r
1851 struct snd_soc_codec *codec = codec_dai->codec;
\r
1854 DBG("enter %s\n", __func__);
\r
1855 /*set slave/master mode*/
\r
1856 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK)
\r
1858 case SND_SOC_DAIFMT_CBM_CFM:
\r
1861 case SND_SOC_DAIFMT_CBS_CFS:
\r
1868 switch(fmt & SND_SOC_DAIFMT_FORMAT_MASK)
\r
1870 case SND_SOC_DAIFMT_I2S:
\r
1873 case SND_SOC_DAIFMT_LEFT_J:
\r
1876 case SND_SOC_DAIFMT_DSP_A:
\r
1879 case SND_SOC_DAIFMT_DSP_B:
\r
1886 /*clock inversion*/
\r
1887 switch (fmt & SND_SOC_DAIFMT_INV_MASK)
\r
1889 case SND_SOC_DAIFMT_NB_NF:
\r
1892 case SND_SOC_DAIFMT_IB_NF:
\r
1899 iface |= 0x8000; /*enable vopcm*/
\r
1900 rt5625_write(codec, RT5625_EXTEND_SDP_CTRL, iface);
\r
1905 static int rt5625_hifi_codec_mute(struct snd_soc_dai *dai, int mute)
\r
1907 struct snd_soc_codec *codec = dai->codec;
\r
1910 rt5625_write_mask(codec, RT5625_STEREO_DAC_VOL, 0x8080, 0x8080);
\r
1912 rt5625_write_mask(codec, RT5625_STEREO_DAC_VOL, 0x0000, 0x8080);
\r
1916 static int rt5625_voice_codec_mute(struct snd_soc_dai *dai, int mute)
\r
1918 struct snd_soc_codec *codec = dai->codec;
\r
1921 rt5625_write_mask(codec, RT5625_VOICE_DAC_OUT_VOL, 0x1000, 0x1000);
\r
1923 rt5625_write_mask(codec, RT5625_VOICE_DAC_OUT_VOL, 0x0000, 0x1000);
\r
1928 static int rt5625_set_bias_level(struct snd_soc_codec *codec,
\r
1929 enum snd_soc_bias_level level)
\r
1932 case SND_SOC_BIAS_ON:
\r
1934 case SND_SOC_BIAS_PREPARE:
\r
1935 rt5625_write(codec, 0x26, 0x0000);
\r
1936 rt5625_write_mask(codec, 0x3c, 0x2000, 0x2000);
\r
1937 rt5625_write_mask(codec, 0x3a, 0x000e, 0x000e);
\r
1939 case SND_SOC_BIAS_STANDBY:
\r
1941 case SND_SOC_BIAS_OFF:
\r
1942 rt5625_write_mask(codec, 0x04, 0x8080, 0x8080); /*mute hp*/
\r
1943 rt5625_write_mask(codec, 0x02, 0x8080, 0x8080); /*mute spk*/
\r
1944 rt5625_write(codec, 0x3e, 0x0000); //power off all bit
\r
1945 rt5625_write(codec, 0x3a, 0x0000); //power off all bit
\r
1946 rt5625_write(codec, 0x3c, 0x0000); //power off all bit
\r
1950 codec->bias_level = level;
\r
1955 #define RT5625_STEREO_RATES SNDRV_PCM_RATE_8000_48000
\r
1957 #define RT5626_VOICE_RATES SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000
\r
1959 #define RT5625_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
\r
1960 SNDRV_PCM_FMTBIT_S20_3LE |\
\r
1961 SNDRV_PCM_FMTBIT_S24_LE |\
\r
1962 SNDRV_PCM_FMTBIT_S8)
\r
1964 static struct snd_soc_dai_ops rt5625_dai_ops_hifi = {
\r
1966 .hw_params = rt5625_hifi_pcm_hw_params,
\r
1967 // .digital_mute = rt5625_hifi_codec_mute,
\r
1968 .set_fmt = rt5625_hifi_codec_set_dai_fmt,
\r
1969 .set_pll = rt5625_codec_set_dai_pll,
\r
1970 .set_sysclk = rt5625_hifi_codec_set_dai_sysclk,
\r
1975 static struct snd_soc_dai_ops rt5625_dai_ops_voice = {
\r
1977 .hw_params = rt5625_voice_pcm_hw_params,
\r
1978 // .digital_mute = rt5625_voice_codec_mute,
\r
1979 .set_fmt = rt5625_voice_codec_set_dai_fmt,
\r
1980 .set_pll = rt5625_codec_set_dai_pll,
\r
1981 .set_sysclk = rt5625_voice_codec_set_dai_sysclk,
\r
1987 struct snd_soc_dai rt5625_dai[] = {
\r
1988 /*hifi codec dai*/
\r
1990 .name = "RT5625 HiFi",
\r
1993 .stream_name = "HiFi Playback",
\r
1994 .channels_min = 1,
\r
1995 .channels_max = 2,
\r
1996 .rates = RT5625_STEREO_RATES,
\r
1997 .formats = RT5625_FORMATS,
\r
2000 .stream_name = "HiFi Capture",
\r
2001 .channels_min = 1,
\r
2002 .channels_max = 2,
\r
2003 .rates = RT5625_STEREO_RATES,
\r
2004 .formats = RT5625_FORMATS,
\r
2007 .ops = &rt5625_dai_ops_hifi,
\r
2010 /*voice codec dai*/
\r
2012 .name = "RT5625 Voice",
\r
2015 .stream_name = "Voice Playback",
\r
2016 .channels_min = 1,
\r
2017 .channels_max = 1,
\r
2018 .rates = RT5626_VOICE_RATES,
\r
2019 .formats = RT5625_FORMATS,
\r
2022 .stream_name = "Voice Capture",
\r
2023 .channels_min = 1,
\r
2024 .channels_max = 1,
\r
2025 .rates = RT5626_VOICE_RATES,
\r
2026 .formats = RT5625_FORMATS,
\r
2029 .ops = &rt5625_dai_ops_voice,
\r
2034 EXPORT_SYMBOL_GPL(rt5625_dai);
\r
2037 static void rt5625_work(struct work_struct *work)
\r
2039 struct snd_soc_codec *codec =
\r
2040 container_of(work, struct snd_soc_codec, delayed_work.work);
\r
2041 rt5625_set_bias_level(codec, codec->bias_level);
\r
2045 #if defined(CONFIG_SND_HWDEP)
\r
2049 #define RT_CE_CODEC_HWDEP_NAME "rt56xx hwdep "
\r
2052 static int rt56xx_hwdep_open(struct snd_hwdep *hw, struct file *file)
\r
2054 DBG("enter %s\n", __func__);
\r
2058 static int rt56xx_hwdep_release(struct snd_hwdep *hw, struct file *file)
\r
2060 DBG("enter %s\n", __func__);
\r
2065 static int rt56xx_hwdep_ioctl_common(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
\r
2067 struct rt56xx_cmd rt56xx;
\r
2068 struct rt56xx_cmd __user *_rt56xx = arg;
\r
2069 struct rt56xx_reg_state *buf;
\r
2070 struct rt56xx_reg_state *p;
\r
2071 struct snd_soc_codec *codec = hw->private_data;
\r
2073 if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))
\r
2075 buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL);
\r
2078 if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number)) {
\r
2082 case RT_READ_CODEC_REG_IOCTL:
\r
2083 for (p = buf; p < buf + rt56xx.number; p++)
\r
2085 p->reg_value = codec->read(codec, p->reg_index);
\r
2087 if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
\r
2091 case RT_WRITE_CODEC_REG_IOCTL:
\r
2092 for (p = buf; p < buf + rt56xx.number; p++)
\r
2093 codec->write(codec, p->reg_index, p->reg_value);
\r
2106 static int rt56xx_codec_dump_reg(struct snd_hwdep *hw, struct file *file, unsigned long arg)
\r
2108 struct rt56xx_cmd rt56xx;
\r
2109 struct rt56xx_cmd __user *_rt56xx = arg;
\r
2110 struct rt56xx_reg_state *buf;
\r
2111 struct snd_soc_codec *codec = hw->private_data;
\r
2112 int number = codec->reg_cache_size;
\r
2115 DBG("enter %s, number = %d\n", __func__, number);
\r
2116 if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx)))
\r
2119 buf = kmalloc(sizeof(*buf) * number, GFP_KERNEL);
\r
2123 for (i = 0; i < number; i++)
\r
2125 buf[i].reg_index = i << 1;
\r
2126 buf[i].reg_value = codec->read(codec, buf[i].reg_index);
\r
2128 if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * i))
\r
2130 rt56xx.number = number;
\r
2131 if (copy_to_user(_rt56xx, &rt56xx, sizeof(rt56xx)))
\r
2141 static int rt56xx_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigned int cmd, unsigned long arg)
\r
2143 if (cmd == RT_READ_ALL_CODEC_REG_IOCTL)
\r
2145 return rt56xx_codec_dump_reg(hw, file, arg);
\r
2149 return rt56xx_hwdep_ioctl_common(hw, file, cmd, arg);
\r
2153 int realtek_ce_init_hwdep(struct snd_soc_codec *codec)
\r
2155 struct snd_hwdep *hw;
\r
2156 struct snd_card *card = codec->card;
\r
2159 if ((err = snd_hwdep_new(card, RT_CE_CODEC_HWDEP_NAME, 0, &hw)) < 0)
\r
2162 strcpy(hw->name, RT_CE_CODEC_HWDEP_NAME);
\r
2163 hw->private_data = codec;
\r
2164 hw->ops.open = rt56xx_hwdep_open;
\r
2165 hw->ops.release = rt56xx_hwdep_release;
\r
2166 hw->ops.ioctl = rt56xx_hwdep_ioctl;
\r
2174 static int rt5625_init(struct snd_soc_device *socdev)
\r
2177 struct snd_soc_codec *codec = socdev->card->codec;
\r
2180 codec->name = "RT5625";
\r
2181 codec->owner = THIS_MODULE;
\r
2182 codec->read = rt5625_read;
\r
2183 codec->write = rt5625_write;
\r
2184 codec->set_bias_level = rt5625_set_bias_level;
\r
2185 codec->dai= rt5625_dai;
\r
2186 codec->num_dai = 2;
\r
2187 codec->reg_cache_step = 2;
\r
2188 codec->reg_cache_size = ARRAY_SIZE(rt5625_reg)*2;
\r
2189 codec->reg_cache = kmemdup(rt5625_reg, sizeof(rt5625_reg), GFP_KERNEL);
\r
2190 if (codec->reg_cache == NULL)
\r
2193 rt5625_reset(codec);
\r
2195 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
\r
2198 printk(KERN_ERR "rt5625: failed to create pcms\n");
\r
2202 rt5625_write(codec, RT5625_PD_CTRL_STAT, 0);
\r
2203 rt5625_write(codec, RT5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS);
\r
2204 rt5625_write(codec, RT5625_PWR_MANAG_ADD2, PWR_MIXER_VREF);
\r
2205 rt5625_reg_init(codec);
\r
2206 rt5625_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
\r
2207 codec->bias_level = SND_SOC_BIAS_STANDBY;
\r
2208 schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(80));
\r
2210 #if (RT5625_EQ_FUNC_ENA==1)
\r
2211 rt5625_update_eqmode(codec,POP);
\r
2214 rt5625_add_controls(codec);
\r
2215 rt5625_add_widgets(codec);
\r
2217 #if defined(CONFIG_SND_HWDEP)
\r
2221 realtek_ce_init_hwdep(codec);
\r
2227 ret = snd_soc_init_card(socdev);
\r
2231 printk(KERN_ERR "rt5625: failed to register card\n");
\r
2234 DBG("rt5625: initial ok\n");
\r
2238 snd_soc_free_pcms(socdev);
\r
2239 snd_soc_dapm_free(socdev);
\r
2242 kfree(codec->reg_cache);
\r
2249 static int rt5625_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
\r
2251 struct snd_soc_device *socdev = rt5625_socdev;
\r
2252 struct snd_soc_codec *codec = socdev->card->codec;
\r
2255 i2c_set_clientdata(i2c, codec);
\r
2256 codec->control_data = i2c;
\r
2258 ret = rt5625_init(socdev);
\r
2260 pr_err("failed to initialise rt5625\n");
\r
2265 static int rt5625_i2c_remove(struct i2c_client *client)
\r
2267 struct snd_soc_codec *codec = i2c_get_clientdata(client);
\r
2268 kfree(codec->reg_cache);
\r
2272 static const struct i2c_device_id rt5625_i2c_id[] = {
\r
2276 MODULE_DEVICE_TABLE(i2c, rt5625_i2c_id);
\r
2277 static struct i2c_driver rt5625_i2c_driver = {
\r
2279 .name = "RT5625 I2C Codec",
\r
2280 .owner = THIS_MODULE,
\r
2282 .probe = rt5625_i2c_probe,
\r
2283 .remove = rt5625_i2c_remove,
\r
2284 .id_table = rt5625_i2c_id,
\r
2288 static int rt5625_add_i2c_device(struct platform_device *pdev,
\r
2289 const struct rt5625_setup_data *setup)
\r
2292 struct i2c_board_info info;
\r
2293 struct i2c_adapter *adapter;
\r
2294 struct i2c_client *client;
\r
2298 ret = i2c_add_driver(&rt5625_i2c_driver);
\r
2300 dev_err(&pdev->dev, "can't add i2c driver\n");
\r
2304 memset(&info, 0, sizeof(struct i2c_board_info));
\r
2305 info.addr = setup->i2c_address;
\r
2306 strlcpy(info.type, "rt5625", I2C_NAME_SIZE);
\r
2308 adapter = i2c_get_adapter(setup->i2c_bus);
\r
2310 dev_err(&pdev->dev, "can't get i2c adapter %d\n",
\r
2315 client = i2c_new_device(adapter, &info);
\r
2316 i2c_put_adapter(adapter);
\r
2318 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
\r
2319 (unsigned int)info.addr);
\r
2326 i2c_del_driver(&rt5625_i2c_driver);
\r
2332 static int rt5625_probe(struct platform_device *pdev)
\r
2334 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
\r
2335 struct rt5625_setup_data *setup;
\r
2336 struct snd_soc_codec *codec;
\r
2337 struct rt5625_priv *rt5625;
\r
2340 pr_info("RT5625 Audio Codec %s", RT5625_VERSION);
\r
2342 if(socdev->codec_data)
\r
2344 setup = socdev->codec_data;
\r
2347 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
\r
2348 if (codec == NULL)
\r
2351 rt5625 = kzalloc(sizeof(struct rt5625_priv), GFP_KERNEL);
\r
2352 if (rt5625 == NULL) {
\r
2356 codec->private_data = rt5625;
\r
2357 socdev->card->codec = codec;
\r
2359 mutex_init(&codec->mutex);
\r
2360 INIT_LIST_HEAD(&codec->dapm_widgets);
\r
2361 INIT_LIST_HEAD(&codec->dapm_paths);
\r
2362 rt5625_socdev = socdev;
\r
2363 INIT_DELAYED_WORK(&codec->delayed_work, rt5625_work);
\r
2366 // if (setup->i2c_address)
\r
2368 codec->hw_write = (hw_write_t)i2c_master_send;
\r
2369 //codec->hw_read = (hw_read_t)i2c_master_recv;
\r
2370 ret = rt5625_add_i2c_device(pdev, setup);
\r
2374 kfree(codec->private_data);
\r
2376 socdev->card->codec = NULL;
\r
2381 static int run_delayed_work(struct delayed_work *dwork)
\r
2385 /* cancel any work waiting to be queued. */
\r
2386 ret = cancel_delayed_work(dwork);
\r
2388 /* if there was any work waiting then we run it now and
\r
2389 * wait for it's completion */
\r
2391 schedule_delayed_work(dwork, 0);
\r
2392 flush_scheduled_work();
\r
2398 static int rt5625_remove(struct platform_device *pdev)
\r
2400 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
\r
2401 struct snd_soc_codec *codec = socdev->card->codec;
\r
2403 if (codec->control_data)
\r
2404 rt5625_set_bias_level(codec, SND_SOC_BIAS_OFF);
\r
2405 run_delayed_work(&codec->delayed_work);
\r
2406 snd_soc_free_pcms(socdev);
\r
2407 snd_soc_dapm_free(socdev);
\r
2408 i2c_unregister_device(codec->control_data);
\r
2409 i2c_del_driver(&rt5625_i2c_driver);
\r
2410 kfree(codec->private_data);
\r
2417 static int rt5625_suspend(struct platform_device *pdev, pm_message_t state)
\r
2419 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
\r
2420 struct snd_soc_codec *codec = socdev->card->codec;
\r
2422 rt5625_set_bias_level(codec, SND_SOC_BIAS_OFF);
\r
2427 static int rt5625_resume(struct platform_device *pdev)
\r
2429 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
\r
2430 struct snd_soc_codec *codec = socdev->card->codec;
\r
2435 // u16 *cache = codec->reg_cache;
\r
2438 rt5625_reset(codec);
\r
2439 rt5625_write(codec, RT5625_PD_CTRL_STAT, 0);
\r
2440 rt5625_write(codec, RT5625_PWR_MANAG_ADD1, PWR_MAIN_BIAS);
\r
2441 rt5625_write(codec, RT5625_PWR_MANAG_ADD2, PWR_MIXER_VREF);
\r
2442 rt5625_reg_init(codec);
\r
2444 /* Sync reg_cache with the hardware */
\r
2445 for (i = 0; i < ARRAY_SIZE(rt5625_reg); i++) {
\r
2446 if (i == RT5625_RESET)
\r
2449 data[1] = (0xff00 & cache[i]) >> 8;
\r
2450 data[2] = 0x00ff & cache[i];
\r
2451 codec->hw_write(codec->control_data, data, 3);
\r
2454 rt5625_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
\r
2457 /* charge rt5625 caps */
\r
2458 if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
\r
2459 rt5625_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
\r
2460 codec->bias_level = SND_SOC_BIAS_ON;
\r
2461 schedule_delayed_work(&codec->delayed_work,
\r
2462 msecs_to_jiffies(100));
\r
2469 struct snd_soc_codec_device soc_codec_dev_rt5625 = {
\r
2470 .probe = rt5625_probe,
\r
2471 .remove = rt5625_remove,
\r
2472 .suspend = rt5625_suspend,
\r
2473 .resume = rt5625_resume,
\r
2476 EXPORT_SYMBOL_GPL(soc_codec_dev_rt5625);
\r
2478 static int __init rt5625_modinit(void)
\r
2480 return snd_soc_register_dais(rt5625_dai, ARRAY_SIZE(rt5625_dai));
\r
2483 static void __exit rt5625_exit(void)
\r
2485 snd_soc_unregister_dais(rt5625_dai, ARRAY_SIZE(rt5625_dai));
\r
2488 module_init(rt5625_modinit);
\r
2489 module_exit(rt5625_exit);
\r
2490 MODULE_LICENSE("GPL");
\r