From 20c075b8c2e8cbc77aded7adbb02bd93c19095af Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E8=94=A1=E6=9E=AB?= Date: Tue, 26 Jul 2011 11:07:48 +0800 Subject: [PATCH] newton:update cs42l52 driver --- sound/soc/codecs/cs42l52.c | 1137 +++++++++++++++++---------------- sound/soc/rk29/rk29_cs42l52.c | 123 ++-- 2 files changed, 677 insertions(+), 583 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 36c4cc926535..cf736ec14a1b 100755 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -32,37 +32,43 @@ #include #include -#include -#include -#include +#include +#include + +#include #include "cs42l52.h" #include + //#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 +static struct early_suspend cs42l52_early_suspend; +#endif /** * snd_soc_get_volsw - single mixer get callback @@ -105,6 +111,7 @@ int snd_soc_cs42l5x_get_volsw(struct snd_kcontrol *kcontrol, 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; @@ -247,7 +254,6 @@ int snd_soc_cs42l5x_put_volsw_2r(struct snd_kcontrol *kcontrol, /* * CS42L52 register default value */ - static const u8 soc_cs42l52_reg_default[] = { 0x00, 0xE0, 0x01, 0x07, 0x05, /*4*/ 0xa0, 0x00, 0x00, 0x81, /*8*/ @@ -290,8 +296,8 @@ static int soc_cs42l52_write(struct snd_soc_codec *codec, 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) { @@ -315,7 +321,6 @@ static int soc_cs42l52_write(struct snd_soc_codec *codec, 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); @@ -328,69 +333,99 @@ static int soc_cs42l52_write(struct snd_soc_codec *codec, 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"}; @@ -530,7 +565,8 @@ static int soc_cs42l52_add_controls(struct snd_soc_codec *codec) 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"); @@ -574,11 +610,12 @@ static const struct snd_kcontrol_new cs42l52_hpb_mux = 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), @@ -587,7 +624,7 @@ static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = { 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), @@ -612,7 +649,7 @@ static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = { /* 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), @@ -620,11 +657,11 @@ static const struct snd_soc_dapm_widget soc_cs42l52_dapm_widgets[] = { 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"), @@ -650,54 +687,54 @@ static const struct snd_soc_dapm_route soc_cs42l52_audio_map[] = { {"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"}, @@ -705,7 +742,7 @@ static const struct snd_soc_dapm_route soc_cs42l52_audio_map[] = { {"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"}, @@ -713,14 +750,13 @@ static const struct snd_soc_dapm_route soc_cs42l52_audio_map[] = { {"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) @@ -739,171 +775,79 @@ 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)); @@ -912,172 +856,155 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id (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) { @@ -1085,18 +1012,26 @@ static int soc_cs42l52_set_sysclk(struct snd_soc_dai *codec_dai, 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) { @@ -1106,8 +1041,7 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai, 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; @@ -1122,8 +1056,7 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai, } /* 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); @@ -1151,8 +1084,7 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai, } /* 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; @@ -1172,192 +1104,257 @@ static int soc_cs42l52_set_fmt(struct snd_soc_dai *codec_dai, 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); @@ -1365,7 +1362,6 @@ static int soc_cs42l52_suspend(struct platform_device *pdev, pm_message_t state) soc_cs42l52_write(soc_codec, CODEC_CS42L52_PWCTL1, PWCTL1_PDN_CODEC); soc_cs42l52_set_bias_level(soc_codec, SND_SOC_BIAS_OFF); - return 0; } @@ -1398,11 +1394,10 @@ static int soc_cs42l52_resume(struct platform_device *pdev) 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); @@ -1416,17 +1411,15 @@ static int soc_cs42l52_probe(struct platform_device *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); @@ -1439,6 +1432,11 @@ static int soc_cs42l52_probe(struct platform_device *pdev) 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: @@ -1455,33 +1453,90 @@ static int soc_cs42l52_remove(struct platform_device *pdev) 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 +#include +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 */ diff --git a/sound/soc/rk29/rk29_cs42l52.c b/sound/soc/rk29/rk29_cs42l52.c index d4c92cbf90bd..29b9b249360e 100755 --- a/sound/soc/rk29/rk29_cs42l52.c +++ b/sound/soc/rk29/rk29_cs42l52.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -24,12 +25,13 @@ #include "rk29_pcm.h" #include "rk29_i2s.h" -#if 0 +#if 1 #define DBG(x...) printk(KERN_INFO x) #else #define DBG(x...) #endif + static int rk29_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -38,6 +40,8 @@ static int rk29_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; unsigned int pll_out = 0; unsigned int lrclk = 0; + int div_bclk,div_mclk; + struct clk *general_pll; int ret; DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); @@ -50,34 +54,33 @@ static int rk29_hw_params(struct snd_pcm_substream *substream, DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); } else - { - - /* set codec DAI configuration */ - #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - #endif - #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); - #endif - if (ret < 0) - return ret; - - /* set cpu DAI configuration */ - #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); - #endif - #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); - #endif - if (ret < 0) - return ret; + { + /* set codec DAI configuration */ + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + #endif + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + #endif + if (ret < 0) + return ret; - } + /* set cpu DAI configuration */ + #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); + #endif + #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) + ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); + #endif + if (ret < 0) + return ret; + } + DBG("Enter:%s, rate=%d\n",__FUNCTION__,params_rate(params)); switch(params_rate(params)) { case 8000: @@ -93,23 +96,48 @@ static int rk29_hw_params(struct snd_pcm_substream *substream, pll_out = 11289600; break; default: - DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); + DBG("Enter:%s, Error rate=%d\n",__FUNCTION__,params_rate(params)); return -EINVAL; break; } - DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); + + //pll_out = 12000000; #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) - // - // + pll_out = 11289600; + snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0); + snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); #endif #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) - snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); - snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1); - snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3); + general_pll=clk_get(NULL, "general_pll"); + if(clk_get_rate(general_pll)>260000000) + { + div_bclk=(pll_out/4)/params_rate(params)-1; + //div_bclk= 63; + div_mclk= 3; + } + else if(clk_get_rate(general_pll)>130000000) + { + div_bclk=(pll_out/2)/params_rate(params)-1; + div_mclk=1; + } + else + { + pll_out=pll_out/4; + div_bclk=(pll_out)/params_rate(params)-1; + div_mclk=0; + } + DBG("func is%s,gpll=%ld,pll_out=%ld,div_mclk=%ld,div_bclk=%ld\n", + __FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk,div_bclk); + + //snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0); + snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk); + snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk); + DBG("Enter:%s, LRCK=%d\n",__FUNCTION__,(pll_out/4)/params_rate(params)); #endif - DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params)); + return 0; } @@ -140,20 +168,31 @@ static int rk29_cs42l52_init(struct snd_soc_codec *codec) int ret; DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - +#if 0 /* Add specific widgets */ snd_soc_dapm_new_controls(codec, cs42l52_dapm_widgets, ARRAY_SIZE(cs42l52_dapm_widgets)); + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); /* Set up specific audio path audio_mapnects */ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - snd_soc_dapm_nc_pin(codec, "HPA"); - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - snd_soc_dapm_nc_pin(codec, "HPB"); - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); +#endif + + snd_soc_dapm_nc_pin(codec, "INPUT1A"); + snd_soc_dapm_nc_pin(codec, "INPUT2A"); + + snd_soc_dapm_nc_pin(codec, "INPUT3A"); + snd_soc_dapm_nc_pin(codec, "INPUT4A"); + + snd_soc_dapm_nc_pin(codec, "INPUT1B"); + snd_soc_dapm_nc_pin(codec, "INPUT2B"); + snd_soc_dapm_nc_pin(codec, "INPUT3B"); + snd_soc_dapm_nc_pin(codec, "INPUT4B"); + snd_soc_dapm_nc_pin(codec, "MICB"); + snd_soc_dapm_sync(codec); - DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + return 0; } -- 2.34.1