#include <sound/initval.h>
#include <sound/tlv.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <asm/io.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
#include "cs42l52.h"
#include <mach/board.h>
+
//#include "cs42L52_control.h"
-//#define DEBUG
+
+
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)
+ #define AUTO_DETECT_DISABLE
+#else
+ //#define AUTO_DETECT_DISABLE
+ #undef AUTO_DETECT_DISABLE
+#endif
+
+#define DEBUG
#ifdef DEBUG
#define SOCDBG(fmt, arg...) printk(KERN_ERR "%s: %s() " fmt, SOC_CS42L52_NAME, __FUNCTION__, ##arg)
#else
-#define SOCDBG(fmt, arg...)
+#define SOCDBG(fmt, arg...) do { } while (0)
#endif
#define SOCINF(fmt, args...) printk(KERN_INFO "%s: " fmt, SOC_CS42L52_NAME, ##args)
#define SOCERR(fmt, args...) printk(KERN_ERR "%s: " fmt, SOC_CS42L52_NAME, ##args)
+
+
static void soc_cs42l52_work(struct work_struct *work);
-static int soc_cs42l52_set_bias_level(struct snd_soc_codec *codec,
- enum snd_soc_bias_level level);
-static int soc_cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, struct snd_soc_dai *dai);
-static int soc_cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, u_int freq, int dir);
-static int soc_cs42l52_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
- int div_id, int div);
+static struct snd_soc_codec *cs42l52_codec;
-static int soc_cs42l52_digital_mute(struct snd_soc_dai *dai, int mute);
-static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
- u_int fmt);
-static unsigned int soc_cs42l52_read(struct snd_soc_codec *codec,
- u_int reg);
+//added for suspend
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+static struct early_suspend cs42l52_early_suspend;
+#endif
/**
* snd_soc_get_volsw - single mixer get callback
int snd_soc_cs42l5x_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+SOCDBG("i am here\n");
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0x0f;
/*
* CS42L52 register default value
*/
-
static const u8 soc_cs42l52_reg_default[] = {
0x00, 0xE0, 0x01, 0x07, 0x05, /*4*/
0xa0, 0x00, 0x00, 0x81, /*8*/
int i,num, ret = 0;
struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)codec->private_data;
- datas[0] = reg & 0xff; /*reg addr*/
- datas[1] = val & 0xff; /*reg val*/
+ datas[0] = reg & 0xff;
+ datas[1] = val & 0xff;
codec->num_dai = 1;
if(info->flags & SOC_CS42L52_ALL_IN_ONE)
{
ret = -EIO;
}
- printk(KERN_INFO"soc_cs42l52_write---reg=%d--val=%d\n",reg,val);
if(ret >= 0)
soc_cs42l52_write_reg_cache(codec, reg, val);
static unsigned int soc_cs42l52_read(struct snd_soc_codec *codec,
u_int reg)
{
-#if 0//commented out @20110706, for audio recording commit
- u8 data;
- u8 addr;
- int i, ret = 0;
-
- struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)codec->private_data;
-#ifndef CONFIG_CS42L52_DEBUG
- if(reg == CODEC_CS42L52_SPK_STATUS)
- {
-
-#endif
- addr = reg & 0xff;
- if(info->flags & SOC_CS42L52_ALL_IN_ONE)
- {
- codec->num_dai = 1;
- for(i = 0; i < codec->num_dai; i++)
- {
- if(codec->hw_write(codec->control_data, &addr, 1) == 1)
- {
-// if(codec->hw_read(codec->control_data, &data, 1) == 1)
- {
-// ret |= data << (i * 8);
- }
- }
- else{
- ret = -EIO;
- break;
- }
-
- }
- }
-#ifndef CONFIG_CS42L52_DEBUG
- }
- else{
-
-
- u8 *cache = codec->reg_cache;
- u8 retval;
- retval = reg > SOC_CS42L52_REG_NUM ? -EINVAL : cache[reg];
-/* SOCDBG("%s (cache) 0x%x = %02x (%d)\n", reg, retval, retval); */
- return retval;
- }
-#endif
-// SOCDBG("0x%x = %02x (%d)\n", reg, ret, ret);
- return ret;
-#else
- //return codec->read(codec, reg);
-
+#if 1
u8 data;
- if(i2c_master_reg8_recv(codec->control_data,reg,&data,1,50*1000)>0)
- {
- printk("cs42l52 read reg%x = %d\n",reg,data);
+ if(i2c_master_reg8_recv(codec->control_data,reg,&data,1,50*1000)>0) {
return data;
}
- else
- {
+ else {
printk("cs42l52 read error\n");
return -1;
}
+#else
+ return codec->read(codec, reg);
+#endif
+}
+
+struct soc_cs42l52_clk_para {
+ u32 mclk;
+ u32 rate;
+ u8 speed;
+ u8 group;
+ u8 videoclk;
+ u8 ratio;
+ u8 mclkdiv2;
+};
+
+static const struct soc_cs42l52_clk_para clk_map_table[] = {
+ /*8k*/
+ {12288000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {18432000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {12000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+ {24000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+ {27000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0}, /*4*/
+
+ /*11.025k*/
+ {11289600, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {16934400, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+
+ /*16k*/
+ {12288000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {18432000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {12000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},/*9*/
+ {24000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+ {27000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
+
+ /*22.05k*/
+ {11289600, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {16934400, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ /* 32k */
+ {12288000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*14*/
+ {18432000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {12000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+ {24000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+ {27000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0},
+ /* 44.1k */
+ {11289600, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*19*/
+ {16934400, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {12000000, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_136, 0},
-#endif
+ /* 48k */
+ {12288000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {18432000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {12000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+ {24000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},/*25*/
+ {27000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
+
+ /* 88.2k */
+ {11289600, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {16934400, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+
+ /* 96k */
+ {12288000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ {18432000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*30*/
+ {12000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
+ {24000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
+};
+
+static int soc_cs42l52_get_clk(int mclk, int rate)
+{
+ int i , ret = 0;
+ u_int mclk1, mclk2 = 0;
+
+ for(i = 0; i < ARRAY_SIZE(clk_map_table); i++){
+ if(clk_map_table[i].rate == rate){
+ mclk1 = clk_map_table[i].mclk;
+ if(abs(mclk - mclk1) < abs(mclk - mclk2)){
+ mclk2 = mclk1;
+ ret = i;
+ }
+ }
+ }
+
+ return ret < ARRAY_SIZE(clk_map_table) ? ret : -EINVAL;
}
static const char *cs42l52_mic_bias[] = {"0.5VA", "0.6VA", "0.7VA", "0.8VA", "0.83VA", "0.91VA"};
for(i = 0; i < ARRAY_SIZE(soc_cs42l52_controls); i++)
{
ret = snd_ctl_add(codec->card,
- snd_soc_cnew(&soc_cs42l52_controls[i], codec, NULL));
+ snd_soc_cnew(&soc_cs42l52_controls[i], codec, NULL));
+
if(ret < 0)
{
SOCDBG("add cs42l52 controls failed\n");
SOC_DAPM_ENUM("Route", soc_cs42l52_enum[21]);
static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = {
-#if 0 //20110706
+
/* Input path */
SND_SOC_DAPM_ADC("ADC Left", "Capture", CODEC_CS42L52_PWCTL1, 1, 1),
- SND_SOC_DAPM_ADC("ADC Right", "Capture", CODEC_CS42L52_PWCTL1, 2, 1),
-#endif
+ //SND_SOC_DAPM_ADC("ADC Right", "Capture", CODEC_CS42L52_PWCTL1, 2, 1),
+
+
SND_SOC_DAPM_MUX("MICA Mux Capture Switch", SND_SOC_NOPM, 0, 0, &cs42l52_mica_mux),
SND_SOC_DAPM_MUX("MICB Mux Capture Switch", SND_SOC_NOPM, 0, 0, &cs42l52_micb_mux),
SND_SOC_DAPM_MUX("MICA Stereo Mux Capture Switch", SND_SOC_NOPM, 1, 0, &cs42l52_mica_stereo_mux),
SND_SOC_DAPM_MUX("ADC Mux Left Capture Switch", SND_SOC_NOPM, 1, 1, &cs42l52_adca_mux),
SND_SOC_DAPM_MUX("ADC Mux Right Capture Switch", SND_SOC_NOPM, 2, 1, &cs42l52_adcb_mux),
-#if 0//20110706
+
/* Sum switches */
SND_SOC_DAPM_PGA("AIN1A Switch", CODEC_CS42L52_ADC_PGA_A, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("AIN2A Switch", CODEC_CS42L52_ADC_PGA_A, 1, 0, NULL, 0),
/* PGA Power */
SND_SOC_DAPM_PGA("PGA Left", CODEC_CS42L52_PWCTL1, PWCTL1_PDN_PGAA_SHIFT, 1, NULL, 0),
SND_SOC_DAPM_PGA("PGA Right", CODEC_CS42L52_PWCTL1, PWCTL1_PDN_PGAB_SHIFT, 1, NULL, 0),
-#endif
+
/* Output path */
SND_SOC_DAPM_MUX("Passthrough Left Playback Switch", SND_SOC_NOPM, 0, 0, &cs42l52_hpa_mux),
SND_SOC_DAPM_MUX("Passthrough Right Playback Switch", SND_SOC_NOPM, 0, 0, &cs42l52_hpb_mux),
SND_SOC_DAPM_DAC("DAC Left", "Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DAC Right", "Playback", SND_SOC_NOPM, 0, 0),
- // SND_SOC_DAPM_PGA("HP Amp Left", CODEC_CS42L52_PWCTL3, 4, 1, NULL, 0),
- // SND_SOC_DAPM_PGA("HP Amp Right", CODEC_CS42L52_PWCTL3, 6, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("HP Amp Left", CODEC_CS42L52_PWCTL3, 4, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("HP Amp Right", CODEC_CS42L52_PWCTL3, 6, 1, NULL, 0),
- // SND_SOC_DAPM_PGA("SPK Pwr Left", CODEC_CS42L52_PWCTL3, 0, 1, NULL, 0),
- // SND_SOC_DAPM_PGA("SPK Pwr Right", CODEC_CS42L52_PWCTL3, 2, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("SPK Pwr Left", CODEC_CS42L52_PWCTL3, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("SPK Pwr Right", CODEC_CS42L52_PWCTL3, 2, 0, NULL, 0),
SND_SOC_DAPM_OUTPUT("HPA"),
SND_SOC_DAPM_OUTPUT("HPB"),
{"ADC Mux Left Capture Switch", "AIN1", "INPUT1A"},
{"ADC Mux Right Capture Switch", "AIN1", "INPUT1B"},
{"ADC Mux Left Capture Switch", "AIN2", "INPUT2A"},
- {"ADC Mux Right Capture Switch", "AIN2", "INPUT2B"},
+ {"ADC Mux Right Capture Switch", "AIN2", "INPUT2B"},
{"ADC Mux Left Capture Switch", "AIN3", "INPUT3A"},
- {"ADC Mux Right Capture Switch", "AIN3", "INPUT3B"},
+ {"ADC Mux Right Capture Switch", "AIN3", "INPUT3B"},
{"ADC Mux Left Capture Switch", "AIN4", "INPUT4A"},
- {"ADC Mux Right Capture Switch", "AIN4", "INPUT4B"},
+ {"ADC Mux Right Capture Switch", "AIN4", "INPUT4B"},
/* left capture part */
- {"AIN1A Switch", NULL, "INPUT1A"},
- {"AIN2A Switch", NULL, "INPUT2A"},
- {"AIN3A Switch", NULL, "INPUT3A"},
- {"AIN4A Switch", NULL, "INPUT4A"},
- {"MICA Switch", NULL, "MICA"},
- {"PGA MICA", NULL, "MICA Switch"},
-
- {"PGA Left", NULL, "AIN1A Switch"},
- {"PGA Left", NULL, "AIN2A Switch"},
- {"PGA Left", NULL, "AIN3A Switch"},
- {"PGA Left", NULL, "AIN4A Switch"},
- {"PGA Left", NULL, "PGA MICA"},
+ {"AIN1A Switch", NULL, "INPUT1A"},
+ {"AIN2A Switch", NULL, "INPUT2A"},
+ {"AIN3A Switch", NULL, "INPUT3A"},
+ {"AIN4A Switch", NULL, "INPUT4A"},
+ {"MICA Switch", NULL, "MICA"},
+ {"PGA MICA", NULL, "MICA Switch"},
+
+ {"PGA Left", NULL, "AIN1A Switch"},
+ {"PGA Left", NULL, "AIN2A Switch"},
+ {"PGA Left", NULL, "AIN3A Switch"},
+ {"PGA Left", NULL, "AIN4A Switch"},
+ {"PGA Left", NULL, "PGA MICA"},
/* right capture part */
- {"AIN1B Switch", NULL, "INPUT1B"},
- {"AIN2B Switch", NULL, "INPUT2B"},
- {"AIN3B Switch", NULL, "INPUT3B"},
- {"AIN4B Switch", NULL, "INPUT4B"},
- {"MICB Switch", NULL, "MICB"},
- {"PGA MICB", NULL, "MICB Switch"},
-
- {"PGA Right", NULL, "AIN1B Switch"},
- {"PGA Right", NULL, "AIN2B Switch"},
- {"PGA Right", NULL, "AIN3B Switch"},
- {"PGA Right", NULL, "AIN4B Switch"},
- {"PGA Right", NULL, "PGA MICB"},
+ {"AIN1B Switch", NULL, "INPUT1B"},
+ {"AIN2B Switch", NULL, "INPUT2B"},
+ {"AIN3B Switch", NULL, "INPUT3B"},
+ {"AIN4B Switch", NULL, "INPUT4B"},
+ {"MICB Switch", NULL, "MICB"},
+ {"PGA MICB", NULL, "MICB Switch"},
+
+ {"PGA Right", NULL, "AIN1B Switch"},
+ {"PGA Right", NULL, "AIN2B Switch"},
+ {"PGA Right", NULL, "AIN3B Switch"},
+ {"PGA Right", NULL, "AIN4B Switch"},
+ {"PGA Right", NULL, "PGA MICB"},
{"ADC Mux Left Capture Switch", "PGA", "PGA Left"},
- {"ADC Mux Right Capture Switch", "PGA", "PGA Right"},
+ {"ADC Mux Right Capture Switch", "PGA", "PGA Right"},
{"ADC Left", NULL, "ADC Mux Left Capture Switch"},
{"ADC Right", NULL, "ADC Mux Right Capture Switch"},
/* Mic Bias */
- {"Mic Bias Capture Switch", "On", "PGA MICA"},
- {"Mic Bias Capture Switch", "On", "PGA MICB"},
+ {"Mic Bias Capture Switch", "On", "PGA MICA"},
+ {"Mic Bias Capture Switch", "On", "PGA MICB"},
{"Mic-Bias", NULL, "Mic Bias Capture Switch"},
{"Mic-Bias", NULL, "Mic Bias Capture Switch"},
- {"ADC Mux Left Capture Switch", "PGA", "Mic-Bias"},
- {"ADC Mux Right Capture Switch", "PGA", "Mic-Bias"},
- {"Passthrough Left Playback Switch", "On", "Mic-Bias"},
- {"Passthrough Right Playback Switch", "On", "Mic-Bias"},
+ {"ADC Mux Left Capture Switch", "PGA", "Mic-Bias"},
+ {"ADC Mux Right Capture Switch", "PGA", "Mic-Bias"},
+ {"Passthrough Left Playback Switch", "On", "Mic-Bias"},
+ {"Passthrough Right Playback Switch", "On", "Mic-Bias"},
/* loopback path */
{"Passthrough Left Playback Switch", "On", "PGA Left"},
{"Passthrough Left Playback Switch", "Off", "DAC Left"},
{"Passthrough Right Playback Switch", "Off", "DAC Right"},
-/* Output map */
+ /* Output map */
/* Headphone */
{"HP Amp Left", NULL, "Passthrough Left Playback Switch"},
{"HP Amp Right", NULL, "Passthrough Right Playback Switch"},
{"HPB", NULL, "HP Amp Right"},
/* Speakers */
-
{"SPK Pwr Left", NULL, "DAC Left"},
{"SPK Pwr Right", NULL, "DAC Right"},
{"SPKA", NULL, "SPK Pwr Left"},
{"SPKB", NULL, "SPK Pwr Right"},
/* terminator */
- // {NULL, NULL, NULL},
+ //{NULL, NULL, NULL},
};
static int soc_cs42l52_add_widgets(struct snd_soc_codec *soc_codec)
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
- SNDRV_PCM_RATE_96000 ) /*refer to cs42l52 datasheet page35*/
+ SNDRV_PCM_RATE_96000 )
#define SOC_CS42L52_FORMATS ( SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE )
-static int soc_cs42l52_trigger(struct snd_pcm_substream *substream,
- int status,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai_link *machine = rtd->dai;
- struct snd_soc_dai *codec_dai = machine->codec_dai;
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_set_bias_level
+ * Purpose : This function is to get triggered when dapm events occurs.
+ *
+ *----------------------------------------------------------------------------
+ */
+int soc_cs42l52_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+{
+ u8 pwctl1 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL1) & 0x9f;
+ u8 pwctl2 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL2) & 0x07;
- if(status == 1 || status == 0){
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
- codec_dai->playback.active = status;
- }else{
- codec_dai->capture.active = status;
- }
- }
+ switch (level) {
+ case SND_SOC_BIAS_ON: /* full On */
+ SOCDBG("full on\n");
+ break;
+ case SND_SOC_BIAS_PREPARE: /* partial On */
+ SOCDBG("partial on\n");
+ pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
+ soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
+ break;
+ case SND_SOC_BIAS_STANDBY: /* Off, with power */
+ SOCDBG("off with power\n");
+ pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
+ soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
+ break;
+ case SND_SOC_BIAS_OFF: /* Off, without power */
+ SOCDBG("off without power\n");
+ soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1 | 0x9f);
+ soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL2, pwctl2 | 0x07);
+ break;
+ }
+ codec->bias_level = level;
- return 0;
+ return 0;
}
-
-static struct snd_soc_dai_ops cs42l52_ops = {
- .hw_params = soc_cs42l52_pcm_hw_params,
- .set_sysclk = soc_cs42l52_set_sysclk,
- .set_fmt = soc_cs42l52_set_fmt,
- .digital_mute = soc_cs42l52_digital_mute,
- .set_clkdiv = soc_cs42l52_set_dai_clkdiv,
- .trigger = soc_cs42l52_trigger, //20110706, add for audio recording
-};
-
-
-struct snd_soc_dai soc_cs42l52_dai = {
- .name = SOC_CS42L52_NAME,
- .playback = {
- .stream_name = "Playback",
- .channels_min = 1,
- .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
- .rates = SOC_CS42L52_RATES,
- .formats = SOC_CS42L52_FORMATS,
- },
- .capture = {
- .stream_name = "Capture",
- .channels_min = 1,
- .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
- .rates = SOC_CS42L52_RATES,
- .formats = SOC_CS42L52_FORMATS,
- },
- .ops = &cs42l52_ops,
-#if 0
- .ops = {
- .hw_params = soc_cs42l52_pcm_hw_params,
- .set_sysclk = soc_cs42l52_set_sysclk,
- .set_fmt = soc_cs42l52_set_fmt,
- .digital_mute = soc_cs42l52_digital_mute,
- },
-#endif
-};
-
-EXPORT_SYMBOL_GPL(soc_cs42l52_dai);
-
-/* #define CONFIG_MANUAL_CLK */
-
-/* page 37 from cs42l52 datasheet */
-static void soc_cs42l52_required_setup(struct snd_soc_codec *codec)
+/*
+ *----------------------------------------------------------------------------
+ * Function : cs42l52_power_init
+ * Purpose : This function is toinit codec to a normal status
+ *
+ *----------------------------------------------------------------------------
+ */
+static void cs42l52_power_init (struct snd_soc_codec *soc_codec)
{
- u8 data;
- soc_cs42l52_write(codec, 0x00, 0x99);
- soc_cs42l52_write(codec, 0x3e, 0xba);
- soc_cs42l52_write(codec, 0x47, 0x80);
- data = soc_cs42l52_read(codec, 0x32);
- soc_cs42l52_write(codec, 0x32, data | 0x80);
- soc_cs42l52_write(codec, 0x32, data & 0x7f);
- soc_cs42l52_write(codec, 0x00, 0x00);
-}
-
-
-static struct snd_soc_codec *cs42l52_codec;
-
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
-
-
-static int cs42l52_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
-{
- struct snd_soc_codec *soc_codec;
- struct soc_codec_cs42l52 * info;
- struct cs42l52_platform_data *pdata = i2c->dev.platform_data;
- unsigned int reg;
- int i, ret = 0;
- printk(KERN_INFO"cs42l52_i2c_probe\n");
-
- soc_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
- if (soc_codec == NULL)
- return -ENOMEM;
-
- soc_codec->name = SOC_CS42L52_NAME;
- soc_codec->owner = THIS_MODULE;
- soc_codec->write = soc_cs42l52_write;
- soc_codec->read = soc_cs42l52_read;
- soc_codec->hw_write = (hw_write_t)i2c_master_send;
- mutex_init(&soc_codec->mutex);
- INIT_LIST_HEAD(&soc_codec->dapm_widgets);
- INIT_LIST_HEAD(&soc_codec->dapm_paths);
-
- soc_codec->set_bias_level = soc_cs42l52_set_bias_level;
- soc_codec->dai = &soc_cs42l52_dai;
- soc_codec->dai->playback.channels_max = 2;
- soc_codec->dai->capture.channels_max = 2;
- soc_codec->num_dai = 1;
- soc_codec->control_data = i2c;
- soc_codec->dev = &i2c->dev;
- soc_codec->pcm_devs = 0; /*pcm device num index*/
- soc_codec->pop_time = 2;
- soc_codec->dai[0].codec = soc_codec;
-
- soc_codec->reg_cache_size = sizeof(soc_cs42l52_reg_default);
-
- soc_codec->reg_cache = kmemdup(soc_cs42l52_reg_default, sizeof(soc_cs42l52_reg_default), GFP_KERNEL);
-
- info = (struct soc_codec_cs42l52 *)kmalloc(sizeof(struct soc_codec_cs42l52),GFP_KERNEL);
-
- if (info == NULL) {
- kfree(soc_codec);
- return -ENOMEM;
- }
-
- info->sysclk = SOC_CS42L52_DEFAULT_CLK;
- info->format = SOC_CS42L52_DEFAULT_FORMAT;
-
- soc_codec->private_data =(void*)info;
-
- printk(KERN_INFO"soc_cs42l52_setup1\n");
- if(!soc_codec->reg_cache)
- {
- SOCERR("%s: err out of memory\n", __FUNCTION__);
- ret = -ENOMEM;
- goto err;
- }
- if (pdata->init_platform_hw)
- pdata->init_platform_hw();
+ int i,ret;
- /*initialize codec*/
- for(i = 0; i < soc_codec->num_dai; i++) //while(1) //
+ SOCDBG("\n");
+ for(i = 0; i < soc_codec->num_dai; i++)
{
-
SOCINF("Cirrus CS42L52 codec , revision %d\n", ret & CHIP_REV_MASK);
+
/*set hp default volume*/
soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPA_VOL, DEFAULT_HP_VOL);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPB_VOL, DEFAULT_HP_VOL);
-
/*set spk default volume*/
soc_cs42l52_write(soc_codec, CODEC_CS42L52_SPKA_VOL, DEFAULT_SPK_VOL);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_SPKB_VOL, DEFAULT_SPK_VOL);
-
/*set output default powerstate*/
soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL3, 5);
-#ifdef CONFIG_MANUAL_CLK
+
+#ifdef AUTO_DETECT_DISABLE
soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL,
(soc_cs42l52_read(soc_codec, CODEC_CS42L52_CLK_CTL)
& ~CLK_CTL_AUTODECT_ENABLE));
(soc_cs42l52_read(soc_codec, CODEC_CS42L52_CLK_CTL)
|CLK_CTL_AUTODECT_ENABLE));
#endif
-
+
/*default output stream configure*/
soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1,
(soc_cs42l52_read(soc_codec, CODEC_CS42L52_PB_CTL1)
- | (PB_CTL1_HP_GAIN_07099 << PB_CTL1_HP_GAIN_SHIFT)));
+ | (PB_CTL1_HP_GAIN_06047 << PB_CTL1_HP_GAIN_SHIFT)));
soc_cs42l52_write(soc_codec, CODEC_CS42L52_MISC_CTL,
(soc_cs42l52_read(soc_codec, CODEC_CS42L52_MISC_CTL))
| (MISC_CTL_DEEMPH | MISC_CTL_DIGZC | MISC_CTL_DIGSFT));
-
- /*default input stream configure*/
- //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_A, info->adc_sel1);
- //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_A, 0<<6); //20110706
-
- //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_B, info->adc_sel2);
- //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_B, 1<<7); //20110706
soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICA_CTL,
(soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICA_CTL)
| 0<<6));/*pre-amplifer 16db*/
soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICB_CTL,
- (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICB_CTL)
- | 0<<6));
-#if 0 //20110706, commented out, for audio recording commit
- /*default input stream path configure*/
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_ANALOG_HPF_CTL,
-// (soc_cs42l52_read(soc_codec, CODEC_CS42L52_ANALOG_HPF_CTL)
-// | HPF_CTL_ANLGSFTB | HPF_CTL_ANLGSFTA));
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAA_CTL, PGAX_CTL_VOL_6DB);
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAB_CTL, PGAX_CTL_VOL_6DB); /*PGA volume*/
-
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCA_VOL, ADCX_VOL_12DB);
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCB_VOL, ADCX_VOL_12DB); /*ADC volume*/
-
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_ALC_CTL,
-// (ALC_CTL_ALCB_ENABLE | ALC_CTL_ALCA_ENABLE)); /*enable ALC*/
-
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_ALC_THRESHOLD,
-// ((ALC_RATE_0DB << ALC_MAX_RATE_SHIFT)
-// | (ALC_RATE_3DB << ALC_MIN_RATE_SHIFT)));/*ALC max and min threshold*/
-
-
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_NOISE_GATE_CTL,
-// (NG_ENABLE | (NG_MIN_70DB << NG_THRESHOLD_SHIFT)
-// | (NG_DELAY_100MS << NG_DELAY_SHIFT))); /*Noise Gate enable*/
-
-// soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_VOL, BEEP_VOL_12DB);
-
-
- //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCA_MIXER_VOL, 0x80 | ADC_MIXER_VOL_12DB);
- //soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADCB_MIXER_VOL, 0x80 | ADC_MIXER_VOL_12DB);
-#endif
+ (soc_cs42l52_read(soc_codec, CODEC_CS42L52_MICB_CTL)
+ | 0<<6));/*pre-amplifer 16db*/
- // add by koffu
soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL2, 0x00);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_A, 0x90);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_PGA_B, 0x90);
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICA_CTL, 0x2c); //za yin contrl mic volume by koffu
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICA_CTL, 0x2c);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_MICB_CTL, 0x2c);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAA_CTL, 0x00); //0dB PGA
soc_cs42l52_write(soc_codec, CODEC_CS42L52_PGAB_CTL, 0x00); //0dB PGA
soc_cs42l52_write(soc_codec, CODEC_CS42L52_ADC_HPF_FREQ, 0x0F); //enable 464Hz HPF
-//for speaker
-
-
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x12); //contrl spekers volume by koffu
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x12);
+ //soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x12);
+ //soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x12);
-
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPA_VOL, 0xe0); //contrl spekers volume by koffu
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPB_VOL, 0xe0);
+ //soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPA_VOL, 0xc0);
+ //soc_cs42l52_write(soc_codec, CODEC_CS42L52_HPB_VOL, 0xc0);
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X07); //enab
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X07);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_TONE_CTL, 0X8f);
-//for headphone
-/* soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x00); //contrl spekers volume by koffu
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x00);
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X00); //enab
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_TONE_CTL, 0X00);
-*/
-
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL1, 0x00); // init by you
+ /*
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERA_VOL, 0x00);
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_MASTERB_VOL, 0x00);
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_BEEP_TONE_CTL, 0X00);
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_TONE_CTL, 0X00);
+ */
}
- soc_cs42l52_dai.dev = &i2c->dev;
- cs42l52_codec = soc_codec;
-
- ret = snd_soc_register_codec(soc_codec);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
- goto err;
- }
-
- INIT_DELAYED_WORK(&soc_codec->delayed_work, soc_cs42l52_work);
+ return;
+}
- ret = snd_soc_register_dai(&soc_cs42l52_dai);
- if (ret != 0) {
- dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
- goto err_codec;
- }
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_work
+ * Purpose : This function is to power on bias.
+ *
+ *----------------------------------------------------------------------------
+ */
+static void soc_cs42l52_work(struct work_struct *work)
+{
+ struct snd_soc_codec *codec =
+ container_of(work, struct snd_soc_codec, delayed_work.work);
- return ret;
+ soc_cs42l52_set_bias_level(codec, codec->bias_level);
-err_codec:
- snd_soc_unregister_codec(soc_codec);
-err:
- kfree(cs42l52_codec);
- cs42l52_codec = NULL;
- return ret;
+ return;
}
-static int cs42l52_i2c_remove(struct i2c_client *client)
-{
-
- snd_soc_unregister_dai(&soc_cs42l52_dai);
- snd_soc_unregister_codec(cs42l52_codec);
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_trigger
+ * Purpose : This function is to respond to trigger.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int soc_cs42l52_trigger(struct snd_pcm_substream *substream,
+ int status,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_link *machine = rtd->dai;
+ struct snd_soc_dai *codec_dai = machine->codec_dai;
- soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+ SOCDBG ("substream->stream:%s status:%d\n",
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE", status);
- soc_cs42l52_dai.dev = NULL;
- if(cs42l52_codec->reg_cache)
- kfree(cs42l52_codec->reg_cache);
- if(cs42l52_codec->private_data)
- kfree(cs42l52_codec->private_data);
- kfree(cs42l52_codec);
- cs42l52_codec = NULL;
+ if(status == 1 || status == 0){
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK){
+ codec_dai->playback.active = status;
+ }else{
+ codec_dai->capture.active = status;
+ }
+ }
return 0;
}
-static const struct i2c_device_id cs42l52_i2c_id[] = {
- { "cs42l52", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, cs42l52_i2c_id);
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_hw_params
+ * Purpose : This function is to set the hardware parameters for CS42L52.
+ * The functions set the sample rate and audio serial data word
+ * length.
+ *
+ *----------------------------------------------------------------------------
+ */
+static int soc_cs42l52_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *soc_dev = rtd->socdev;
+ struct snd_soc_codec *soc_codec = soc_dev->card->codec;
+ struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
-static struct i2c_driver cs42l52_i2c_drv = {
- .driver = {
- .name = "CS42L52",
- .owner = THIS_MODULE,
- },
- .probe = cs42l52_i2c_probe,
- .remove = cs42l52_i2c_remove,
- .id_table = cs42l52_i2c_id,
+ u32 clk = 0;
+ int ret = 0;
+ int index = soc_cs42l52_get_clk(info->sysclk, params_rate(params));
-};
+ SOCDBG("----------sysclk=%d,rate=%d\n",info->sysclk, params_rate(params));
+ if(index >= 0)
+ {
+ info->sysclk = clk_map_table[index].mclk;
+ clk |= (clk_map_table[index].speed << CLK_CTL_SPEED_SHIFT) |
+ (clk_map_table[index].group << CLK_CTL_32K_SR_SHIFT) |
+ (clk_map_table[index].videoclk << CLK_CTL_27M_MCLK_SHIFT) |
+ (clk_map_table[index].ratio << CLK_CTL_RATIO_SHIFT) |
+ clk_map_table[index].mclkdiv2;
+
+#ifdef AUTO_DETECT_DISABLE
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, clk);
+#else
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, 0xa0);
#endif
-#if 1
-static int soc_cs42l52_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
- int div_id, int div)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- u16 reg;
-
- printk("soc_cs42l52_set_dai_clkdiv\n");
- return 0;
+ }
+ else{
+ SOCDBG("can't find out right mclk\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
}
-#endif
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_set_sysclk
+ * Purpose : This function is to set the DAI system clock
+ *
+ *----------------------------------------------------------------------------
+ */
static int soc_cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, u_int freq, int dir)
{
struct snd_soc_codec *soc_codec = codec_dai->codec;
struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
- if((freq >= SOC_CS42L52_MIN_CLK) && (freq <= SOC_CS42L52_MAX_CLK))
- {
+ SOCDBG("sysclk=%dHz,freq=%d\n", info->sysclk,freq);
+
+ if((freq >= SOC_CS42L52_MIN_CLK) && (freq <= SOC_CS42L52_MAX_CLK)){
info->sysclk = freq;
- SOCDBG("sysclk %d\n", info->sysclk);
+ SOCDBG("info->sysclk set to %d Hz\n", info->sysclk);
}
else{
- SOCDBG("invalid paramter\n");
+ printk("invalid paramter\n");
ret = -EINVAL;
}
return ret;
}
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_set_fmt
+ * Purpose : This function is to set the DAI format
+ *
+ *----------------------------------------------------------------------------
+ */
static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai,
u_int fmt)
{
u8 iface = 0;
/* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
SOCDBG("codec dai fmt master\n");
iface = IFACE_CTL1_MASTER;
}
/* interface format */
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
-
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
SOCDBG("codec dai fmt i2s\n");
iface |= (IFACE_CTL1_ADC_FMT_I2S | IFACE_CTL1_DAC_FMT_I2S);
}
/* clock inversion */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) { /*tonyliu*/
-
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
SOCDBG("codec dai fmt normal sclk\n");
break;
info->format = iface;
done:
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_IFACE_CTL1, info->format); //20110706
- return ret;
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_IFACE_CTL1, info->format);
+ return ret;
}
+/*
+ *----------------------------------------------------------------------------
+ * Function : soc_cs42l52_digital_mute
+ * Purpose : This function is to mute DAC or not
+ *
+ *----------------------------------------------------------------------------
+ */
static int soc_cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
{
-
struct snd_soc_codec *soc_codec = dai->codec;
u8 mute_val = soc_cs42l52_read(soc_codec, CODEC_CS42L52_PB_CTL1) & PB_CTL1_MUTE_MASK;
- if(mute)
- {
- printk(KERN_INFO"soc_cs42l52_digital_mute=1 %d\n",mute_val);
+ SOCDBG("%d\n",mute);
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val | PB_CTL1_MSTB_MUTE | PB_CTL1_MSTA_MUTE);
+ if(mute) {
+ soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val \
+ | PB_CTL1_MSTB_MUTE | PB_CTL1_MSTA_MUTE);
}
- else{
- printk(KERN_INFO"soc_cs42l52_digital_mute=0 %d\n",mute_val);
+ else {
soc_cs42l52_write(soc_codec, CODEC_CS42L52_PB_CTL1, mute_val );
}
return 0;
}
-struct soc_cs42l52_clk_para {
- u32 mclk;
- u32 rate;
- u8 speed;
- u8 group;
- u8 videoclk;
- u8 ratio;
- u8 mclkdiv2;
+static struct snd_soc_dai_ops cs42l52_ops = {
+ .hw_params = soc_cs42l52_hw_params,
+ .set_sysclk = soc_cs42l52_set_sysclk,
+ .set_fmt = soc_cs42l52_set_fmt,
+ .trigger = soc_cs42l52_trigger,
+ .digital_mute = soc_cs42l52_digital_mute,
};
+/*
+ *----------------------------------------------------------------------------
+ * @struct soc_cs42l52_dai |
+ * It is SoC Codec DAI structure which has DAI capabilities viz.,
+ * playback and capture, DAI runtime information viz. state of DAI
+ * and pop wait state, and DAI private data.
+ * The AIC3111 rates ranges from 8k to 192k
+ * The PCM bit format supported are 16, 20, 24 and 32 bits
+ *----------------------------------------------------------------------------
+ */
+struct snd_soc_dai soc_cs42l52_dai = {
+ .name = SOC_CS42L52_NAME,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
+ .rates = SOC_CS42L52_RATES,
+ .formats = SOC_CS42L52_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = SOC_CS42L52_DEFAULT_MAX_CHANS,
+ .rates = SOC_CS42L52_RATES,
+ .formats = SOC_CS42L52_FORMATS,
+ },
+ .ops = &cs42l52_ops,
+};
+EXPORT_SYMBOL_GPL(soc_cs42l52_dai);
-static const struct soc_cs42l52_clk_para clk_map_table[] = {
- /*8k*/
- {12288000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {18432000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {12000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
- {24000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
- {27000000, 8000, CLK_CTL_S_QS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0}, /*4*/
-
- /*11.025k*/
- {11289600, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {16934400, 11025, CLK_CTL_S_QS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-
- /*16k*/
- {12288000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {18432000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {12000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},/*9*/
- {24000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
- {27000000, 16000, CLK_CTL_S_HS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
- /*22.05k*/
- {11289600, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {16934400, 22050, CLK_CTL_S_HS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
-
- /* 32k */
- {12288000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*14*/
- {18432000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {12000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
- {24000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
- {27000000, 32000, CLK_CTL_S_SS_MODE, CLK_CTL_32K_SR, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 0},
+#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+static int cs42l52_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ struct snd_soc_codec *soc_codec;
+ struct soc_codec_cs42l52 * info;
+ struct cs42l52_platform_data *pdata = i2c->dev.platform_data;
+ int ret = 0;
- /* 44.1k */
- {11289600, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*19*/
- {16934400, 44100, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ soc_codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (soc_codec == NULL)
+ return -ENOMEM;
- /* 48k */
- {12288000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {18432000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {12000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
- {24000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},/*24*/
- {27000000, 48000, CLK_CTL_S_SS_MODE, CLK_CTL_NOT_32K, CLK_CTL_27M_MCLK, CLK_CTL_RATIO_125, 1},
+ soc_codec->name = SOC_CS42L52_NAME;
+ soc_codec->owner = THIS_MODULE;
+ soc_codec->write = soc_cs42l52_write;
+ soc_codec->read = soc_cs42l52_read;
+ soc_codec->hw_write = (hw_write_t)i2c_master_send;
+ mutex_init(&soc_codec->mutex);
+ INIT_LIST_HEAD(&soc_codec->dapm_widgets);
+ INIT_LIST_HEAD(&soc_codec->dapm_paths);
+
+ soc_codec->set_bias_level = soc_cs42l52_set_bias_level;
+ soc_codec->dai = &soc_cs42l52_dai;
+ soc_codec->dai->playback.channels_max = 2;
+ soc_codec->dai->capture.channels_max = 2;
+ soc_codec->num_dai = 1;
+ soc_codec->control_data = i2c;
+ soc_codec->dev = &i2c->dev;
+ soc_codec->pcm_devs = 0;
+ soc_codec->pop_time = 2;
+ soc_codec->dai[0].codec = soc_codec;
- /* 88.2k */
- {11289600, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {16934400, 88200, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
+ soc_codec->reg_cache_size = sizeof(soc_cs42l52_reg_default);
- /* 96k */
- {12288000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},
- {18432000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_128, 0},/*29*/
- {12000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 0},
- {24000000, 96000, CLK_CTL_S_DS_MODE, CLK_CTL_NOT_32K, CLK_CTL_NOT_27M, CLK_CTL_RATIO_125, 1},
-};
+ soc_codec->reg_cache = kmemdup(soc_cs42l52_reg_default, sizeof(soc_cs42l52_reg_default), GFP_KERNEL);
-static int soc_cs42l52_get_clk(int mclk, int rate)
-{
+ info = (struct soc_codec_cs42l52 *)kmalloc(sizeof(struct soc_codec_cs42l52),GFP_KERNEL);
+ if (info == NULL) {
+ kfree(soc_codec);
+ return -ENOMEM;
+ }
- int i , ret = 0;
- u_int mclk1, mclk2 = 0;
+ info->sysclk = SOC_CS42L52_DEFAULT_CLK;
+ info->format = SOC_CS42L52_DEFAULT_FORMAT;
- for(i = 0; i < ARRAY_SIZE(clk_map_table); i++)
- {
- if(clk_map_table[i].rate == rate)
- {
- mclk1 = clk_map_table[i].mclk;
- {
- if(abs(mclk - mclk1) < abs(mclk - mclk2))
- {
- mclk2 = mclk1;
- ret = i;
- }
- }
- }
+ soc_codec->private_data =(void*)info;
+ if(!soc_codec->reg_cache) {
+ SOCERR("%s: err out of memory\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto err;
}
- return ret < ARRAY_SIZE(clk_map_table) ? ret : -EINVAL;
-}
-
-static int soc_cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-{
- int ret = 0;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_device *soc_dev = rtd->socdev;
- struct snd_soc_codec *soc_codec = soc_dev->card->codec;
- struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*)soc_codec->private_data;
+ if (pdata->init_platform_hw)
+ pdata->init_platform_hw();
- u32 clk = 0;
- int index = soc_cs42l52_get_clk(info->sysclk, params_rate(params));
+ /*initialize codec*/
+ cs42l52_power_init(soc_codec);
- if(index >= 0)
- {
- info->sysclk = clk_map_table[index].mclk;
- clk |= (clk_map_table[index].speed << CLK_CTL_SPEED_SHIFT) |
- (clk_map_table[index].group << CLK_CTL_32K_SR_SHIFT) |
- (clk_map_table[index].videoclk << CLK_CTL_27M_MCLK_SHIFT) |
- (clk_map_table[index].ratio << CLK_CTL_RATIO_SHIFT) |
- clk_map_table[index].mclkdiv2;
-#ifdef CONFIG_MANUAL_CLK
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, clk);
-#else
- soc_cs42l52_write(soc_codec, CODEC_CS42L52_CLK_CTL, 0xa0);
-#endif
+ INIT_DELAYED_WORK(&soc_codec->delayed_work, soc_cs42l52_work);
+ soc_cs42l52_dai.dev = &i2c->dev;
+ cs42l52_codec = soc_codec;
+ ret = snd_soc_register_codec(soc_codec);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+ goto err;
}
- else{
- SOCDBG("can't find out right mclk\n");
- ret = -EINVAL;
+
+ ret = snd_soc_register_dai(&soc_cs42l52_dai);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
+ goto err_codec;
}
return ret;
+
+err_codec:
+ snd_soc_unregister_codec(soc_codec);
+err:
+ kfree(cs42l52_codec);
+ cs42l52_codec = NULL;
+ return ret;
}
-int soc_cs42l52_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+static int cs42l52_i2c_remove(struct i2c_client *client)
{
- u8 pwctl1 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL1) & 0x9f;
- u8 pwctl2 = soc_cs42l52_read(codec, CODEC_CS42L52_PWCTL2) & 0x07;
+ snd_soc_unregister_dai(&soc_cs42l52_dai);
+ snd_soc_unregister_codec(cs42l52_codec);
- switch (level) {
- case SND_SOC_BIAS_ON: /* full On */
- SOCDBG("full on\n");
- break;
- case SND_SOC_BIAS_PREPARE: /* partial On */
- SOCDBG("partial on\n");
- pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
- soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
- break;
- case SND_SOC_BIAS_STANDBY: /* Off, with power */
- SOCDBG("off with power\n");
- pwctl1 &= ~(PWCTL1_PDN_CHRG | PWCTL1_PDN_CODEC);
- soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1);
- break;
- case SND_SOC_BIAS_OFF: /* Off, without power */
- SOCDBG("off without power\n");
-// soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL1, pwctl1 | 0x9f);
-// soc_cs42l52_write(codec, CODEC_CS42L52_PWCTL2, pwctl2 | 0x07);
- break;
- }
- codec->bias_level = level;
- return 0;
+ soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+
+ soc_cs42l52_dai.dev = NULL;
+ if(cs42l52_codec->reg_cache)
+ kfree(cs42l52_codec->reg_cache);
+ if(cs42l52_codec->private_data)
+ kfree(cs42l52_codec->private_data);
+ kfree(cs42l52_codec);
+ cs42l52_codec = NULL;
+
+ return 0;
}
-static void soc_cs42l52_work(struct work_struct *work)
+
+static int cs42l52_i2c_shutdown(struct i2c_client *client)
{
- struct snd_soc_codec *codec =
- container_of(work, struct snd_soc_codec, delayed_work.work);
-//added by koffu
- codec->bias_level = SND_SOC_BIAS_ON; //20110706
+ SOCDBG("i am here\n");
+ snd_soc_unregister_dai(&soc_cs42l52_dai);
+ snd_soc_unregister_codec(cs42l52_codec);
- soc_cs42l52_set_bias_level(codec, codec->bias_level);
+ soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+
+ soc_cs42l52_dai.dev = NULL;
+ if(cs42l52_codec->reg_cache)
+ kfree(cs42l52_codec->reg_cache);
+ if(cs42l52_codec->private_data)
+ kfree(cs42l52_codec->private_data);
+ kfree(cs42l52_codec);
+ cs42l52_codec = NULL;
+
+ return 0;
}
+static const struct i2c_device_id cs42l52_i2c_id[] = {
+ { "cs42l52", 0 },
+};
+MODULE_DEVICE_TABLE(i2c, cs42l52_i2c_id);
+
+static struct i2c_driver cs42l52_i2c_drv = {
+ .driver = {
+ .name = "CS42L52",
+ .owner = THIS_MODULE,
+ },
+ .probe = cs42l52_i2c_probe,
+ .remove = cs42l52_i2c_remove,
+ .shutdown = cs42l52_i2c_shutdown,
+ .id_table = cs42l52_i2c_id,
+};
+
+#endif
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static int soc_cs42l52_suspend(struct early_suspend *h)
+{
+
+ soc_cs42l52_write(cs42l52_codec, CODEC_CS42L52_PWCTL1, PWCTL1_PDN_CODEC);
+ soc_cs42l52_set_bias_level(cs42l52_codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int soc_cs42l52_resume(struct early_suspend *h)
+{
+ struct snd_soc_codec *soc_codec = cs42l52_codec;
+ struct soc_codec_cs42l52 *info = (struct soc_codec_cs42l52*) soc_codec->private_data;
+ int i, reg;
+ u8 data[2];
+ u8 *reg_cache = (u8*) soc_codec->reg_cache;
+ soc_codec->num_dai = 1;
+ /* Sync reg_cache with the hardware */
+ for(i = 0; i < soc_codec->num_dai; i++) {
+
+ for(reg = 0; reg < ARRAY_SIZE(soc_cs42l52_reg_default); reg++) {
+ data[0] = reg;
+ data[1] = reg_cache[reg];
+ if(soc_codec->hw_write(soc_codec->control_data, data, 2) != 2)
+ break;
+ }
+ }
+
+ soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_STANDBY);
+
+ /*charge cs42l52 codec*/
+ if(soc_codec->suspend_bias_level == SND_SOC_BIAS_ON)
+ {
+ soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_PREPARE);
+ soc_codec->bias_level = SND_SOC_BIAS_ON;
+ schedule_delayed_work(&soc_codec->delayed_work, msecs_to_jiffies(1000));
+ }
+ return 0;
+
+}
+#else
static int soc_cs42l52_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *soc_dev = (struct snd_soc_device*)platform_get_drvdata(pdev);
soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL1, PWCTL1_PDN_CODEC);
soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_OFF);
-
return 0;
}
soc_codec->bias_level = SND_SOC_BIAS_ON;
schedule_delayed_work(&soc_codec->delayed_work, msecs_to_jiffies(1000));
}
-
return 0;
}
-
+#endif
static int soc_cs42l52_probe(struct platform_device *pdev)
{
struct snd_soc_device *soc_dev = platform_get_drvdata(pdev);
soc_dev->card->codec = cs42l52_codec;
soc_codec = cs42l52_codec;
-
- ret = snd_soc_new_pcms(soc_dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+
+ ret = snd_soc_new_pcms(soc_dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if(ret)
{
SOCERR("%s: add new pcms failed\n",__FUNCTION__);
goto pcm_err;
}
- /*init done*/
soc_cs42l52_add_controls(soc_codec);
-
soc_cs42l52_add_widgets(soc_codec);
ret = snd_soc_init_card(soc_dev);
goto card_err;
}
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ cs42l52_early_suspend.suspend =soc_cs42l52_suspend;
+ cs42l52_early_suspend.resume =soc_cs42l52_resume;// cs42l52_early_suspend.level = 0x2;
+ register_early_suspend(&cs42l52_early_suspend);
+#endif
return ret;
card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
-
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&cs42l52_early_suspend);
+#endif
return 0;
}
struct snd_soc_codec_device soc_codec_dev_cs42l52 = {
.probe = soc_cs42l52_probe,
.remove = soc_cs42l52_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = soc_cs42l52_suspend,
.resume = soc_cs42l52_resume,
+#endif
};
EXPORT_SYMBOL_GPL(soc_codec_dev_cs42l52);
static int __init cs42l52_modinit(void)
{
- printk(KERN_INFO"cs42l52_i2c_probe\n");
return i2c_add_driver(&cs42l52_i2c_drv);
}
module_init(cs42l52_modinit);
static void __exit cs42l52_exit(void)
{
- printk(KERN_INFO"cs42l52_i2c_probe\n");
i2c_del_driver(&cs42l52_i2c_drv);
}
module_exit(cs42l52_exit);
+
+
MODULE_DESCRIPTION("ALSA SoC CS42L52 Codec");
MODULE_AUTHOR("Bo Liu, Bo.Liu@cirrus.com, www.cirrus.com");
MODULE_LICENSE("GPL");
+
+
+
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+static int proc_cs42l52_show (struct seq_file *s, void *v)
+{
+ struct snd_soc_codec *codec = cs42l52_codec;
+ int reg;
+
+ seq_printf (s, " cs42l52 registers:\n");
+ for (reg = 0; reg < 53; reg++) {
+ if (reg%10 == 0)
+ seq_printf (s, "\n ");
+ seq_printf (s, "0x%02x ", soc_cs42l52_read(codec, reg));
+ }
+ seq_printf (s, "\n\n");
+
+#if 0//for check cache
+ u8 *cache = codec->reg_cache;
+ seq_printf (s, " cache:\n");
+ for (reg = 0; reg < 53; reg++) {
+ if (reg%10 == 0)
+ seq_printf (s, "\n ");
+ seq_printf (s, "0x%02x ", cache[reg]);
+ }
+ seq_printf (s, "\n\n");
+#endif
+
+ return 0;
+}
+
+static int proc_cs42l52_open (struct inode *inode, struct file *file)
+{
+ return single_open (file, proc_cs42l52_show, NULL);
+}
+
+static const struct file_operations proc_cs42l52_fops = {
+ .open = proc_cs42l52_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init codec_proc_init (void)
+{
+ proc_create ("cs42l52", 0, NULL, &proc_cs42l52_fops);
+ return 0;
+}
+late_initcall (codec_proc_init);
+#endif /* CONFIG_PROC_FS */