2 * cs42l52.c -- CS42L52 ALSA SoC audio driver
4 * Copyright 2007 CirrusLogic, Inc.
6 * Author: Bo Liu <Bo.Liu@cirrus.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * Nov 2007 Initial version.
13 * Oct 2008 Updated to 2.6.26
17 #include <linux/module.h>
18 #include <linux/moduleparam.h>
19 #include <linux/version.h>
20 #include <linux/kernel.h>
21 #include <linux/init.h>
22 #include <linux/delay.h>
24 #include <linux/i2c.h>
25 #include <linux/platform_device.h>
26 #include <linux/spi/spi.h>
27 #include <sound/core.h>
28 #include <sound/pcm.h>
29 #include <sound/pcm_params.h>
30 #include <sound/soc.h>
31 #include <sound/soc-dapm.h>
32 #include <sound/initval.h>
33 #include <sound/tlv.h>
35 #include <linux/types.h>
36 #include <linux/device.h>
40 #include <mach/board.h>
42 //#include "cs42L52_control.h"
45 #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
46 #define AUTO_DETECT_DISABLE
48 //#define AUTO_DETECT_DISABLE
49 #undef AUTO_DETECT_DISABLE
54 #define SOCDBG(fmt, arg...) printk(KERN_ERR "%s: %s() " fmt, SOC_CS42L52_NAME, __FUNCTION__, ##arg)
56 #define SOCDBG(fmt, arg...) do { } while (0)
58 #define SOCINF(fmt, args...) printk(KERN_INFO "%s: " fmt, SOC_CS42L52_NAME, ##args)
59 #define SOCERR(fmt, args...) printk(KERN_ERR "%s: " fmt, SOC_CS42L52_NAME, ##args)
63 static void soc_cs42l52_work(struct work_struct *work);
65 static struct snd_soc_codec *cs42l52_codec;
68 #ifdef CONFIG_HAS_EARLYSUSPEND
69 #include <linux/earlysuspend.h>
70 static struct early_suspend cs42l52_early_suspend;
74 * snd_soc_get_volsw - single mixer get callback
75 * @kcontrol: mixer control
76 * @uinfo: control element information
78 * Callback to get the value of a single mixer control.
80 * Returns 0 for success.
82 int snd_soc_cs42l5x_get_volsw(struct snd_kcontrol *kcontrol,
83 struct snd_ctl_elem_value *ucontrol)
85 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
86 int reg = kcontrol->private_value & 0xff;
87 int shift = (kcontrol->private_value >> 8) & 0x0f;
88 int rshift = (kcontrol->private_value >> 12) & 0x0f;
89 int max = (kcontrol->private_value >> 16) & 0xff;
90 int mask = (1 << fls(max)) - 1;
91 int min = (kcontrol->private_value >> 24) & 0xff;
93 ucontrol->value.integer.value[0] =
94 ((snd_soc_read(codec, reg) >> shift) - min) & mask;
96 ucontrol->value.integer.value[1] =
97 ((snd_soc_read(codec, reg) >> rshift) - min) & mask;
103 * snd_soc_put_volsw - single mixer put callback
104 * @kcontrol: mixer control
105 * @uinfo: control element information
107 * Callback to set the value of a single mixer control.
109 * Returns 0 for success.
111 int snd_soc_cs42l5x_put_volsw(struct snd_kcontrol *kcontrol,
112 struct snd_ctl_elem_value *ucontrol)
114 SOCDBG("i am here\n");
115 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
116 int reg = kcontrol->private_value & 0xff;
117 int shift = (kcontrol->private_value >> 8) & 0x0f;
118 int rshift = (kcontrol->private_value >> 12) & 0x0f;
119 int max = (kcontrol->private_value >> 16) & 0xff;
120 int mask = (1 << fls(max)) - 1;
121 int min = (kcontrol->private_value >> 24) & 0xff;
122 unsigned short val, val2, val_mask;
124 val = ((ucontrol->value.integer.value[0] + min) & mask);
126 val_mask = mask << shift;
128 if (shift != rshift) {
129 val2 = ((ucontrol->value.integer.value[1] + min) & mask);
130 val_mask |= mask << rshift;
131 val |= val2 << rshift;
133 return snd_soc_update_bits(codec, reg, val_mask, val);
137 * snd_soc_info_volsw_2r - double mixer info callback
138 * @kcontrol: mixer control
139 * @uinfo: control element information
141 * Callback to provide information about a double mixer control that
142 * spans 2 codec registers.
144 * Returns 0 for success.
146 int snd_soc_cs42l5x_info_volsw_2r(struct snd_kcontrol *kcontrol,
147 struct snd_ctl_elem_info *uinfo)
149 int max = (kcontrol->private_value >> 8) & 0xff;
152 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
154 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
157 uinfo->value.integer.min = 0;
158 uinfo->value.integer.max = max;
163 * snd_soc_get_volsw_2r - double mixer get callback
164 * @kcontrol: mixer control
165 * @uinfo: control element information
167 * Callback to get the value of a double mixer control that spans 2 registers.
169 * Returns 0 for success.
171 int snd_soc_cs42l5x_get_volsw_2r(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_value *ucontrol)
174 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
175 int reg = kcontrol->private_value & 0xff;
176 int reg2 = (kcontrol->private_value >> 24) & 0xff;
177 int max = (kcontrol->private_value >> 8) & 0xff;
178 int min = (kcontrol->private_value >> 16) & 0xff;
179 int mask = (1<<fls(max))-1;
182 val = snd_soc_read(codec, reg);
183 val2 = snd_soc_read(codec, reg2);
184 ucontrol->value.integer.value[0] = (val - min) & mask;
185 ucontrol->value.integer.value[1] = (val2 - min) & mask;
187 SOCDBG("reg[%02x:%02x] = %02x:%02x ucontrol[%02x:%02x], min = %02x, max = %02x, mask %02x\n",
189 ucontrol->value.integer.value[0], ucontrol->value.integer.value[1],
196 * snd_soc_put_volsw_2r - double mixer set callback
197 * @kcontrol: mixer control
198 * @uinfo: control element information
200 * Callback to set the value of a double mixer control that spans 2 registers.
202 * Returns 0 for success.
204 int snd_soc_cs42l5x_put_volsw_2r(struct snd_kcontrol *kcontrol,
205 struct snd_ctl_elem_value *ucontrol)
207 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
208 int reg = kcontrol->private_value & 0xff;
209 int reg2 = (kcontrol->private_value >> 24) & 0xff;
210 int max = (kcontrol->private_value >> 8) & 0xff;
211 int min = (kcontrol->private_value >> 16) & 0xff;
212 int mask = (1 << fls(max)) - 1;
214 unsigned short val, val2;
216 val = (ucontrol->value.integer.value[0] + min) & mask;
217 val2 = (ucontrol->value.integer.value[1] + min) & mask;
219 if ((err = snd_soc_update_bits(codec, reg, mask, val)) < 0)
222 err = snd_soc_update_bits(codec, reg2, mask, val2);
224 SOCDBG("reg[%02x:%02x] = %02x:%02x, ucontrol[%02x:%02x], min = %02x, max = %02x, mask = %02x\n",
225 reg, reg2, val, val2,
226 ucontrol->value.integer.value[0], ucontrol->value.integer.value[1],
232 #define SOC_SINGLE_CS42L52(xname, reg, shift, max, min) \
233 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
234 .info = snd_soc_info_volsw, .get = snd_soc_cs42l5x_get_volsw,\
235 .put = snd_soc_cs42l5x_put_volsw, \
236 .private_value = SOC_SINGLE_VALUE(reg, shift, max, min) }
238 #define SOC_DOUBLE_CS42L52(xname, reg, shift_left, shift_right, max, min) \
239 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
240 .info = snd_soc_info_volsw, .get = snd_soc_cs42l5x_get_volsw, \
241 .put = snd_soc_cs42l5x_put_volsw, \
242 .private_value = (reg) | ((shift_left) << 8) | \
243 ((shift_right) << 12) | ((max) << 16) | ((min) << 24) }
245 /* No shifts required */
246 #define SOC_DOUBLE_R_CS42L52(xname, reg_left, reg_right, max, min) \
247 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
248 .info = snd_soc_cs42l5x_info_volsw_2r, \
249 .get = snd_soc_cs42l5x_get_volsw_2r, .put = snd_soc_cs42l5x_put_volsw_2r, \
250 .private_value = (reg_left) | ((max) << 8) | ((min) << 16) | \
251 ((reg_right) << 24) }
255 * CS42L52 register default value
257 static const u8 soc_cs42l52_reg_default[] = {
258 0x00, 0xE0, 0x01, 0x07, 0x05, /*4*/
259 0xa0, 0x00, 0x00, 0x81, /*8*/
260 0x81, 0xa5, 0x00, 0x00, /*12*/
261 0x60, 0x02, 0x00, 0x00, /*16*/
262 0x00, 0x00, 0x00, 0x00, /*20*/
263 0x00, 0x00, 0x00, 0x80, /*24*/
264 0x80, 0x00, 0x00, 0x00, /*28*/
265 0x00, 0x00, 0x88, 0x00, /*32*/
266 0x00, 0x00, 0x00, 0x00, /*36*/
267 0x00, 0x00, 0x00, 0x7f, /*40*/
268 0xc0, 0x00, 0x3f, 0x00, /*44*/
269 0x00, 0x00, 0x00, 0x00, /*48*/
270 0x00, 0x3b, 0x00, 0x5f, /*52*/
273 static inline int soc_cs42l52_read_reg_cache(struct snd_soc_codec *codec,
276 u8 *cache = codec->reg_cache;
278 return reg > SOC_CS42L52_REG_NUM ? -EINVAL : cache[reg];
281 static inline void soc_cs42l52_write_reg_cache(struct snd_soc_codec *codec,
282 u_int reg, u_int val)
284 u8 *cache = codec->reg_cache;
286 if(reg > SOC_CS42L52_REG_NUM)
288 cache[reg] = val & 0xff;
291 static int soc_cs42l52_write(struct snd_soc_codec *codec,
292 unsigned reg, u_int val)
297 struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)codec->private_data;
299 datas[0] = reg & 0xff;
300 datas[1] = val & 0xff;
302 if(info->flags & SOC_CS42L52_ALL_IN_ONE)
304 for(i = 0; i < codec->num_dai; i++)
306 if(codec->hw_write(codec->control_data, datas, 2) != 2)
315 if(info->flags & SOC_CS42L52_CHIP_SWICTH)
317 num = info->flags & SOC_CS42L52_CHIP_MASK;
320 if(codec->hw_write(codec->control_data, datas, 2) != 2)
325 soc_cs42l52_write_reg_cache(codec, reg, val);
329 return codec->write(codec, reg, val);
333 static unsigned int soc_cs42l52_read(struct snd_soc_codec *codec,
338 if(i2c_master_reg8_recv(codec->control_data,reg,&data,1,50*1000)>0) {
342 printk("cs42l52 read error\n");
346 return codec->read(codec, reg);
350 struct soc_cs42l52_clk_para {
360 static const struct soc_cs42l52_clk_para clk_map_table[] = {
362 {12288000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
363 {18432000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
364 {12000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
365 {24000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
366 {27000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0}, /*4*/
369 {11289600, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
370 {16934400, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
373 {12288000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
374 {18432000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
375 {12000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},/*9*/
376 {24000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
377 {27000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
380 {11289600, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
381 {16934400, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
384 {12288000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*14*/
385 {18432000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
386 {12000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
387 {24000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
388 {27000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0},
391 {11289600, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*19*/
392 {16934400, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
393 {12000000, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_136, 0},
396 {12288000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
397 {18432000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
398 {12000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
399 {24000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},/*25*/
400 {27000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
403 {11289600, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
404 {16934400, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
407 {12288000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
408 {18432000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*30*/
409 {12000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
410 {24000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
413 static int soc_cs42l52_get_clk(int mclk, int rate)
416 u_int mclk1, mclk2 = 0;
418 for(i = 0; i < ARRAY_SIZE(clk_map_table); i++){
419 if(clk_map_table[i].rate == rate){
420 mclk1 = clk_map_table[i].mclk;
421 if(abs(mclk - mclk1) < abs(mclk - mclk2)){
428 return ret < ARRAY_SIZE(clk_map_table) ? ret : -EINVAL;
431 static const char *cs42l52_mic_bias[] = {"0.5VA", "0.6VA", "0.7VA", "0.8VA", "0.83VA", "0.91VA"};
432 static const char *cs42l52_hpf_freeze[] = {"Continuous DC Subtraction", "Frozen DC Subtraction"};
433 static const char *cs42l52_hpf_corner_freq[] = {"Normal", "119Hz", "236Hz", "464Hz"};
434 static const char *cs42l52_adc_sum[] = {"Normal", "Sum half", "Sub half", "Inverted"};
435 static const char *cs42l52_sig_polarity[] = {"Normal", "Inverted"};
436 static const char *cs42l52_spk_mono_channel[] = {"ChannelA", "ChannelB"};
437 static const char *cs42l52_beep_type[] = {"Off", "Single", "Multiple", "Continuous"};
438 static const char *cs42l52_treble_freq[] = {"5kHz", "7kHz", "10kHz", "15kHz"};
439 static const char *cs42l52_bass_freq[] = {"50Hz", "100Hz", "200Hz", "250Hz"};
440 static const char *cs42l52_target_sel[] = {"Apply Specific", "Apply All"};
441 static const char *cs42l52_noise_gate_delay[] = {"50ms", "100ms", "150ms", "200ms"};
442 static const char *cs42l52_adc_mux[] = {"AIN1", "AIN2", "AIN3", "AIN4", "PGA"};
443 static const char *cs42l52_mic_mux[] = {"MIC1", "MIC2"};
444 static const char *cs42l52_stereo_mux[] = {"Mono", "Stereo"};
445 static const char *cs42l52_off[] = {"On", "Off"};
446 static const char *cs42l52_hpmux[] = {"Off", "On"};
448 static const struct soc_enum soc_cs42l52_enum[] = {
449 SOC_ENUM_DOUBLE(CODEC_CS42L52_ANALOG_HPF_CTL, 4, 6, 2, cs42l52_hpf_freeze), /*0*/
450 SOC_ENUM_SINGLE(CODEC_CS42L52_ADC_HPF_FREQ, 0, 4, cs42l52_hpf_corner_freq),
451 SOC_ENUM_SINGLE(CODEC_CS42L52_ADC_MISC_CTL, 4, 4, cs42l52_adc_sum),
452 SOC_ENUM_DOUBLE(CODEC_CS42L52_ADC_MISC_CTL, 2, 3, 2, cs42l52_sig_polarity),
453 SOC_ENUM_DOUBLE(CODEC_CS42L52_PB_CTL1, 2, 3, 2, cs42l52_sig_polarity),
454 SOC_ENUM_SINGLE(CODEC_CS42L52_PB_CTL2, 2, 2, cs42l52_spk_mono_channel), /*5*/
455 SOC_ENUM_SINGLE(CODEC_CS42L52_BEEP_TONE_CTL, 6, 4, cs42l52_beep_type),
456 SOC_ENUM_SINGLE(CODEC_CS42L52_BEEP_TONE_CTL, 3, 4, cs42l52_treble_freq),
457 SOC_ENUM_SINGLE(CODEC_CS42L52_BEEP_TONE_CTL, 1, 4, cs42l52_bass_freq),
458 SOC_ENUM_SINGLE(CODEC_CS42L52_LIMITER_CTL2, 6, 2, cs42l52_target_sel),
459 SOC_ENUM_SINGLE(CODEC_CS42L52_NOISE_GATE_CTL, 7, 2, cs42l52_target_sel), /*10*/
460 SOC_ENUM_SINGLE(CODEC_CS42L52_NOISE_GATE_CTL, 0, 4, cs42l52_noise_gate_delay),
461 SOC_ENUM_SINGLE(CODEC_CS42L52_ADC_PGA_A, 5, 5, cs42l52_adc_mux),
462 SOC_ENUM_SINGLE(CODEC_CS42L52_ADC_PGA_B, 5, 5, cs42l52_adc_mux),
463 SOC_ENUM_SINGLE(CODEC_CS42L52_MICA_CTL, 6, 2, cs42l52_mic_mux),
464 SOC_ENUM_SINGLE(CODEC_CS42L52_MICB_CTL, 6, 2, cs42l52_mic_mux), /*15*/
465 SOC_ENUM_SINGLE(CODEC_CS42L52_MICA_CTL, 5, 2, cs42l52_stereo_mux),
466 SOC_ENUM_SINGLE(CODEC_CS42L52_MICB_CTL, 5, 2, cs42l52_stereo_mux),
467 SOC_ENUM_SINGLE(CODEC_CS42L52_IFACE_CTL2, 0, 6, cs42l52_mic_bias), /*18*/
468 SOC_ENUM_SINGLE(CODEC_CS42L52_PWCTL2, 0, 2, cs42l52_off),
469 SOC_ENUM_SINGLE(CODEC_CS42L52_MISC_CTL, 6, 2, cs42l52_hpmux),
470 SOC_ENUM_SINGLE(CODEC_CS42L52_MISC_CTL, 7, 2, cs42l52_hpmux),
473 static const struct snd_kcontrol_new soc_cs42l52_controls[] = {
475 SOC_ENUM("Mic VA Capture Switch", soc_cs42l52_enum[18]), /*0*/
476 SOC_DOUBLE("HPF Capture Switch", CODEC_CS42L52_ANALOG_HPF_CTL, 5, 7, 1, 0),
477 SOC_ENUM("HPF Freeze Capture Switch", soc_cs42l52_enum[0]),
479 SOC_DOUBLE("Analog SR Capture Switch", CODEC_CS42L52_ANALOG_HPF_CTL, 1, 3, 1, 1),
480 SOC_DOUBLE("Analog ZC Capture Switch", CODEC_CS42L52_ANALOG_HPF_CTL, 0, 2, 1, 1),
481 SOC_ENUM("HPF corner freq Capture Switch", soc_cs42l52_enum[1]), /*5*/
483 SOC_SINGLE("Ganged Ctl Capture Switch", CODEC_CS42L52_ADC_MISC_CTL, 7, 1, 1), /* should be enabled init */
484 SOC_ENUM("Mix/Swap Capture Switch",soc_cs42l52_enum[2]),
485 SOC_ENUM("Signal Polarity Capture Switch", soc_cs42l52_enum[3]),
487 SOC_SINGLE("HP Analog Gain Playback Volume", CODEC_CS42L52_PB_CTL1, 5, 7, 0),
488 SOC_SINGLE("Playback B=A Volume Playback Switch", CODEC_CS42L52_PB_CTL1, 4, 1, 0), /*10*/ /*should be enabled init*/
489 SOC_ENUM("PCM Signal Polarity Playback Switch",soc_cs42l52_enum[4]),
491 SOC_SINGLE("Digital De-Emphasis Playback Switch", CODEC_CS42L52_MISC_CTL, 2, 1, 0),
492 SOC_SINGLE("Digital SR Playback Switch", CODEC_CS42L52_MISC_CTL, 1, 1, 0),
493 SOC_SINGLE("Digital ZC Playback Switch", CODEC_CS42L52_MISC_CTL, 0, 1, 0),
495 SOC_SINGLE("Spk Volume Equal Playback Switch", CODEC_CS42L52_PB_CTL2, 3, 1, 0) , /*15*/ /*should be enabled init*/
496 SOC_SINGLE("Spk Mute 50/50 Playback Switch", CODEC_CS42L52_PB_CTL2, 0, 1, 0),
497 SOC_ENUM("Spk Swap Channel Playback Switch", soc_cs42l52_enum[5]),
498 SOC_SINGLE("Spk Full-Bridge Playback Switch", CODEC_CS42L52_PB_CTL2, 1, 1, 0),
499 SOC_DOUBLE_R("Mic Gain Capture Volume", CODEC_CS42L52_MICA_CTL, CODEC_CS42L52_MICB_CTL, 0, 31, 0),
501 SOC_DOUBLE_R("ALC SR Capture Switch", CODEC_CS42L52_PGAA_CTL, CODEC_CS42L52_PGAB_CTL, 7, 1, 1), /*20*/
502 SOC_DOUBLE_R("ALC ZC Capture Switch", CODEC_CS42L52_PGAA_CTL, CODEC_CS42L52_PGAB_CTL, 6, 1, 1),
503 SOC_DOUBLE_R_CS42L52("PGA Capture Volume", CODEC_CS42L52_PGAA_CTL, CODEC_CS42L52_PGAB_CTL, 0x30, 0x18),
505 SOC_DOUBLE_R_CS42L52("Passthru Playback Volume", CODEC_CS42L52_PASSTHRUA_VOL, CODEC_CS42L52_PASSTHRUB_VOL, 0x90, 0x88),
506 SOC_DOUBLE("Passthru Playback Switch", CODEC_CS42L52_MISC_CTL, 4, 5, 1, 1),
507 SOC_DOUBLE_R_CS42L52("ADC Capture Volume", CODEC_CS42L52_ADCA_VOL, CODEC_CS42L52_ADCB_VOL, 0x80, 0xA0),
508 SOC_DOUBLE("ADC Capture Switch", CODEC_CS42L52_ADC_MISC_CTL, 0, 1, 1, 1),
509 SOC_DOUBLE_R_CS42L52("ADC Mixer Capture Volume", CODEC_CS42L52_ADCA_MIXER_VOL, CODEC_CS42L52_ADCB_MIXER_VOL, 0x7f, 0x19),
510 SOC_DOUBLE_R("ADC Mixer Capture Switch", CODEC_CS42L52_ADCA_MIXER_VOL, CODEC_CS42L52_ADCB_MIXER_VOL, 7, 1, 1),
511 SOC_DOUBLE_R_CS42L52("PCM Mixer Playback Volume", CODEC_CS42L52_PCMA_MIXER_VOL, CODEC_CS42L52_PCMB_MIXER_VOL, 0x7f, 0x19),
512 SOC_DOUBLE_R("PCM Mixer Playback Switch", CODEC_CS42L52_PCMA_MIXER_VOL, CODEC_CS42L52_PCMB_MIXER_VOL, 7, 1, 1),
514 SOC_SINGLE("Beep Freq", CODEC_CS42L52_BEEP_FREQ, 4, 15, 0),
515 SOC_SINGLE("Beep OnTime", CODEC_CS42L52_BEEP_FREQ, 0, 15, 0), /*30*/
516 SOC_SINGLE_CS42L52("Beep Volume", CODEC_CS42L52_BEEP_VOL, 0, 0x1f, 0x07),
517 SOC_SINGLE("Beep OffTime", CODEC_CS42L52_BEEP_VOL, 5, 7, 0),
518 SOC_ENUM("Beep Type", soc_cs42l52_enum[6]),
519 SOC_SINGLE("Beep Mix Switch", CODEC_CS42L52_BEEP_TONE_CTL, 5, 1, 1),
521 SOC_ENUM("Treble Corner Freq Playback Switch", soc_cs42l52_enum[7]), /*35*/
522 SOC_ENUM("Bass Corner Freq Playback Switch",soc_cs42l52_enum[8]),
523 SOC_SINGLE("Tone Control Playback Switch", CODEC_CS42L52_BEEP_TONE_CTL, 0, 1, 0),
524 SOC_SINGLE("Treble Gain Playback Volume", CODEC_CS42L52_TONE_CTL, 4, 15, 1),
525 SOC_SINGLE("Bass Gain Playback Volume", CODEC_CS42L52_TONE_CTL, 0, 15, 1),
527 SOC_DOUBLE_R_CS42L52("Master Playback Volume", CODEC_CS42L52_MASTERA_VOL, CODEC_CS42L52_MASTERB_VOL,0x18, 0x18), /* koffu 40*/
528 SOC_DOUBLE_R_CS42L52("HP Digital Playback Volume", CODEC_CS42L52_HPA_VOL, CODEC_CS42L52_HPB_VOL, 0xff, 0x1),
529 SOC_DOUBLE("HP Digital Playback Switch", CODEC_CS42L52_PB_CTL2, 6, 7, 1, 1),
530 SOC_DOUBLE_R_CS42L52("Speaker Playback Volume", CODEC_CS42L52_SPKA_VOL, CODEC_CS42L52_SPKB_VOL, 0xff, 0x1),
531 SOC_DOUBLE("Speaker Playback Switch", CODEC_CS42L52_PB_CTL2, 4, 5, 1, 1),
533 SOC_SINGLE("Limiter Max Threshold Playback Volume", CODEC_CS42L52_LIMITER_CTL1, 5, 7, 0),
534 SOC_SINGLE("Limiter Cushion Threshold Playback Volume", CODEC_CS42L52_LIMITER_CTL1, 2, 7, 0),
535 SOC_SINGLE("Limiter SR Playback Switch", CODEC_CS42L52_LIMITER_CTL1, 1, 1, 0), /*45*/
536 SOC_SINGLE("Limiter ZC Playback Switch", CODEC_CS42L52_LIMITER_CTL1, 0, 1, 0),
537 SOC_SINGLE("Limiter Playback Switch", CODEC_CS42L52_LIMITER_CTL2, 7, 1, 0),
538 SOC_ENUM("Limiter Attnenuate Playback Switch", soc_cs42l52_enum[9]),
539 SOC_SINGLE("Limiter Release Rate Playback Volume", CODEC_CS42L52_LIMITER_CTL2, 0, 63, 0),
540 SOC_SINGLE("Limiter Attack Rate Playback Volume", CODEC_CS42L52_LIMITER_AT_RATE, 0, 63, 0), /*50*/
542 SOC_DOUBLE("ALC Capture Switch",CODEC_CS42L52_ALC_CTL, 6, 7, 1, 0),
543 SOC_SINGLE("ALC Attack Rate Capture Volume", CODEC_CS42L52_ALC_CTL, 0, 63, 0),
544 SOC_SINGLE("ALC Release Rate Capture Volume", CODEC_CS42L52_ALC_RATE, 0, 63, 0),
545 SOC_SINGLE("ALC Max Threshold Capture Volume", CODEC_CS42L52_ALC_THRESHOLD, 5, 7, 0),
546 SOC_SINGLE("ALC Min Threshold Capture Volume", CODEC_CS42L52_ALC_THRESHOLD, 2, 7, 0), /*55*/
548 SOC_ENUM("Noise Gate Type Capture Switch", soc_cs42l52_enum[10]),
549 SOC_SINGLE("Noise Gate Capture Switch", CODEC_CS42L52_NOISE_GATE_CTL, 6, 1, 0),
550 SOC_SINGLE("Noise Gate Boost Capture Switch", CODEC_CS42L52_NOISE_GATE_CTL, 5, 1, 1),
551 SOC_SINGLE("Noise Gate Threshold Capture Volume", CODEC_CS42L52_NOISE_GATE_CTL, 2, 7, 0),
552 SOC_ENUM("Noise Gate Delay Time Capture Switch", soc_cs42l52_enum[11]), /*60*/
554 SOC_SINGLE("Batt Compensation Switch", CODEC_CS42L52_BATT_COMPEN, 7, 1, 0),
555 SOC_SINGLE("Batt VP Monitor Switch", CODEC_CS42L52_BATT_COMPEN, 6, 1, 0),
556 SOC_SINGLE("Batt VP ref", CODEC_CS42L52_BATT_COMPEN, 0, 0x0f, 0),
557 SOC_SINGLE("Playback Charge Pump Freq", CODEC_CS42L52_CHARGE_PUMP, 4, 15, 0), /*64*/
561 static int soc_cs42l52_add_controls(struct snd_soc_codec *codec)
565 for(i = 0; i < ARRAY_SIZE(soc_cs42l52_controls); i++)
567 ret = snd_ctl_add(codec->card,
568 snd_soc_cnew(&soc_cs42l52_controls[i], codec, NULL));
572 SOCDBG("add cs42l52 controls failed\n");
579 static const struct snd_kcontrol_new cs42l52_adca_mux =
580 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[12]);
582 static const struct snd_kcontrol_new cs42l52_adcb_mux =
583 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[13]);
585 static const struct snd_kcontrol_new cs42l52_mica_mux =
586 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[14]);
588 static const struct snd_kcontrol_new cs42l52_micb_mux =
589 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[15]);
591 static const struct snd_kcontrol_new cs42l52_mica_stereo_mux =
592 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[16]);
594 static const struct snd_kcontrol_new cs42l52_micb_stereo_mux =
595 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[17]);
597 static const struct snd_kcontrol_new cs42l52_passa_switch =
598 SOC_DAPM_SINGLE("Switch", CODEC_CS42L52_MISC_CTL, 6, 1, 0);
600 static const struct snd_kcontrol_new cs42l52_passb_switch =
601 SOC_DAPM_SINGLE("Switch", CODEC_CS42L52_MISC_CTL, 7, 1, 0);
603 static const struct snd_kcontrol_new cs42l52_micbias_switch =
604 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[19]);
606 static const struct snd_kcontrol_new cs42l52_hpa_mux =
607 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[20]);
609 static const struct snd_kcontrol_new cs42l52_hpb_mux =
610 SOC_DAPM_ENUM("Route", soc_cs42l52_enum[21]);
612 static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = {
615 SND_SOC_DAPM_ADC("ADC Left", "Capture", CODEC_CS42L52_PWCTL1, 1, 1),
616 //SND_SOC_DAPM_ADC("ADC Right", "Capture", CODEC_CS42L52_PWCTL1, 2, 1),
619 SND_SOC_DAPM_MUX("MICA Mux Capture Switch", SND_SOC_NOPM, 0, 0, &cs42l52_mica_mux),
620 SND_SOC_DAPM_MUX("MICB Mux Capture Switch", SND_SOC_NOPM, 0, 0, &cs42l52_micb_mux),
621 SND_SOC_DAPM_MUX("MICA Stereo Mux Capture Switch", SND_SOC_NOPM, 1, 0, &cs42l52_mica_stereo_mux),
622 SND_SOC_DAPM_MUX("MICB Stereo Mux Capture Switch", SND_SOC_NOPM, 2, 0, &cs42l52_micb_stereo_mux),
624 SND_SOC_DAPM_MUX("ADC Mux Left Capture Switch", SND_SOC_NOPM, 1, 1, &cs42l52_adca_mux),
625 SND_SOC_DAPM_MUX("ADC Mux Right Capture Switch", SND_SOC_NOPM, 2, 1, &cs42l52_adcb_mux),
629 SND_SOC_DAPM_PGA("AIN1A Switch", CODEC_CS42L52_ADC_PGA_A, 0, 0, NULL, 0),
630 SND_SOC_DAPM_PGA("AIN2A Switch", CODEC_CS42L52_ADC_PGA_A, 1, 0, NULL, 0),
631 SND_SOC_DAPM_PGA("AIN3A Switch", CODEC_CS42L52_ADC_PGA_A, 2, 0, NULL, 0),
632 SND_SOC_DAPM_PGA("AIN4A Switch", CODEC_CS42L52_ADC_PGA_A, 3, 0, NULL, 0),
633 SND_SOC_DAPM_PGA("MICA Switch" , CODEC_CS42L52_ADC_PGA_A, 4, 0, NULL, 0),
635 SND_SOC_DAPM_PGA("AIN1B Switch", CODEC_CS42L52_ADC_PGA_B, 0, 0, NULL, 0),
636 SND_SOC_DAPM_PGA("AIN2B Switch", CODEC_CS42L52_ADC_PGA_B, 1, 0, NULL, 0),
637 SND_SOC_DAPM_PGA("AIN3B Switch", CODEC_CS42L52_ADC_PGA_B, 2, 0, NULL, 0),
638 SND_SOC_DAPM_PGA("AIN4B Switch", CODEC_CS42L52_ADC_PGA_B, 3, 0, NULL, 0),
639 SND_SOC_DAPM_PGA("MICB Switch" , CODEC_CS42L52_ADC_PGA_B, 4, 0, NULL, 0),
642 SND_SOC_DAPM_PGA("PGA MICA", CODEC_CS42L52_PWCTL2, PWCTL2_PDN_MICA_SHIFT, 1, NULL, 0),
643 SND_SOC_DAPM_PGA("PGA MICB", CODEC_CS42L52_PWCTL2, PWCTL2_PDN_MICB_SHIFT, 1, NULL, 0),
645 /* MIC bias switch */
646 SND_SOC_DAPM_MUX("Mic Bias Capture Switch", SND_SOC_NOPM, 0, 0, &cs42l52_micbias_switch),
647 SND_SOC_DAPM_PGA("Mic-Bias", CODEC_CS42L52_PWCTL2, 0, 1, NULL, 0),
650 SND_SOC_DAPM_PGA("PGA Left", CODEC_CS42L52_PWCTL1, PWCTL1_PDN_PGAA_SHIFT, 1, NULL, 0),
651 SND_SOC_DAPM_PGA("PGA Right", CODEC_CS42L52_PWCTL1, PWCTL1_PDN_PGAB_SHIFT, 1, NULL, 0),
654 SND_SOC_DAPM_MUX("Passthrough Left Playback Switch", SND_SOC_NOPM, 0, 0, &cs42l52_hpa_mux),
655 SND_SOC_DAPM_MUX("Passthrough Right Playback Switch", SND_SOC_NOPM, 0, 0, &cs42l52_hpb_mux),
657 SND_SOC_DAPM_DAC("DAC Left", "Playback", SND_SOC_NOPM, 0, 0),
658 SND_SOC_DAPM_DAC("DAC Right", "Playback", SND_SOC_NOPM, 0, 0),
660 SND_SOC_DAPM_PGA("HP Amp Left", CODEC_CS42L52_PWCTL3, 4, 1, NULL, 0),
661 SND_SOC_DAPM_PGA("HP Amp Right", CODEC_CS42L52_PWCTL3, 6, 1, NULL, 0),
663 SND_SOC_DAPM_PGA("SPK Pwr Left", CODEC_CS42L52_PWCTL3, 0, 0, NULL, 0),
664 SND_SOC_DAPM_PGA("SPK Pwr Right", CODEC_CS42L52_PWCTL3, 2, 0, NULL, 0),
666 SND_SOC_DAPM_OUTPUT("HPA"),
667 SND_SOC_DAPM_OUTPUT("HPB"),
668 SND_SOC_DAPM_OUTPUT("SPKA"),
669 SND_SOC_DAPM_OUTPUT("SPKB"),
670 SND_SOC_DAPM_OUTPUT("MICBIAS"),
672 SND_SOC_DAPM_INPUT("INPUT1A"),
673 SND_SOC_DAPM_INPUT("INPUT2A"),
674 SND_SOC_DAPM_INPUT("INPUT3A"),
675 SND_SOC_DAPM_INPUT("INPUT4A"),
676 SND_SOC_DAPM_INPUT("INPUT1B"),
677 SND_SOC_DAPM_INPUT("INPUT2B"),
678 SND_SOC_DAPM_INPUT("INPUT3B"),
679 SND_SOC_DAPM_INPUT("INPUT4B"),
680 SND_SOC_DAPM_INPUT("MICA"),
681 SND_SOC_DAPM_INPUT("MICB"),
684 static const struct snd_soc_dapm_route soc_cs42l52_audio_map[] = {
686 /* adc select path */
687 {"ADC Mux Left Capture Switch", "AIN1", "INPUT1A"},
688 {"ADC Mux Right Capture Switch", "AIN1", "INPUT1B"},
689 {"ADC Mux Left Capture Switch", "AIN2", "INPUT2A"},
690 {"ADC Mux Right Capture Switch", "AIN2", "INPUT2B"},
691 {"ADC Mux Left Capture Switch", "AIN3", "INPUT3A"},
692 {"ADC Mux Right Capture Switch", "AIN3", "INPUT3B"},
693 {"ADC Mux Left Capture Switch", "AIN4", "INPUT4A"},
694 {"ADC Mux Right Capture Switch", "AIN4", "INPUT4B"},
696 /* left capture part */
697 {"AIN1A Switch", NULL, "INPUT1A"},
698 {"AIN2A Switch", NULL, "INPUT2A"},
699 {"AIN3A Switch", NULL, "INPUT3A"},
700 {"AIN4A Switch", NULL, "INPUT4A"},
701 {"MICA Switch", NULL, "MICA"},
702 {"PGA MICA", NULL, "MICA Switch"},
704 {"PGA Left", NULL, "AIN1A Switch"},
705 {"PGA Left", NULL, "AIN2A Switch"},
706 {"PGA Left", NULL, "AIN3A Switch"},
707 {"PGA Left", NULL, "AIN4A Switch"},
708 {"PGA Left", NULL, "PGA MICA"},
710 /* right capture part */
711 {"AIN1B Switch", NULL, "INPUT1B"},
712 {"AIN2B Switch", NULL, "INPUT2B"},
713 {"AIN3B Switch", NULL, "INPUT3B"},
714 {"AIN4B Switch", NULL, "INPUT4B"},
715 {"MICB Switch", NULL, "MICB"},
716 {"PGA MICB", NULL, "MICB Switch"},
718 {"PGA Right", NULL, "AIN1B Switch"},
719 {"PGA Right", NULL, "AIN2B Switch"},
720 {"PGA Right", NULL, "AIN3B Switch"},
721 {"PGA Right", NULL, "AIN4B Switch"},
722 {"PGA Right", NULL, "PGA MICB"},
724 {"ADC Mux Left Capture Switch", "PGA", "PGA Left"},
725 {"ADC Mux Right Capture Switch", "PGA", "PGA Right"},
726 {"ADC Left", NULL, "ADC Mux Left Capture Switch"},
727 {"ADC Right", NULL, "ADC Mux Right Capture Switch"},
730 {"Mic Bias Capture Switch", "On", "PGA MICA"},
731 {"Mic Bias Capture Switch", "On", "PGA MICB"},
732 {"Mic-Bias", NULL, "Mic Bias Capture Switch"},
733 {"Mic-Bias", NULL, "Mic Bias Capture Switch"},
734 {"ADC Mux Left Capture Switch", "PGA", "Mic-Bias"},
735 {"ADC Mux Right Capture Switch", "PGA", "Mic-Bias"},
736 {"Passthrough Left Playback Switch", "On", "Mic-Bias"},
737 {"Passthrough Right Playback Switch", "On", "Mic-Bias"},
740 {"Passthrough Left Playback Switch", "On", "PGA Left"},
741 {"Passthrough Right Playback Switch", "On", "PGA Right"},
742 {"Passthrough Left Playback Switch", "Off", "DAC Left"},
743 {"Passthrough Right Playback Switch", "Off", "DAC Right"},
747 {"HP Amp Left", NULL, "Passthrough Left Playback Switch"},
748 {"HP Amp Right", NULL, "Passthrough Right Playback Switch"},
749 {"HPA", NULL, "HP Amp Left"},
750 {"HPB", NULL, "HP Amp Right"},
753 {"SPK Pwr Left", NULL, "DAC Left"},
754 {"SPK Pwr Right", NULL, "DAC Right"},
755 {"SPKA", NULL, "SPK Pwr Left"},
756 {"SPKB", NULL, "SPK Pwr Right"},
759 //{NULL, NULL, NULL},
762 static int soc_cs42l52_add_widgets(struct snd_soc_codec *soc_codec)
764 snd_soc_dapm_new_controls(soc_codec, soc_cs42l52_dapm_widgets,
765 ARRAY_SIZE(soc_cs42l52_dapm_widgets));
767 snd_soc_dapm_add_routes(soc_codec, soc_cs42l52_audio_map,
768 ARRAY_SIZE(soc_cs42l52_audio_map));
770 snd_soc_dapm_new_widgets(soc_codec);
774 #define SOC_CS42L52_RATES ( SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
775 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
776 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
777 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
778 SNDRV_PCM_RATE_96000 )
780 #define SOC_CS42L52_FORMATS ( SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
781 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
782 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
783 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE )
787 *----------------------------------------------------------------------------
788 * Function : soc_cs42l52_set_bias_level
789 * Purpose : This function is to get triggered when dapm events occurs.
791 *----------------------------------------------------------------------------
793 int soc_cs42l52_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
795 u8 pwctl1 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL1) & 0x9f;
796 u8 pwctl2 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL2) & 0x07;
799 case SND_SOC_BIAS_ON: /* full On */
802 case SND_SOC_BIAS_PREPARE: /* partial On */
803 SOCDBG("partial on\n");
804 pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
805 soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
807 case SND_SOC_BIAS_STANDBY: /* Off, with power */
808 SOCDBG("off with power\n");
809 pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
810 soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
812 case SND_SOC_BIAS_OFF: /* Off, without power */
813 SOCDBG("off without power\n");
814 soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1 | 0x9f);
815 soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL2, pwctl2 | 0x07);
818 codec->bias_level = level;
824 *----------------------------------------------------------------------------
825 * Function : cs42l52_power_init
826 * Purpose : This function is toinit codec to a normal status
828 *----------------------------------------------------------------------------
830 static void cs42l52_power_init (struct snd_soc_codec *soc_codec)
835 for(i = 0; i < soc_codec->num_dai; i++)
837 SOCINF("Cirrus CS42L52 codec , revision %d\n", ret & CHIP_REV_MASK);
839 /*set hp default volume*/
840 soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPA_VOL, DEFAULT_HP_VOL);
841 soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPB_VOL, DEFAULT_HP_VOL);
843 /*set spk default volume*/
844 soc_cs42l52_write(soc_codec, CODEC_CS42L52_SPKA_VOL, DEFAULT_SPK_VOL);
845 soc_cs42l52_write(soc_codec, CODEC_CS42L52_SPKB_VOL, DEFAULT_SPK_VOL);
847 /*set output default powerstate*/
848 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL3, 5);
850 #ifdef AUTO_DETECT_DISABLE
851 soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL,
852 (soc_cs42l52_read(soc_codec, CODEC_CS42L52_CLK_CTL)
853 & ~CLK_CTL_AUTODECT_ENABLE));
855 soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL,
856 (soc_cs42l52_read(soc_codec, CODEC_CS42L52_CLK_CTL)
857 |CLK_CTL_AUTODECT_ENABLE));
860 /*default output stream configure*/
861 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1,
862 (soc_cs42l52_read(soc_codec, CODEC_CS42L52_PB_CTL1)
863 | (PB_CTL1_HP_GAIN_06047 << PB_CTL1_HP_GAIN_SHIFT)));
865 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MISC_CTL,
866 (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MISC_CTL))
867 | (MISC_CTL_DEEMPH | MISC_CTL_DIGZC | MISC_CTL_DIGSFT));
869 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICA_CTL,
870 (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICA_CTL)
871 | 0<<6));/*pre-amplifer 16db*/
872 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICB_CTL,
873 (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICB_CTL)
874 | 0<<6));/*pre-amplifer 16db*/
876 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL2, 0x00);
877 soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_A, 0x90);
878 soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_B, 0x90);
880 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICA_CTL, 0x2c);
881 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICB_CTL, 0x2c);
883 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAA_CTL, 0x00); //0dB PGA
884 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAB_CTL, 0x00); //0dB PGA
886 soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_HPF_FREQ, 0x0F); //enable 464Hz HPF
888 //soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x12);
889 //soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x12);
891 //soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPA_VOL, 0xc0);
892 //soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPB_VOL, 0xc0);
894 soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X07);
895 soc_cs42l52_write(soc_codec, CODEC_CS42L52_TONE_CTL, 0X8f);
898 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x00);
899 soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x00);
901 soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X00);
902 soc_cs42l52_write(soc_codec, CODEC_CS42L52_TONE_CTL, 0X00);
910 *----------------------------------------------------------------------------
911 * Function : soc_cs42l52_work
912 * Purpose : This function is to power on bias.
914 *----------------------------------------------------------------------------
916 static void soc_cs42l52_work(struct work_struct *work)
918 struct snd_soc_codec *codec =
919 container_of(work, struct snd_soc_codec, delayed_work.work);
921 soc_cs42l52_set_bias_level(codec, codec->bias_level);
927 *----------------------------------------------------------------------------
928 * Function : soc_cs42l52_trigger
929 * Purpose : This function is to respond to trigger.
931 *----------------------------------------------------------------------------
933 static int soc_cs42l52_trigger(struct snd_pcm_substream *substream,
935 struct snd_soc_dai *dai)
937 struct snd_soc_pcm_runtime *rtd = substream->private_data;
938 struct snd_soc_dai_link *machine = rtd->dai;
939 struct snd_soc_dai *codec_dai = machine->codec_dai;
941 SOCDBG ("substream->stream:%s status:%d\n",
942 substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE", status);
944 if(status == 1 || status == 0){
945 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
946 codec_dai->playback.active = status;
948 codec_dai->capture.active = status;
956 *----------------------------------------------------------------------------
957 * Function : soc_cs42l52_hw_params
958 * Purpose : This function is to set the hardware parameters for CS42L52.
959 * The functions set the sample rate and audio serial data word
962 *----------------------------------------------------------------------------
964 static int soc_cs42l52_hw_params(struct snd_pcm_substream *substream,
965 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
967 struct snd_soc_pcm_runtime *rtd = substream->private_data;
968 struct snd_soc_device *soc_dev = rtd->socdev;
969 struct snd_soc_codec *soc_codec = soc_dev->card->codec;
970 struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
974 int index = soc_cs42l52_get_clk(info->sysclk, params_rate(params));
976 SOCDBG("----------sysclk=%d,rate=%d\n",info->sysclk, params_rate(params));
980 info->sysclk = clk_map_table[index].mclk;
981 clk |= (clk_map_table[index].speed << CLK_CTL_SPEED_SHIFT) |
982 (clk_map_table[index].group << CLK_CTL_32K_SR_SHIFT) |
983 (clk_map_table[index].videoclk << CLK_CTL_27M_MCLK_SHIFT) |
984 (clk_map_table[index].ratio << CLK_CTL_RATIO_SHIFT) |
985 clk_map_table[index].mclkdiv2;
987 #ifdef AUTO_DETECT_DISABLE
988 soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, clk);
990 soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, 0xa0);
994 SOCDBG("can't find out right mclk\n");
1002 *----------------------------------------------------------------------------
1003 * Function : soc_cs42l52_set_sysclk
1004 * Purpose : This function is to set the DAI system clock
1006 *----------------------------------------------------------------------------
1008 static int soc_cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
1009 int clk_id, u_int freq, int dir)
1012 struct snd_soc_codec *soc_codec = codec_dai->codec;
1013 struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
1015 SOCDBG("sysclk=%dHz,freq=%d\n", info->sysclk,freq);
1017 if((freq >= SOC_CS42L52_MIN_CLK) && (freq <= SOC_CS42L52_MAX_CLK)){
1018 info->sysclk = freq;
1019 SOCDBG("info->sysclk set to %d Hz\n", info->sysclk);
1022 printk("invalid paramter\n");
1029 *----------------------------------------------------------------------------
1030 * Function : soc_cs42l52_set_fmt
1031 * Purpose : This function is to set the DAI format
1033 *----------------------------------------------------------------------------
1035 static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
1038 struct snd_soc_codec *soc_codec = codec_dai->codec;
1039 struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
1043 /* set master/slave audio interface */
1044 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1045 case SND_SOC_DAIFMT_CBM_CFM:
1046 SOCDBG("codec dai fmt master\n");
1047 iface = IFACE_CTL1_MASTER;
1049 case SND_SOC_DAIFMT_CBS_CFS:
1050 SOCDBG("codec dai fmt slave\n");
1053 SOCDBG("invaild formate\n");
1058 /* interface format */
1059 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1060 case SND_SOC_DAIFMT_I2S:
1061 SOCDBG("codec dai fmt i2s\n");
1062 iface |= (IFACE_CTL1_ADC_FMT_I2S | IFACE_CTL1_DAC_FMT_I2S);
1064 case SND_SOC_DAIFMT_RIGHT_J:
1065 SOCDBG("codec dai fmt right justified\n");
1066 iface |= IFACE_CTL1_DAC_FMT_RIGHT_J;
1067 SOCINF("warning only playback stream support this format\n");
1069 case SND_SOC_DAIFMT_LEFT_J:
1070 SOCDBG("codec dai fmt left justified\n");
1071 iface |= (IFACE_CTL1_ADC_FMT_LEFT_J | IFACE_CTL1_DAC_FMT_LEFT_J);
1073 case SND_SOC_DAIFMT_DSP_A:
1074 iface |= IFACE_CTL1_DSP_MODE_EN;
1076 case SND_SOC_DAIFMT_DSP_B:
1077 SOCINF("unsupported format\n");
1081 SOCINF("invaild format\n");
1086 /* clock inversion */
1087 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
1088 case SND_SOC_DAIFMT_NB_NF:
1089 SOCDBG("codec dai fmt normal sclk\n");
1091 case SND_SOC_DAIFMT_IB_IF:
1092 SOCDBG("codec dai fmt inversed sclk\n");
1093 iface |= IFACE_CTL1_INV_SCLK;
1095 case SND_SOC_DAIFMT_IB_NF:
1096 iface |= IFACE_CTL1_INV_SCLK;
1098 case SND_SOC_DAIFMT_NB_IF:
1101 SOCDBG("unsupported format\n");
1105 info->format = iface;
1107 soc_cs42l52_write(soc_codec, CODEC_CS42L52_IFACE_CTL1, info->format);
1113 *----------------------------------------------------------------------------
1114 * Function : soc_cs42l52_digital_mute
1115 * Purpose : This function is to mute DAC or not
1117 *----------------------------------------------------------------------------
1119 static int soc_cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
1121 struct snd_soc_codec *soc_codec = dai->codec;
1122 u8 mute_val = soc_cs42l52_read(soc_codec, CODEC_CS42L52_PB_CTL1) & PB_CTL1_MUTE_MASK;
1124 SOCDBG("%d\n",mute);
1127 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val \
1128 | PB_CTL1_MSTB_MUTE | PB_CTL1_MSTA_MUTE);
1131 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val );
1137 static struct snd_soc_dai_ops cs42l52_ops = {
1138 .hw_params = soc_cs42l52_hw_params,
1139 .set_sysclk = soc_cs42l52_set_sysclk,
1140 .set_fmt = soc_cs42l52_set_fmt,
1141 .trigger = soc_cs42l52_trigger,
1142 .digital_mute = soc_cs42l52_digital_mute,
1145 *----------------------------------------------------------------------------
1146 * @struct soc_cs42l52_dai |
1147 * It is SoC Codec DAI structure which has DAI capabilities viz.,
1148 * playback and capture, DAI runtime information viz. state of DAI
1149 * and pop wait state, and DAI private data.
1150 * The AIC3111 rates ranges from 8k to 192k
1151 * The PCM bit format supported are 16, 20, 24 and 32 bits
1152 *----------------------------------------------------------------------------
1154 struct snd_soc_dai soc_cs42l52_dai = {
1155 .name = SOC_CS42L52_NAME,
1157 .stream_name = "Playback",
1159 .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
1160 .rates = SOC_CS42L52_RATES,
1161 .formats = SOC_CS42L52_FORMATS,
1164 .stream_name = "Capture",
1166 .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
1167 .rates = SOC_CS42L52_RATES,
1168 .formats = SOC_CS42L52_FORMATS,
1170 .ops = &cs42l52_ops,
1172 EXPORT_SYMBOL_GPL(soc_cs42l52_dai);
1175 #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
1176 static int cs42l52_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
1178 struct snd_soc_codec *soc_codec;
1179 struct soc_codec_cs42l52 * info;
1180 struct cs42l52_platform_data *pdata = i2c->dev.platform_data;
1183 soc_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
1184 if (soc_codec == NULL)
1187 soc_codec->name = SOC_CS42L52_NAME;
1188 soc_codec->owner = THIS_MODULE;
1189 soc_codec->write = soc_cs42l52_write;
1190 soc_codec->read = soc_cs42l52_read;
1191 soc_codec->hw_write = (hw_write_t)i2c_master_send;
1192 mutex_init(&soc_codec->mutex);
1193 INIT_LIST_HEAD(&soc_codec->dapm_widgets);
1194 INIT_LIST_HEAD(&soc_codec->dapm_paths);
1196 soc_codec->set_bias_level = soc_cs42l52_set_bias_level;
1197 soc_codec->dai = &soc_cs42l52_dai;
1198 soc_codec->dai->playback.channels_max = 2;
1199 soc_codec->dai->capture.channels_max = 2;
1200 soc_codec->num_dai = 1;
1201 soc_codec->control_data = i2c;
1202 soc_codec->dev = &i2c->dev;
1203 soc_codec->pcm_devs = 0;
1204 soc_codec->pop_time = 2;
1205 soc_codec->dai[0].codec = soc_codec;
1207 soc_codec->reg_cache_size = sizeof(soc_cs42l52_reg_default);
1209 soc_codec->reg_cache = kmemdup(soc_cs42l52_reg_default, sizeof(soc_cs42l52_reg_default), GFP_KERNEL);
1211 info = (struct soc_codec_cs42l52 *)kmalloc(sizeof(struct soc_codec_cs42l52),GFP_KERNEL);
1217 info->sysclk = SOC_CS42L52_DEFAULT_CLK;
1218 info->format = SOC_CS42L52_DEFAULT_FORMAT;
1220 soc_codec->private_data =(void*)info;
1221 if(!soc_codec->reg_cache) {
1222 SOCERR("%s: err out of memory\n", __FUNCTION__);
1227 if (pdata->init_platform_hw)
1228 pdata->init_platform_hw();
1230 /*initialize codec*/
1231 cs42l52_power_init(soc_codec);
1233 INIT_DELAYED_WORK(&soc_codec->delayed_work, soc_cs42l52_work);
1235 soc_cs42l52_dai.dev = &i2c->dev;
1236 cs42l52_codec = soc_codec;
1238 ret = snd_soc_register_codec(soc_codec);
1240 dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
1244 ret = snd_soc_register_dai(&soc_cs42l52_dai);
1246 dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
1253 snd_soc_unregister_codec(soc_codec);
1255 kfree(cs42l52_codec);
1256 cs42l52_codec = NULL;
1260 static int cs42l52_i2c_remove(struct i2c_client *client)
1262 snd_soc_unregister_dai(&soc_cs42l52_dai);
1263 snd_soc_unregister_codec(cs42l52_codec);
1265 soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
1267 soc_cs42l52_dai.dev = NULL;
1268 if(cs42l52_codec->reg_cache)
1269 kfree(cs42l52_codec->reg_cache);
1270 if(cs42l52_codec->private_data)
1271 kfree(cs42l52_codec->private_data);
1272 kfree(cs42l52_codec);
1273 cs42l52_codec = NULL;
1279 static int cs42l52_i2c_shutdown(struct i2c_client *client)
1281 SOCDBG("i am here\n");
1282 snd_soc_unregister_dai(&soc_cs42l52_dai);
1283 snd_soc_unregister_codec(cs42l52_codec);
1285 soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
1287 soc_cs42l52_dai.dev = NULL;
1288 if(cs42l52_codec->reg_cache)
1289 kfree(cs42l52_codec->reg_cache);
1290 if(cs42l52_codec->private_data)
1291 kfree(cs42l52_codec->private_data);
1292 kfree(cs42l52_codec);
1293 cs42l52_codec = NULL;
1298 static const struct i2c_device_id cs42l52_i2c_id[] = {
1301 MODULE_DEVICE_TABLE(i2c, cs42l52_i2c_id);
1303 static struct i2c_driver cs42l52_i2c_drv = {
1306 .owner = THIS_MODULE,
1308 .probe = cs42l52_i2c_probe,
1309 .remove = cs42l52_i2c_remove,
1310 .shutdown = cs42l52_i2c_shutdown,
1311 .id_table = cs42l52_i2c_id,
1317 #ifdef CONFIG_HAS_EARLYSUSPEND
1318 static int soc_cs42l52_suspend(struct early_suspend *h)
1321 soc_cs42l52_write(cs42l52_codec, CODEC_CS42L52_PWCTL1, PWCTL1_PDN_CODEC);
1322 soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
1326 static int soc_cs42l52_resume(struct early_suspend *h)
1328 struct snd_soc_codec *soc_codec = cs42l52_codec;
1329 struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*) soc_codec->private_data;
1332 u8 *reg_cache = (u8*) soc_codec->reg_cache;
1333 soc_codec->num_dai = 1;
1334 /* Sync reg_cache with the hardware */
1335 for(i = 0; i < soc_codec->num_dai; i++) {
1337 for(reg = 0; reg < ARRAY_SIZE(soc_cs42l52_reg_default); reg++) {
1339 data[1] = reg_cache[reg];
1340 if(soc_codec->hw_write(soc_codec->control_data, data, 2) != 2)
1345 soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_STANDBY);
1347 /*charge cs42l52 codec*/
1348 if(soc_codec->suspend_bias_level == SND_SOC_BIAS_ON)
1350 soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_PREPARE);
1351 soc_codec->bias_level = SND_SOC_BIAS_ON;
1352 schedule_delayed_work(&soc_codec->delayed_work, msecs_to_jiffies(1000));
1358 static int soc_cs42l52_suspend(struct platform_device *pdev, pm_message_t state)
1360 struct snd_soc_device *soc_dev = (struct snd_soc_device*)platform_get_drvdata(pdev);
1361 struct snd_soc_codec *soc_codec = soc_dev->card->codec;
1363 soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL1, PWCTL1_PDN_CODEC);
1364 soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_OFF);
1368 static int soc_cs42l52_resume(struct platform_device *pdev)
1370 struct snd_soc_device *soc_dev = (struct snd_soc_device*) platform_get_drvdata(pdev);
1371 struct snd_soc_codec *soc_codec = soc_dev->card->codec;
1372 struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*) soc_codec->private_data;
1375 u8 *reg_cache = (u8*) soc_codec->reg_cache;
1376 soc_codec->num_dai = 1;
1377 /* Sync reg_cache with the hardware */
1378 for(i = 0; i < soc_codec->num_dai; i++) {
1380 for(reg = 0; reg < ARRAY_SIZE(soc_cs42l52_reg_default); reg++) {
1382 data[1] = reg_cache[reg];
1383 if(soc_codec->hw_write(soc_codec->control_data, data, 2) != 2)
1388 soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_STANDBY);
1390 /*charge cs42l52 codec*/
1391 if(soc_codec->suspend_bias_level == SND_SOC_BIAS_ON)
1393 soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_PREPARE);
1394 soc_codec->bias_level = SND_SOC_BIAS_ON;
1395 schedule_delayed_work(&soc_codec->delayed_work, msecs_to_jiffies(1000));
1401 static int soc_cs42l52_probe(struct platform_device *pdev)
1403 struct snd_soc_device *soc_dev = platform_get_drvdata(pdev);
1404 struct snd_soc_codec *soc_codec;
1407 if (cs42l52_codec == NULL) {
1408 dev_err(&pdev->dev, "Codec device not registered\n");
1412 soc_dev->card->codec = cs42l52_codec;
1413 soc_codec = cs42l52_codec;
1415 ret = snd_soc_new_pcms(soc_dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1418 SOCERR("%s: add new pcms failed\n",__FUNCTION__);
1422 soc_cs42l52_add_controls(soc_codec);
1423 soc_cs42l52_add_widgets(soc_codec);
1425 ret = snd_soc_init_card(soc_dev);
1427 INIT_DELAYED_WORK(&soc_codec->delayed_work, soc_cs42l52_work);
1431 SOCERR("add snd card failed\n");
1435 #ifdef CONFIG_HAS_EARLYSUSPEND
1436 cs42l52_early_suspend.suspend =soc_cs42l52_suspend;
1437 cs42l52_early_suspend.resume =soc_cs42l52_resume;// cs42l52_early_suspend.level = 0x2;
1438 register_early_suspend(&cs42l52_early_suspend);
1443 snd_soc_free_pcms(soc_dev);
1444 snd_soc_dapm_free(soc_dev);
1450 static int soc_cs42l52_remove(struct platform_device *pdev)
1452 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1454 snd_soc_free_pcms(socdev);
1455 snd_soc_dapm_free(socdev);
1456 #ifdef CONFIG_HAS_EARLYSUSPEND
1457 unregister_early_suspend(&cs42l52_early_suspend);
1462 struct snd_soc_codec_device soc_codec_dev_cs42l52 = {
1463 .probe = soc_cs42l52_probe,
1464 .remove = soc_cs42l52_remove,
1465 #ifndef CONFIG_HAS_EARLYSUSPEND
1466 .suspend = soc_cs42l52_suspend,
1467 .resume = soc_cs42l52_resume,
1471 EXPORT_SYMBOL_GPL(soc_codec_dev_cs42l52);
1473 static int __init cs42l52_modinit(void)
1475 return i2c_add_driver(&cs42l52_i2c_drv);
1477 module_init(cs42l52_modinit);
1479 static void __exit cs42l52_exit(void)
1481 i2c_del_driver(&cs42l52_i2c_drv);
1483 module_exit(cs42l52_exit);
1487 MODULE_DESCRIPTION("ALSA SoC CS42L52 Codec");
1488 MODULE_AUTHOR("Bo Liu, Bo.Liu@cirrus.com, www.cirrus.com");
1489 MODULE_LICENSE("GPL");
1494 #ifdef CONFIG_PROC_FS
1495 #include <linux/proc_fs.h>
1496 #include <linux/seq_file.h>
1497 static int proc_cs42l52_show (struct seq_file *s, void *v)
1499 struct snd_soc_codec *codec = cs42l52_codec;
1502 seq_printf (s, " cs42l52 registers:\n");
1503 for (reg = 0; reg < 53; reg++) {
1505 seq_printf (s, "\n ");
1506 seq_printf (s, "0x%02x ", soc_cs42l52_read(codec, reg));
1508 seq_printf (s, "\n\n");
1510 #if 0//for check cache
1511 u8 *cache = codec->reg_cache;
1512 seq_printf (s, " cache:\n");
1513 for (reg = 0; reg < 53; reg++) {
1515 seq_printf (s, "\n ");
1516 seq_printf (s, "0x%02x ", cache[reg]);
1518 seq_printf (s, "\n\n");
1524 static int proc_cs42l52_open (struct inode *inode, struct file *file)
1526 return single_open (file, proc_cs42l52_show, NULL);
1529 static const struct file_operations proc_cs42l52_fops = {
1530 .open = proc_cs42l52_open,
1532 .llseek = seq_lseek,
1533 .release = single_release,
1536 static int __init codec_proc_init (void)
1538 proc_create ("cs42l52", 0, NULL, &proc_cs42l52_fops);
1541 late_initcall (codec_proc_init);
1542 #endif /* CONFIG_PROC_FS */