From 54e61f5302754a5524740e5f422f2adc6fc2cedd Mon Sep 17 00:00:00 2001 From: hjc Date: Mon, 18 Mar 2013 10:57:42 +0800 Subject: [PATCH] rk3168_86v: add support codec es8323,tp goodix_82x --- arch/arm/configs/rk3168_86v_codec_defconfig | 6 +- arch/arm/mach-rk30/board-rk3168-86v.c | 102 +- drivers/input/touchscreen/goodix_touch_82x.c | 2 +- sound/soc/codecs/Kconfig | 2 + sound/soc/codecs/Makefile | 1 + sound/soc/codecs/es8323.c | 1666 ++++++++++++++++++ sound/soc/codecs/es8323.h | 157 ++ sound/soc/rk29/Kconfig | 12 +- sound/soc/rk29/Makefile | 2 + sound/soc/rk29/rk29_es8323.c | 243 +++ 10 files changed, 2187 insertions(+), 6 deletions(-) create mode 100755 sound/soc/codecs/es8323.c create mode 100755 sound/soc/codecs/es8323.h create mode 100755 sound/soc/rk29/rk29_es8323.c diff --git a/arch/arm/configs/rk3168_86v_codec_defconfig b/arch/arm/configs/rk3168_86v_codec_defconfig index 29895499ceab..101527a88ecc 100644 --- a/arch/arm/configs/rk3168_86v_codec_defconfig +++ b/arch/arm/configs/rk3168_86v_codec_defconfig @@ -230,7 +230,7 @@ CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_TABLET_USB_WACOM=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_86V_GT811_IIC=y +CONFIG_TOUCHSCREEN_GT82X_IIC=y CONFIG_INPUT_MISC=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y @@ -291,7 +291,7 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_DISPLAY_SUPPORT=y -CONFIG_LCD_RK3168_86V=y +CONFIG_LCD_RK3168_AUO_A080SN03=y CONFIG_FB_ROCKCHIP=y CONFIG_ONE_LCDC_DUAL_OUTPUT_INF=y CONFIG_LCDC_RK3066B=y @@ -309,7 +309,7 @@ CONFIG_SND_SOC=y CONFIG_SND_RK29_SOC=y CONFIG_SND_RK29_SOC_I2S_2CH=y CONFIG_SND_I2S_DMA_EVENT_STATIC=y -CONFIG_SND_RK29_SOC_RT5631=y +CONFIG_SND_RK29_SOC_ES8323=y CONFIG_SND_RK29_CODEC_SOC_SLAVE=y CONFIG_UHID=y CONFIG_HID_A4TECH=y diff --git a/arch/arm/mach-rk30/board-rk3168-86v.c b/arch/arm/mach-rk30/board-rk3168-86v.c index 7811536f3ae0..09efd6781422 100755 --- a/arch/arm/mach-rk30/board-rk3168-86v.c +++ b/arch/arm/mach-rk30/board-rk3168-86v.c @@ -54,6 +54,10 @@ #include #endif +#ifdef CONFIG_TOUCHSCREEN_GT82X_IIC +#include +#endif + #if defined(CONFIG_RK_HDMI) #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" #endif @@ -196,6 +200,73 @@ static struct goodix_platform_data gt811_info = { }; #endif + +#ifdef CONFIG_TOUCHSCREEN_GT82X_IIC +#define TOUCH_ENABLE_PIN INVALID_GPIO +#define TOUCH_RESET_PIN RK30_PIN0_PB6//RK30_PIN4_PD0 +#define TOUCH_INT_PIN RK30_PIN1_PB7//RK30_PIN4_PC2 +int goodix_init_platform_hw(void) +{ + int ret; + + //rk30_mux_api_set(GPIO4D0_SMCDATA8_TRACEDATA8_NAME, GPIO4D_GPIO4D0); //hjc + //rk30_mux_api_set(GPIO4C2_SMCDATA2_TRACEDATA2_NAME, GPIO4C_GPIO4C2); //hjc + //printk("%s:0x%x,0x%x\n",__func__,rk30_mux_api_get(GPIO4D0_SMCDATA8_TRACEDATA8_NAME),rk30_mux_api_get(GPIO4C2_SMCDATA2_TRACEDATA2_NAME)); + if (TOUCH_ENABLE_PIN != INVALID_GPIO) { + ret = gpio_request(TOUCH_ENABLE_PIN, "goodix power pin"); + if (ret != 0) { + gpio_free(TOUCH_ENABLE_PIN); + printk("goodix power error\n"); + return -EIO; + } + gpio_direction_output(TOUCH_ENABLE_PIN, 0); + gpio_set_value(TOUCH_ENABLE_PIN, GPIO_LOW); + msleep(100); + } + + if (TOUCH_RESET_PIN != INVALID_GPIO) { + ret = gpio_request(TOUCH_RESET_PIN, "goodix reset pin"); + if (ret != 0) { + gpio_free(TOUCH_RESET_PIN); + printk("goodix gpio_request error\n"); + return -EIO; + } + gpio_direction_output(TOUCH_RESET_PIN, 0); + gpio_set_value(TOUCH_RESET_PIN, GPIO_LOW); + msleep(10); + gpio_set_value(TOUCH_RESET_PIN, GPIO_HIGH); + msleep(500); + } + return 0; +} +u8 ts82x_config_data[] = { + 0x65,0x00,0x04,0x00,0x03,0x00,0x0A,0x0D,0x1E,0xE7, + 0x32,0x03,0x08,0x10,0x48,0x42,0x42,0x20,0x00,0x01, + 0x60,0x60,0x4B,0x6E,0x0E,0x0D,0x0C,0x0B,0x0A,0x09, + 0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00,0x1D, + 0x1C,0x1B,0x1A,0x19,0x18,0x17,0x16,0x15,0x14,0x13, + 0x12,0x11,0x10,0x0F,0x50,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2B,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 +}; +static struct goodix_i2c_rmi_platform_data ts82x_pdata = { + .gpio_shutdown = TOUCH_ENABLE_PIN, + .gpio_irq = TOUCH_INT_PIN, + .gpio_reset = TOUCH_RESET_PIN, + .irq_edge = 1, /* 0:rising edge, 1:falling edge */ + + .ypol = 1, + .swap_xy = 1, + .xpol = 0, + .xmax = 800, + .ymax = 600, + .config_info_len =ARRAY_SIZE(ts82x_config_data), + .config_info = ts82x_config_data, + .init_platform_hw= goodix_init_platform_hw, +}; +#endif + static struct spi_board_info board_spi_devices[] = { }; @@ -503,11 +574,18 @@ static int rk_fb_io_enable(void) #if defined(CONFIG_LCDC0_RK3066B) struct rk29fb_info lcdc0_screen_info = { +#if 0 .prop = EXTEND, //primary display device .io_init = NULL, .io_disable = NULL, .io_enable = NULL, .set_screen_info = NULL, +#endif + .prop = PRMRY, //primary display device + .io_init = rk_fb_io_init, + .io_disable = rk_fb_io_disable, + .io_enable = rk_fb_io_enable, + .set_screen_info = set_lcd_info, }; #endif @@ -1281,6 +1359,13 @@ static struct i2c_board_info __initdata i2c0_info[] = { .flags = 0, }, #endif +#if defined (CONFIG_SND_SOC_RT5616) + { + .type = "rt5616", + .addr = 0x1b, + .flags = 0, + }, +#endif }; #endif @@ -1697,6 +1782,15 @@ static struct i2c_board_info __initdata i2c2_info[] = { .platform_data = >811_info, }, #endif +#if defined(CONFIG_TOUCHSCREEN_GT82X_IIC) + { + .type = "Goodix-TS-82X", + .addr = 0x5D, + .flags = 0, + .irq = RK30_PIN1_PB7, + .platform_data = &ts82x_pdata, + }, +#endif }; #endif @@ -1738,7 +1832,13 @@ static struct i2c_board_info __initdata i2c4_info[] = { }, #endif #endif - +#if defined (CONFIG_SND_RK29_SOC_ES8323) + { + .type = "es8323",//"es8323", + .addr = 0x10, + .flags = 0, + }, +#endif }; #endif diff --git a/drivers/input/touchscreen/goodix_touch_82x.c b/drivers/input/touchscreen/goodix_touch_82x.c index 8a8d0e1a145b..8012a3db48e5 100755 --- a/drivers/input/touchscreen/goodix_touch_82x.c +++ b/drivers/input/touchscreen/goodix_touch_82x.c @@ -390,7 +390,7 @@ COORDINATE_POLL: Y_value = pdata->ymax - Y_value; input_report_abs(ts->input_dev, ABS_MT_POSITION_X, X_value); //can change x-y!!! - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, Y_value); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, 600-Y_value); //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,15); //input_mt_sync(ts->input_dev); i += 5; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 3e9f2f3ac99c..a88b11186b8b 100755 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -206,6 +206,8 @@ config SND_SOC_DFBMCS320 config SND_SOC_DMIC tristate +config SND_SOC_ES8323 + tristate config SND_SOC_MAX98088 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d74d071f2e1b..3f515b93e105 100755 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -18,6 +18,7 @@ snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o snd-soc-dfbmcs320-objs := dfbmcs320.o snd-soc-dmic-objs := dmic.o +snd-soc-es8323-objs := es8323.o snd-soc-l3-objs := l3.o snd-soc-max98088-objs := max98088.o snd-soc-max98095-objs := max98095.o diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c new file mode 100755 index 000000000000..dca2a8f5aa18 --- /dev/null +++ b/sound/soc/codecs/es8323.c @@ -0,0 +1,1666 @@ +/* + * es8323.c -- es8323 ALSA SoC audio driver + * + * Copyright 2009 Wolfson Microelectronics plc + * Copyright 2005 Openedhand Ltd. + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +//#include + +#include "es8323.h" + +#include +#include + +#if 0 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) do { } while (0) +#endif +#define alsa_dbg DBG + +#define RT5633_SPK_TIMER 0 //if enable this, MUST enable RT5633_EQ_FUNC_ENA and RT5633_EQ_FUNC_SEL==RT5633_EQ_FOR_MANUAL first! +#if (RT5633_SPK_TIMER == 1) +static struct timer_list spk_timer; +struct work_struct spk_work; +static bool last_is_spk = false; +//#define ES8323_HP_PIN RK30_PIN0_PC7 // need modify. +#endif +//#define SPK_CTL RK29_PIN6_PB7 +//#define SPK_CON RK29_PIN6_PB6 + #undef SPK_CTL +// #undef SPK_CON +#define SPK_CON RK30_PIN2_PD7 //RK30_PIN4_PC5 + +//#define SPK_CTL RK29_PIN6_PB6 +//#define EAR_CON_PIN RK29_PIN6_PB5 +#undef EAR_CON_PIN + +#ifndef es8323_DEF_VOL +#define es8323_DEF_VOL 0x1e +#endif + +static int es8323_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level); +/* + * es8323 register cache + * We can't read the es8323 register space when we + * are using 2 wire for device control, so we cache them instead. + */ +static u16 es8323_reg[] = { + 0x06, 0x1C, 0xC3, 0xFC, /* 0 *////0x0100 0x0180 + 0xC0, 0x00, 0x00, 0x7C, /* 4 */ + 0x80, 0x00, 0x00, 0x06, /* 8 */ + 0x00, 0x06, 0x30, 0x30, /* 12 */ + 0xC0, 0xC0, 0x38, 0xB0, /* 16 */ + 0x32, 0x06, 0x00, 0x00, /* 20 */ + 0x06, 0x30, 0xC0, 0xC0, /* 24 */ + 0x08, 0x06, 0x1F, 0xF7, /* 28 */ + 0xFD, 0xFF, 0x1F, 0xF7, /* 32 */ + 0xFD, 0xFF, 0x00, 0x38, /* 36 */ + 0x38, 0x38, 0x38, 0x38, /* 40 */ + 0x38, 0x00, 0x00, 0x00, /* 44 */ + 0x00, 0x00, 0x00, 0x00, /* 48 */ + 0x00, 0x00, 0x00, 0x00, /* 52 */ +}; + +/* codec private data */ +struct es8323_priv { + unsigned int sysclk; + enum snd_soc_control_type control_type; + struct snd_pcm_hw_constraint_list *sysclk_constraints; + int is_startup; // gModify.Add + int is_biason; +}; + +static unsigned int es8323_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg >= ARRAY_SIZE(es8323_reg)) + return -1; + return es8323_reg[reg]; +} + +static int es8323_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[2]; + int ret; + + BUG_ON(codec->volatile_register); + + data[0] = reg; + data[1] = value & 0x00ff; + + if (reg < ARRAY_SIZE(es8323_reg)) + es8323_reg[reg] = value; + ret = codec->hw_write(codec->control_data, data, 2); + if (ret == 2) + return 0; + if (ret < 0) + return ret; + else + return -EIO; +} + +//#define es8323_reset(c) snd_soc_write(c, es8323_RESET, 0) + static int es8323_reset(struct snd_soc_codec *codec) + { + snd_soc_write(codec, ES8323_CONTROL1, 0x80); + return snd_soc_write(codec, ES8323_CONTROL1, 0x00); + } +static int es8323_volatile_register( + struct snd_soc_codec *codec, unsigned int reg) +{ + if(reg<0x35) + { + return 1; + } + else + { + return 0; + } +} + +static int es8323_readable_register( + struct snd_soc_codec *codec, unsigned int reg) +{ + if(reg<0x35) + { + return 1; + } + else + { + return 0; + } +} + +/* + * es8323 Controls + */ +/* +static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"}; +static const struct soc_enum bass_boost = + SOC_ENUM_SINGLE(es8323_BASS, 7, 2, bass_boost_txt); + +static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; +static const struct soc_enum bass_filter = + SOC_ENUM_SINGLE(es8323_BASS, 6, 2, bass_filter_txt); + +static const char *treble_txt[] = {"8kHz", "4kHz"}; +static const struct soc_enum treble = + SOC_ENUM_SINGLE(es8323_TREBLE, 6, 2, treble_txt); + +static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"}; +static const struct soc_enum stereo_3d_lc = + SOC_ENUM_SINGLE(es8323_3D, 5, 2, stereo_3d_lc_txt); + +static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"}; +static const struct soc_enum stereo_3d_uc = + SOC_ENUM_SINGLE(es8323_3D, 6, 2, stereo_3d_uc_txt); + +static const char *stereo_3d_func_txt[] = {"Capture", "Playback"}; +static const struct soc_enum stereo_3d_func = + SOC_ENUM_SINGLE(es8323_3D, 7, 2, stereo_3d_func_txt); +*/ +static const char *stereo_3d_txt[] = {"No 3D ", "Level 1","Level 2","Level 3","Level 4","Level 5","Level 6","Level 7"}; +static const struct soc_enum stereo_3d = + SOC_ENUM_SINGLE(ES8323_DACCONTROL7, 2, 8, stereo_3d_txt); + +static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"}; +static const struct soc_enum alc_func = + SOC_ENUM_SINGLE(ES8323_ADCCONTROL10, 6, 4, alc_func_txt); + +static const char *ng_type_txt[] = {"Constant PGA Gain", + "Mute ADC Output"}; +static const struct soc_enum ng_type = + SOC_ENUM_SINGLE(ES8323_ADCCONTROL14, 1, 2, ng_type_txt); + +static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"}; +static const struct soc_enum deemph = + SOC_ENUM_SINGLE(ES8323_DACCONTROL6, 6, 4, deemph_txt); + +static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert", + "L + R Invert"}; +static const struct soc_enum adcpol = + SOC_ENUM_SINGLE(ES8323_ADCCONTROL6, 6, 4, adcpol_txt); + +static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); +static const DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 50, 1); +static const DECLARE_TLV_DB_SCALE(dac_tlv, -9600, 50, 1); +static const DECLARE_TLV_DB_SCALE(out_tlv, -4500, 150, 0); +static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); + +static const struct snd_kcontrol_new es8323_snd_controls[] = { +/* +SOC_ENUM("Bass Boost", bass_boost), +SOC_ENUM("Bass Filter", bass_filter), +SOC_SINGLE("Bass Volume", es8323_BASS, 0, 15, 1), + +SOC_SINGLE("Treble Volume", es8323_TREBLE, 0, 15, 0), +SOC_ENUM("Treble Cut-off", treble), + +SOC_SINGLE("3D Switch", es8323_3D, 0, 1, 0), +SOC_SINGLE("3D Volume", es8323_3D, 1, 15, 0), +SOC_ENUM("3D Lower Cut-off", stereo_3d_lc), +SOC_ENUM("3D Upper Cut-off", stereo_3d_uc), +SOC_ENUM("3D Mode", stereo_3d_func), +*/ +SOC_ENUM("3D Mode", stereo_3d), +SOC_SINGLE("ALC Capture Target Volume", ES8323_ADCCONTROL11, 4, 15, 0), +SOC_SINGLE("ALC Capture Max PGA", ES8323_ADCCONTROL10, 3, 7, 0), +SOC_SINGLE("ALC Capture Min PGA", ES8323_ADCCONTROL10, 0, 7, 0), +SOC_ENUM("ALC Capture Function", alc_func), +SOC_SINGLE("ALC Capture ZC Switch", ES8323_ADCCONTROL13, 6, 1, 0), +SOC_SINGLE("ALC Capture Hold Time", ES8323_ADCCONTROL11, 0, 15, 0), +SOC_SINGLE("ALC Capture Decay Time", ES8323_ADCCONTROL12, 4, 15, 0), +SOC_SINGLE("ALC Capture Attack Time", ES8323_ADCCONTROL12, 0, 15, 0), +SOC_SINGLE("ALC Capture NG Threshold", ES8323_ADCCONTROL14, 3, 31, 0), +SOC_ENUM("ALC Capture NG Type", ng_type), +SOC_SINGLE("ALC Capture NG Switch", ES8323_ADCCONTROL14, 0, 1, 0), + +SOC_SINGLE("ZC Timeout Switch", ES8323_ADCCONTROL13, 6, 1, 0), + +SOC_DOUBLE_R_TLV("Capture Digital Volume", ES8323_ADCCONTROL8, ES8323_ADCCONTROL9, + 0, 255, 1, adc_tlv), + +SOC_SINGLE("Capture Mute", ES8323_ADCCONTROL7, 2, 1, 0), + /* +SOC_DOUBLE_R_TLV("Capture Volume", es8323_LINVOL, es8323_RINVOL, + 0, 63, 0, pga_tlv), + */ +SOC_SINGLE_TLV("Left Channel Capture Volume", ES8323_ADCCONTROL1, 4, 15, 0, bypass_tlv), +SOC_SINGLE_TLV("Right Channel Capture Volume", ES8323_ADCCONTROL1, 0, 15, 0, bypass_tlv), + +//SOC_DOUBLE_R("Capture ZC Switch", es8323_LINVOL, es8323_RINVOL, 6, 1, 0), +//SOC_SINGLE("Capture Switch", ES8323_ADCPOWER, 4, 3, 1), + +SOC_ENUM("Playback De-emphasis", deemph), + +SOC_ENUM("Capture Polarity", adcpol), +//SOC_SINGLE("Playback 6dB Attenuate", es8323_ADCDAC, 7, 1, 0), +//SOC_SINGLE("Capture 6dB Attenuate", es8323_ADCDAC, 8, 1, 0), + +//SOC_DOUBLE_R_TLV("PCM Volume", ES8323_DACCONTROL4, ES8323_DACCONTROL5, 0, 255, 1, dac_tlv), + +SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", ES8323_DACCONTROL17, 3, 7, 1, bypass_tlv), +/* +SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", es8323_LOUTM2, 4, 7, 1, + bypass_tlv), +SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", es8323_ROUTM1, 4, 7, 1, + bypass_tlv), +*/ +SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", ES8323_DACCONTROL20, 3, 7, 1, + bypass_tlv), + +//SOC_DOUBLE_R("Output 1 Playback ZC Switch", es8323_LOUT1V,es8323_ROUT1V, 7, 1, 0), +SOC_DOUBLE_R_TLV("Output 1 Playback Volume", ES8323_DACCONTROL24, ES8323_DACCONTROL25, + 0, 64, 0, out_tlv), + +//SOC_DOUBLE_R("Output 2 Playback ZC Switch", es8323_LOUT2V,es8323_ROUT2V, 7, 1, 0), +SOC_DOUBLE_R_TLV("Output 2 Playback Volume", ES8323_DACCONTROL26, ES8323_DACCONTROL27, + 0, 64, 0, out_tlv), +}; + +/* + * DAPM Controls + */ +/* +static int es8323_lrc_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + u16 adctl2 = snd_soc_read(codec, es8323_ADCTL2); +*/ + /* Use the DAC to gate LRC if active, otherwise use ADC */ + /* + if (snd_soc_read(codec, es8323_PWR2) & 0x180) + adctl2 &= ~0x4; + else + adctl2 |= 0x4; + + DBG("Enter::%s----%d, adctl2 = %x\n",__FUNCTION__,__LINE__,adctl2); + + return snd_soc_write(codec, es8323_ADCTL2, adctl2); +} +*/ +static const char *es8323_line_texts[] = { + "Line 1", "Line 2", "PGA"}; + +static const unsigned int es8323_line_values[] = { + 0, 1, 3}; + +static const struct soc_enum es8323_lline_enum = + SOC_VALUE_ENUM_SINGLE(ES8323_DACCONTROL16, 3, 7, + ARRAY_SIZE(es8323_line_texts), + es8323_line_texts, + es8323_line_values); +static const struct snd_kcontrol_new es8323_left_line_controls = + SOC_DAPM_VALUE_ENUM("Route", es8323_lline_enum); + +static const struct soc_enum es8323_rline_enum = + SOC_VALUE_ENUM_SINGLE(ES8323_DACCONTROL16, 0, 7, + ARRAY_SIZE(es8323_line_texts), + es8323_line_texts, + es8323_line_values); +static const struct snd_kcontrol_new es8323_right_line_controls = + SOC_DAPM_VALUE_ENUM("Route", es8323_rline_enum); + +/* Left Mixer */ +static const struct snd_kcontrol_new es8323_left_mixer_controls[] = { + SOC_DAPM_SINGLE("Left Playback Switch", ES8323_DACCONTROL17, 7, 1, 0), + SOC_DAPM_SINGLE("Left Bypass Switch", ES8323_DACCONTROL17, 6, 1, 0), + //SOC_DAPM_SINGLE("Right Playback Switch", es8323_LOUTM2, 8, 1, 0), + //SOC_DAPM_SINGLE("Right Bypass Switch", es8323_LOUTM2, 7, 1, 0), +}; + +/* Right Mixer */ +static const struct snd_kcontrol_new es8323_right_mixer_controls[] = { + //SOC_DAPM_SINGLE("Left Playback Switch", es8323_ROUTM1, 8, 1, 0), + //SOC_DAPM_SINGLE("Left Bypass Switch", es8323_ROUTM1, 7, 1, 0), + SOC_DAPM_SINGLE("Right Playback Switch", ES8323_DACCONTROL20, 7, 1, 0), + SOC_DAPM_SINGLE("Right Bypass Switch", ES8323_DACCONTROL20, 6, 1, 0), +}; + +int es8328_dapm_pre_event(struct snd_soc_dapm_widget* widget, struct snd_kcontrol * null, int event); +int es8328_dapm_post_event(struct snd_soc_dapm_widget* widget, struct snd_kcontrol * null, int event); + +static const char *es8323_pga_sel[] = {"Line 1", "Line 2", "Differential"}; +static const unsigned int es8323_pga_val[] = { 0, 1, 3 }; + +/* Left PGA Mux */ +static const struct soc_enum es8323_lpga_enum = + SOC_VALUE_ENUM_SINGLE(ES8323_ADCCONTROL2, 6, 3, + ARRAY_SIZE(es8323_pga_sel), + es8323_pga_sel, + es8323_pga_val); +static const struct snd_kcontrol_new es8323_left_pga_controls = + SOC_DAPM_VALUE_ENUM("Route", es8323_lpga_enum); + +/* Right PGA Mux */ +static const struct soc_enum es8323_rpga_enum = + SOC_VALUE_ENUM_SINGLE(ES8323_ADCCONTROL2, 4, 3, + ARRAY_SIZE(es8323_pga_sel), + es8323_pga_sel, + es8323_pga_val); +static const struct snd_kcontrol_new es8323_right_pga_controls = + SOC_DAPM_VALUE_ENUM("Route", es8323_rpga_enum); + +/* Differential Mux */ +static const char *es8323_diff_sel[] = {"Line 1", "Line 2"}; +static const struct soc_enum diffmux = + SOC_ENUM_SINGLE(ES8323_ADCCONTROL3, 7, 2, es8323_diff_sel); +static const struct snd_kcontrol_new es8323_diffmux_controls = + SOC_DAPM_ENUM("Route", diffmux); + +/* Mono ADC Mux */ +static const char *es8323_mono_mux[] = {"Stereo", "Mono (Left)", + "Mono (Right)"}; +static const struct soc_enum monomux = + SOC_ENUM_SINGLE(ES8323_ADCCONTROL3, 3, 3, es8323_mono_mux); +static const struct snd_kcontrol_new es8323_monomux_controls = + SOC_DAPM_ENUM("Route", monomux); + +static const struct snd_soc_dapm_widget es8323_dapm_widgets[] = { + SND_SOC_DAPM_MICBIAS("Mic Bias", ES8323_ADCPOWER, 3, 1), + + SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, + &es8323_diffmux_controls), + + SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, + &es8323_monomux_controls), + SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, + &es8323_monomux_controls), + + SND_SOC_DAPM_MUX("Left PGA Mux", ES8323_ADCPOWER, 7, 1, + &es8323_left_pga_controls), + SND_SOC_DAPM_MUX("Right PGA Mux", ES8323_ADCPOWER, 6, 1, + &es8323_right_pga_controls), + + SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, + &es8323_left_line_controls), + SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, + &es8323_right_line_controls), + + SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8323_ADCPOWER, 4, 1), + SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8323_ADCPOWER, 5, 1), + + /* gModify.Cmmt Implement when suspend/startup */ + /*SND_SOC_DAPM_DAC("Right DAC", "Right Playback", es8323_PWR2, 7, 0),*/ + /*SND_SOC_DAPM_DAC("Left DAC", "Left Playback", es8323_PWR2, 8, 0),*/ + + SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, + &es8323_left_mixer_controls[0], + ARRAY_SIZE(es8323_left_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, + &es8323_right_mixer_controls[0], + ARRAY_SIZE(es8323_right_mixer_controls)), + + SND_SOC_DAPM_PGA("Right Out 2", ES8323_DACPOWER, 2, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 2", ES8323_DACPOWER, 3, 0, NULL, 0), + SND_SOC_DAPM_PGA("Right Out 1", ES8323_DACPOWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("Left Out 1", ES8323_DACPOWER, 5, 0, NULL, 0), + + //SND_SOC_DAPM_POST("LRC control", es8323_lrc_control), + + SND_SOC_DAPM_OUTPUT("LOUT1"), + SND_SOC_DAPM_OUTPUT("ROUT1"), + SND_SOC_DAPM_OUTPUT("LOUT2"), + SND_SOC_DAPM_OUTPUT("ROUT2"), + SND_SOC_DAPM_OUTPUT("VREF"), + + SND_SOC_DAPM_INPUT("LINPUT1"), + SND_SOC_DAPM_INPUT("LINPUT2"), + SND_SOC_DAPM_INPUT("RINPUT1"), + SND_SOC_DAPM_INPUT("RINPUT2"), + SND_SOC_DAPM_PRE("PRE", es8328_dapm_pre_event), + SND_SOC_DAPM_POST("POST", es8328_dapm_post_event), +}; + +static const struct snd_soc_dapm_route audio_map[] = { + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + //{ "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + //{ "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left PGA Mux", "Line 1", "LINPUT1" }, + { "Left PGA Mux", "Line 2", "LINPUT2" }, + { "Left PGA Mux", "Differential", "Differential Mux" }, + + { "Right PGA Mux", "Line 1", "RINPUT1" }, + { "Right PGA Mux", "Line 2", "RINPUT2" }, + { "Right PGA Mux", "Differential", "Differential Mux" }, + + { "Differential Mux", "Line 1", "LINPUT1" }, + { "Differential Mux", "Line 1", "RINPUT1" }, + { "Differential Mux", "Line 2", "LINPUT2" }, + { "Differential Mux", "Line 2", "RINPUT2" }, + + { "Left ADC Mux", "Stereo", "Left PGA Mux" }, + { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, + //{ "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, + + { "Right ADC Mux", "Stereo", "Right PGA Mux" }, + { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, + //{ "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, + + { "Left ADC", NULL, "Left ADC Mux" }, + { "Right ADC", NULL, "Right ADC Mux" }, + + { "Left Line Mux", "Line 1", "LINPUT1" }, + { "Left Line Mux", "Line 2", "LINPUT2" }, + { "Left Line Mux", "PGA", "Left PGA Mux" }, + //{ "Left Line Mux", "Differential", "Differential Mux" }, + + { "Right Line Mux", "Line 1", "RINPUT1" }, + { "Right Line Mux", "Line 2", "RINPUT2" }, + { "Right Line Mux", "PGA", "Right PGA Mux" }, + //{ "Right Line Mux", "Differential", "Differential Mux" }, + + { "Left Mixer", "Left Playback Switch", "Left DAC" }, + { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, + //{ "Left Mixer", "Right Playback Switch", "Right DAC" }, + //{ "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, + + //{ "Right Mixer", "Left Playback Switch", "Left DAC" }, + //{ "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, + { "Right Mixer", "Right Playback Switch", "Right DAC" }, + { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, + + { "Left Out 1", NULL, "Left Mixer" }, + { "LOUT1", NULL, "Left Out 1" }, + { "Right Out 1", NULL, "Right Mixer" }, + { "ROUT1", NULL, "Right Out 1" }, + + { "Left Out 2", NULL, "Left Mixer" }, + { "LOUT2", NULL, "Left Out 2" }, + { "Right Out 2", NULL, "Right Mixer" }, + { "ROUT2", NULL, "Right Out 2" }, +}; + +int es8328_dapm_pre_event(struct snd_soc_dapm_widget* widget, struct snd_kcontrol * null, int event) +{ +// printk("fun:%s, event:%d\r\n", __FUNCTION__, event); + if (event==1) + { + widget->dapm->dev_power = 1; + es8323_set_bias_level(widget->codec, SND_SOC_BIAS_PREPARE); + } + return 0; +} +int es8328_dapm_post_event(struct snd_soc_dapm_widget* widget, struct snd_kcontrol * null, int event) +{ +// printk("fun:%s, event:%d\r\n", __FUNCTION__, event); + if (event==8) + { + widget->dapm->dev_power = 0; + es8323_set_bias_level(widget->codec, SND_SOC_BIAS_STANDBY); + } + return 0; +} + +struct _coeff_div { + u32 mclk; + u32 rate; + u16 fs; + u8 sr:4; + u8 usb:1; +}; + +/* codec hifi mclk clock divider coefficients */ +static const struct _coeff_div coeff_div[] = { + /* 8k */ + {12288000, 8000, 1536, 0xa, 0x0}, + {11289600, 8000, 1408, 0x9, 0x0}, + {18432000, 8000, 2304, 0xc, 0x0}, + {16934400, 8000, 2112, 0xb, 0x0}, + {12000000, 8000, 1500, 0xb, 0x1}, + + /* 11.025k */ + {11289600, 11025, 1024, 0x7, 0x0}, + {16934400, 11025, 1536, 0xa, 0x0}, + {12000000, 11025, 1088, 0x9, 0x1}, + + /* 16k */ + {12288000, 16000, 768, 0x6, 0x0}, + {18432000, 16000, 1152, 0x8, 0x0}, + {12000000, 16000, 750, 0x7, 0x1}, + + /* 22.05k */ + {11289600, 22050, 512, 0x4, 0x0}, + {16934400, 22050, 768, 0x6, 0x0}, + {12000000, 22050, 544, 0x6, 0x1}, + + /* 32k */ + {12288000, 32000, 384, 0x3, 0x0}, + {18432000, 32000, 576, 0x5, 0x0}, + {12000000, 32000, 375, 0x4, 0x1}, + + /* 44.1k */ + {11289600, 44100, 256, 0x2, 0x0}, + {16934400, 44100, 384, 0x3, 0x0}, + {12000000, 44100, 272, 0x3, 0x1}, + + /* 48k */ + {12288000, 48000, 256, 0x2, 0x0}, + {18432000, 48000, 384, 0x3, 0x0}, + {12000000, 48000, 250, 0x2, 0x1}, + + /* 88.2k */ + {11289600, 88200, 128, 0x0, 0x0}, + {16934400, 88200, 192, 0x1, 0x0}, + {12000000, 88200, 136, 0x1, 0x1}, + + /* 96k */ + {12288000, 96000, 128, 0x0, 0x0}, + {18432000, 96000, 192, 0x1, 0x0}, + {12000000, 96000, 125, 0x0, 0x1}, +}; + +static inline int get_coeff(int mclk, int rate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(coeff_div); i++) { + if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk) + return i; + } + + return -EINVAL; +} + +/* The set of rates we can generate from the above for each SYSCLK */ + +static unsigned int rates_12288[] = { + 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12288 = { + .count = ARRAY_SIZE(rates_12288), + .list = rates_12288, +}; + +static unsigned int rates_112896[] = { + 8000, 11025, 22050, 44100, +}; + +static struct snd_pcm_hw_constraint_list constraints_112896 = { + .count = ARRAY_SIZE(rates_112896), + .list = rates_112896, +}; + +static unsigned int rates_12[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, + 48000, 88235, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12 = { + .count = ARRAY_SIZE(rates_12), + .list = rates_12, +}; + +static void on_off_ext_amp(int i) +{ + struct snd_soc_codec *codec; + gpio_set_value(SPK_CON, i); + mdelay(50); + #ifdef SPK_CTL + //gpio_direction_output(SPK_CTL, GPIO_LOW); + gpio_set_value(SPK_CTL, i); + /*snd_soc_write(codec,0x1E,0x1F); + snd_soc_write(codec,0x1F,0xF7); + snd_soc_write(codec,0x20,0xFD); + snd_soc_write(codec,0x21,0xFF); + snd_soc_write(codec,0x22,0x1F); + snd_soc_write(codec,0x23,0xF7); + snd_soc_write(codec,0x24,0xFD); + snd_soc_write(codec,0x25,0xFF); + snd_soc_write(codec,0x30,0x18); + snd_soc_write(codec,0x31,0x18); + */ + DBG("*** %s() SPEAKER set as %d\n", __FUNCTION__, i); + #endif + #ifdef EAR_CON_PIN + //gpio_direction_output(EAR_CON_PIN, GPIO_LOW); + gpio_set_value(EAR_CON_PIN, i); + /*snd_soc_write(codec,0x1E,0x01);//for 47uF capacitors ,15db Bass@90Hz,Fs=44100 + snd_soc_write(codec,0x1F,0x84); + snd_soc_write(codec,0x20,0xED); + snd_soc_write(codec,0x21,0xAF); + snd_soc_write(codec,0x22,0x20); + snd_soc_write(codec,0x23,0x6C); + snd_soc_write(codec,0x24,0xE9); + snd_soc_write(codec,0x25,0xBE); + snd_soc_write(codec,0x30,0x1c); + snd_soc_write(codec,0x31,0x1c); + */ + DBG("*** %s() HEADPHONE set as %d\n", __FUNCTION__, i); + mdelay(50); + #endif +} + +static void es8323_codec_set_spk(bool on) +{ + on_off_ext_amp(on); +} + + + +/* + * Note that this should be called from init rather than from hw_params. + */ +static int es8323_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct es8323_priv *es8323 = snd_soc_codec_get_drvdata(codec); + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + switch (freq) { + case 11289600: + case 18432000: + case 22579200: + case 36864000: + es8323->sysclk_constraints = &constraints_112896; + es8323->sysclk = freq; + return 0; + + case 12288000: + case 16934400: + case 24576000: + case 33868800: + es8323->sysclk_constraints = &constraints_12288; + es8323->sysclk = freq; + return 0; + + case 12000000: + case 24000000: + es8323->sysclk_constraints = &constraints_12; + es8323->sysclk = freq; + return 0; + } + return -EINVAL; +} + +static int es8323_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u8 iface = 0; + u8 adciface = 0; + u8 daciface = 0; + alsa_dbg("%s----%d, fmt[%02x]\n",__FUNCTION__,__LINE__,fmt); + + iface = snd_soc_read(codec, ES8323_IFACE); + adciface = snd_soc_read(codec, ES8323_ADC_IFACE); + daciface = snd_soc_read(codec, ES8323_DAC_IFACE); + + /* set master/slave audio interface */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: // MASTER MODE + alsa_dbg("es8323 in master mode"); + iface |= 0x80; + break; + case SND_SOC_DAIFMT_CBS_CFS: // SLAVE MODE + alsa_dbg("es8323 in slave mode"); + iface &= 0x7F; + break; + default: + return -EINVAL; + } + + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + adciface &= 0xFC; + //daciface &= 0xF9; //updated by david-everest,5-25 + daciface &= 0xF9; + break; + case SND_SOC_DAIFMT_RIGHT_J: + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + case SND_SOC_DAIFMT_DSP_A: + break; + case SND_SOC_DAIFMT_DSP_B: + break; + default: + return -EINVAL; + } + + /* clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + iface &= 0xDF; + adciface &= 0xDF; + //daciface &= 0xDF; //UPDATED BY david-everest,5-25 + daciface &= 0xBF; + break; + case SND_SOC_DAIFMT_IB_IF: + iface |= 0x20; + //adciface &= 0xDF; //UPDATED BY david-everest,5-25 + adciface |= 0x20; + //daciface &= 0xDF; //UPDATED BY david-everest,5-25 + daciface |= 0x40; + break; + case SND_SOC_DAIFMT_IB_NF: + iface |= 0x20; + // adciface |= 0x40; //UPDATED BY david-everest,5-25 + adciface &= 0xDF; + //daciface |= 0x40; //UPDATED BY david-everest,5-25 + daciface &= 0xBF; + break; + case SND_SOC_DAIFMT_NB_IF: + iface &= 0xDF; + adciface |= 0x20; + //daciface |= 0x20; //UPDATED BY david-everest,5-25 + daciface |= 0x40; + break; + default: + return -EINVAL; + } + + snd_soc_write(codec, ES8323_IFACE , iface); + snd_soc_write(codec, ES8323_ADC_IFACE, adciface); + snd_soc_write(codec, ES8323_DAC_IFACE, daciface); + + return 0; +} + +static int es8323_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct es8323_priv *es8323 = snd_soc_codec_get_drvdata(codec); + u16 i; + if (!es8323->is_startup) { + es8323->is_startup = 1; + //on_off_ext_amp(0); + /* + snd_soc_write(codec, ES8323_CONTROL1, 0x06); + snd_soc_write(codec, ES8323_CONTROL2, 0x72); + snd_soc_write(codec, ES8323_DACPOWER, 0x00); + mdelay(30); + //snd_soc_write(codec, ES8323_CHIPPOWER, 0xf3); + snd_soc_write(codec, ES8323_DACCONTROL21, 0x80); + */ + snd_soc_write(codec, ES8323_ADCPOWER, 0x59); + snd_soc_write(codec, ES8323_DACPOWER, 0x0c); + snd_soc_write(codec, ES8323_CHIPPOWER, 0x00); + //on_off_ext_amp(1); + } + + DBG("Enter::%s----%d es8323->sysclk=%d\n",__FUNCTION__,__LINE__,es8323->sysclk); + + /* The set of sample rates that can be supported depends on the + * MCLK supplied to the CODEC - enforce this. + */ + if (!es8323->sysclk) { + dev_err(codec->dev, + "No MCLK configured, call set_sysclk() on init\n"); + return -EINVAL; + } + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + es8323->sysclk_constraints); + + return 0; +} + +static int es8323_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + + static int codecfirstuse=0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct es8323_priv *es8323 = snd_soc_codec_get_drvdata(codec); + //u16 iface = snd_soc_read(codec, es8323_IFACE) & 0x1f3; + //u16 srate = snd_soc_read(codec, es8323_SRATE) & 0x180; + + u16 srate = snd_soc_read(codec, ES8323_IFACE) & 0x80; + u16 adciface = snd_soc_read(codec, ES8323_ADC_IFACE) & 0xE3; + u16 daciface = snd_soc_read(codec, ES8323_DAC_IFACE) & 0xC7; + + int coeff; + + coeff = get_coeff(es8323->sysclk, params_rate(params)); + if (coeff < 0) { + coeff = get_coeff(es8323->sysclk / 2, params_rate(params)); + srate |= 0x40; + } + if (coeff < 0) { + dev_err(codec->dev, + "Unable to configure sample rate %dHz with %dHz MCLK\n", + params_rate(params), es8323->sysclk); + return coeff; + } + + /* bit size */ + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + adciface |= 0x000C; + daciface |= 0x0018; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + adciface |= 0x0004; + daciface |= 0x0008; + break; + case SNDRV_PCM_FORMAT_S24_LE: + break; + case SNDRV_PCM_FORMAT_S32_LE: + adciface |= 0x0010; + daciface |= 0x0020; + break; + } + + /* set iface & srate*/ + snd_soc_write(codec, ES8323_DAC_IFACE, daciface); //dac bits length + snd_soc_write(codec, ES8323_ADC_IFACE, adciface); //adc bits length + + if (coeff >= 0) + { + snd_soc_write(codec, ES8323_IFACE, srate); //bclk div,mclkdiv2 + snd_soc_write(codec, ES8323_ADCCONTROL5, coeff_div[coeff].sr | (coeff_div[coeff].usb) << 4); + snd_soc_write(codec, ES8323_DACCONTROL2, coeff_div[coeff].sr | (coeff_div[coeff].usb) << 4); + } + if (codecfirstuse == 0) + { + snd_soc_write(codec, ES8323_LOUT2_VOL, es8323_DEF_VOL);//0x1c); // + snd_soc_write(codec, ES8323_ROUT2_VOL, es8323_DEF_VOL);//0x1c); // + codecfirstuse=1; + } + + return 0; +} + +static int es8323_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + u16 mute_reg = snd_soc_read(codec, ES8323_DACCONTROL3) & 0xfb; + + DBG("Enter::%s----%d--mute=%d\n",__FUNCTION__,__LINE__,mute); + + if (mute) + //snd_soc_write(codec, ES8323_DACCONTROL3, mute_reg | 0x4); + { + snd_soc_write(codec, ES8323_DACCONTROL3, 0xe6);//0xe6); + + } + else + { + + snd_soc_write(codec, ES8323_DACCONTROL3, 0xe2);//0xe2); + + + + } + on_off_ext_amp(!mute); + + return 0; +} + +static int es8323_trigger(struct snd_pcm_substream *substream, int status, struct snd_soc_dai *dai) +{ + if(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if(status == SNDRV_PCM_TRIGGER_START){ + //on_off_ext_amp(1); + } + else if(status == SNDRV_PCM_TRIGGER_STOP){ + //on_off_ext_amp(0); + } + } + + return 0; +} +///////////////////////////////////////////////////////////////// +static int es8323_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct es8323_priv *es8323 = snd_soc_codec_get_drvdata(codec); + u16 OUT_VOL = snd_soc_read(codec, ES8323_LOUT1_VOL); + + DBG("Enter::%s----%d level =%d\n",__FUNCTION__,__LINE__,level); + u16 i; + switch (level) { + case SND_SOC_BIAS_ON: + es8323->is_biason = 1; + break; + + case SND_SOC_BIAS_PREPARE: + snd_soc_write(codec, 0x07, 0x7C); + snd_soc_write(codec, 0x05, 0x00); + snd_soc_write(codec, 0x06, 0xFF); + //snd_soc_write(codec, 0x2b, 0x80); + snd_soc_write(codec, ES8323_CHIPPOWER, 0x00); + //snd_soc_write(codec, ES8323_DACPOWER, 0x0c); + snd_soc_write(codec, ES8323_ADCPOWER, 0x59); + //snd_soc_write(codec, 0x19, 0x00); + break; + case SND_SOC_BIAS_STANDBY: + + snd_soc_write(codec, 0x07, 0x7C); + snd_soc_write(codec, 0x05, 0x00); + snd_soc_write(codec, 0x06, 0xFF); + //snd_soc_write(codec, 0x2b, 0x80); + snd_soc_write(codec, ES8323_CHIPPOWER, 0x00); + //snd_soc_write(codec, ES8323_DACPOWER, 0x0c); + snd_soc_write(codec, ES8323_ADCPOWER, 0x59); + //snd_soc_write(codec, 0x19, 0x00); + break; + + case SND_SOC_BIAS_OFF: + //snd_soc_write(codec, 0x19, 0x04); + //snd_soc_write(codec, ES8323_DACPOWER, 0xcc); + snd_soc_write(codec, 0x07, 0x7B); + snd_soc_write(codec, 0x05, 0xFF); + snd_soc_write(codec, 0x06, 0xFF); + snd_soc_write(codec, ES8323_ADCPOWER, 0xFF); + snd_soc_write(codec, ES8323_CHIPPOWER, 0xAA); + + //snd_soc_write(codec, 0x2b, 0x90); + break; + } + codec->dapm.bias_level = level; + return 0; +} + + + +#define es8323_RATES SNDRV_PCM_RATE_8000_96000 + +#define es8323_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops es8323_ops = { + .startup = es8323_pcm_startup, + .hw_params = es8323_pcm_hw_params, + .set_fmt = es8323_set_dai_fmt, + .set_sysclk = es8323_set_dai_sysclk, + .digital_mute = es8323_mute, +// .trigger = es8323_trigger, +}; + +static struct snd_soc_dai_driver es8323_dai = { + .name = "ES8323 HiFi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = es8323_RATES, + .formats = es8323_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = es8323_RATES, + .formats = es8323_FORMATS, + }, + .ops = &es8323_ops, + .symmetric_rates = 1, +}; + +static int es8323_suspend(struct snd_soc_codec *codec, pm_message_t state) +{ + u16 i; + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + +#if 0 + snd_soc_write(codec, 0x19, 0x06); + snd_soc_write(codec, 0x07, 0x7B); + snd_soc_write(codec, 0x06, 0xFF); + snd_soc_write(codec, 0x05, 0xFF); +#endif + + snd_soc_write(codec, 0x19, 0x06); + snd_soc_write(codec, 0x30, 0x00); + snd_soc_write(codec, 0x31, 0x00); + + + snd_soc_write(codec, ES8323_ADCPOWER, 0xFF); + snd_soc_write(codec, ES8323_DACPOWER, 0xc0); + snd_soc_write(codec, ES8323_CHIPPOWER, 0xF3); + snd_soc_write(codec, 0x00, 0x00); + snd_soc_write(codec, 0x01, 0x58); + snd_soc_write(codec, 0x2b, 0x9c); + msleep(50); + gpio_set_value(SPK_CON, 0); + return 0; +} + +static int es8323_resume(struct snd_soc_codec *codec) +{ + u16 i; + u8 data[2]; + u16 *cache = codec->reg_cache; + snd_soc_write(codec, 0x2b, 0x80); + snd_soc_write(codec, 0x01, 0x50); + snd_soc_write(codec, 0x00, 0x36); + + snd_soc_write(codec, ES8323_CHIPPOWER, 0x00); + snd_soc_write(codec, ES8323_DACPOWER, 0x0c); + snd_soc_write(codec, ES8323_ADCPOWER, 0x59); + + snd_soc_write(codec, 0x31, es8323_DEF_VOL); + snd_soc_write(codec, 0x30, es8323_DEF_VOL); + snd_soc_write(codec, 0x19, 0x02); + gpio_set_value(SPK_CON, 1); + return 0; +} + +static u32 cur_reg=0; +static struct snd_soc_codec *es8323_codec; +static int entry_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + + snd_soc_write(es8323_codec, ES8323_ADCPOWER, 0xff); + snd_soc_write(es8323_codec, ES8323_DACPOWER, 0xf0); + snd_soc_write(es8323_codec, ES8323_DACPOWER, 0xc0); + snd_soc_write(es8323_codec, ES8323_CHIPPOWER, 0xf3); + + len = sprintf(page, "es8323 suspend...\n"); + + return len ; +} + +#if (RT5633_SPK_TIMER == 1) +static void spk_work_handler(struct work_struct *work) +{ + //if(!gpio_get_value(ES8323_HP_PIN)){ + //gpio_direction_output(SPK_CON,0); + // gpio_set_value(SPK_CON, 0); +// }else{ + //gpio_direction_output(SPK_CON,1); + // gpio_set_value(SPK_CON, 1); +// } +} +void spk_timer_callback(unsigned long data ) +{ + int ret = 0; + schedule_work(&spk_work); + ret = mod_timer(&spk_timer, jiffies + msecs_to_jiffies(1000)); + if (ret) printk("Error in mod_timer\n"); +} +#endif + +static int es8323_probe(struct snd_soc_codec *codec) +{ + struct es8323_priv *es8323 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret = 0; + u16 reg,i; + + printk("%s\n", __func__); +#if 0 + ret = gpio_request(RK30_PIN0_PC7, NULL); + if (ret != 0) { + printk("%s request RK30_PIN0_PC7 error", __func__); + return ret; + } + gpio_direction_input(RK30_PIN0_PC7); +#endif + ret = gpio_request(SPK_CON, NULL); + if (ret != 0) { + printk("%s request SPK_CON error", __func__); + return ret; + } + //gpio_set_value(SPK_CON, 1); + gpio_direction_output(SPK_CON,0); + + if (codec == NULL) { + dev_err(codec->dev, "Codec device not registered\n"); + return -ENODEV; + } + codec->read = es8323_read_reg_cache; + codec->write = es8323_write; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->control_data = container_of(codec->dev, struct i2c_client, dev); + + es8323_codec = codec; + ret = es8323_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + return ret; + } + #if (RT5633_SPK_TIMER == 1) + setup_timer( &spk_timer, spk_timer_callback, 0 ); + ret = mod_timer( &spk_timer, jiffies + msecs_to_jiffies(5000) ); + if (ret) + printk("Error in mod_timer\n"); + INIT_WORK(&spk_work, spk_work_handler); + es8323_ANVOL=1; +#endif + + //es8323_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + +#if 1 + //snd_soc_write(codec, 0x35 , 0xa0); + //snd_soc_write(codec, 0x36 , 0x08); + snd_soc_write(codec, 0x2B,0x80); + snd_soc_write(codec, 0x08,0x00); //ES8388 salve + snd_soc_write(codec, 0x00,0x36); // + snd_soc_write(codec, 0x01,0x74); + snd_soc_write(codec, 0x01,0x50); //PLAYBACK & RECORD Mode,EnRefr=1 + msleep(1200); + snd_soc_write(codec, 0x04,0xfc); //pdn_ana=0,ibiasgen_pdn=0 + snd_soc_write(codec, 0x03,0x59); //pdn_ana=0,ibiasgen_pdn=0 + snd_soc_write(codec, 0x05,0x00); //pdn_ana=0,ibiasgen_pdn=0 + snd_soc_write(codec, 0x06,0xc3); //pdn_ana=0,ibiasgen_pdn=0 + snd_soc_write(codec, 0x02,0xF0); //START DLL and STM + snd_soc_write(codec, 0x02,0xc0); //START DLL and STM + snd_soc_write(codec, 0x09,0x88); //ADC L/R PGA = +24dB + snd_soc_write(codec, 0x2e, 0x00); + snd_soc_write(codec, 0x2f, 0x00); + //---------------------------------------------------------------------------------------------------------------- + snd_soc_write(codec, 0x0a,0xf0); //ADC INPUT=LIN2/RIN2 + snd_soc_write(codec, 0x0b,0x82); //ADC INPUT=LIN2/RIN2 //82 + //----------------------------------------------------------------------------------------------------------------- + snd_soc_write(codec, 0x0C,0x4c); //I2S-24BIT + snd_soc_write(codec, 0x0d,0x02); //MCLK/LRCK=256 + snd_soc_write(codec, 0x10,0x00); //ADC Left Volume=0db + snd_soc_write(codec, 0x11,0x00); //ADC Right Volume=0db + snd_soc_write(codec, 0x12,0xea); // ALC stereo MAXGAIN: 35.5dB, MINGAIN: +6dB (Record Volume increased!) + snd_soc_write(codec, 0x13,0xc0); + snd_soc_write(codec, 0x14,0x05); + snd_soc_write(codec, 0x15,0x06); + snd_soc_write(codec, 0x16,0x53); + snd_soc_write(codec, 0x17,0x18); //I2S-16BIT + snd_soc_write(codec, 0x18,0x02); + snd_soc_write(codec, 0x1A,0x0A); //DAC VOLUME=0DB + snd_soc_write(codec, 0x1B,0x0A); + /***********************/ + snd_soc_write(codec, 0x1E,0x01); //for 47uF capacitors ,15db Bass@90Hz,Fs=44100 + snd_soc_write(codec, 0x1F,0x84); + snd_soc_write(codec, 0x20,0xED); + snd_soc_write(codec, 0x21,0xAF); + snd_soc_write(codec, 0x22,0x20); + snd_soc_write(codec, 0x23,0x6C); + snd_soc_write(codec, 0x24,0xE9); + snd_soc_write(codec, 0x25,0xBE); + /***********************/ + snd_soc_write(codec, 0x26,0x12); //Left DAC TO Left MIXER + snd_soc_write(codec, 0x27,0xb8); //Left DAC TO Left MIXER + snd_soc_write(codec, 0x28,0x38); + snd_soc_write(codec, 0x29,0x38); + snd_soc_write(codec, 0x2A,0xb8); + snd_soc_write(codec, 0x2e,0x00); + snd_soc_write(codec, 0x2f,0x00); + snd_soc_write(codec, 0x30,0x00); + snd_soc_write(codec, 0x31,0x00); + snd_soc_write(codec, 0x02,0x00); //aa //START DLL and state-machine,START DSM + snd_soc_write(codec, 0x04,0x3c); + snd_soc_write(codec, 0x19,0xe2); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE + + +#endif + + //s8323_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + //codec->dapm.bias_level = SND_SOC_BIAS_STANDBY; + + snd_soc_add_controls(codec, es8323_snd_controls, + ARRAY_SIZE(es8323_snd_controls)); + snd_soc_dapm_new_controls(dapm, es8323_dapm_widgets, + ARRAY_SIZE(es8323_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + + create_proc_read_entry("es8323_suspend", 0644, NULL, entry_read, NULL); + + return 0; +} + +static int es8323_remove(struct snd_soc_codec *codec) +{ + es8323_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +void codec_set_spk(bool on) +{ + struct snd_soc_codec *codec = es8323_codec; + + DBG("Enter::%s----%d--\n",__FUNCTION__,__LINE__); + + if (!on) + //snd_soc_write(codec, ES8323_DACCONTROL3, mute_reg | 0x4); + { + snd_soc_write(codec, ES8323_DACCONTROL3, 0x06);//0xe6); + + } + else + { + + snd_soc_write(codec, ES8323_DACCONTROL3, 0x02);//0xe2); + + + + } + on_off_ext_amp(on); + //return; +} + +static struct snd_soc_codec_driver soc_codec_dev_es8323 = { + .probe = es8323_probe, + .remove = es8323_remove, + .suspend = es8323_suspend, + .resume = es8323_resume, + .set_bias_level = es8323_set_bias_level, + .reg_cache_size = ARRAY_SIZE(es8323_reg), + .reg_word_size = sizeof(u16), + .reg_cache_default = es8323_reg, + //------------------------------------------ + //.volatile_register = es8323_volatile_register, + //.readable_register = es8323_readable_register, + .reg_cache_step = 1, + .controls = es8323_snd_controls, + .num_controls = ARRAY_SIZE(es8323_snd_controls), + .dapm_routes = audio_map, + .num_dapm_routes = ARRAY_SIZE(audio_map), + .dapm_widgets = es8323_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(es8323_dapm_widgets), + + //-------------------------------------------------- + .read = es8323_read_reg_cache, + .write = es8323_write, +}; + +#if defined(CONFIG_SPI_MASTER) +static int __devinit es8323_spi_probe(struct spi_device *spi) +{ + struct es8323_priv *es8323; + int ret; + + es8323 = kzalloc(sizeof(struct es8323_priv), GFP_KERNEL); + if (es8323 == NULL) + return -ENOMEM; + + es8323->control_type = SND_SOC_SPI; + spi_set_drvdata(spi, es8323); + + ret = snd_soc_register_codec(&spi->dev, + &soc_codec_dev_es8323, &es8323_dai, 1); + if (ret < 0) + kfree(es8323); + return ret; +} + +static int __devexit es8323_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + kfree(spi_get_drvdata(spi)); + return 0; +} + +static struct spi_driver es8323_spi_driver = { + .driver = { + .name = "ES8323", + .owner = THIS_MODULE, + }, + .probe = es8323_spi_probe, + .remove = __devexit_p(es8323_spi_remove), +}; +#endif /* CONFIG_SPI_MASTER */ + +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) +static ssize_t es8323_show(struct device *dev, struct device_attribute *attr, char *_buf) +{ + return sprintf(_buf, "%s(): get 0x%04x=0x%04x\n", __FUNCTION__, cur_reg, + snd_soc_read(es8323_codec, cur_reg)); +} + +static u32 strtol(const char *nptr, int base) +{ + u32 ret; + if(!nptr || (base!=16 && base!=10 && base!=8)) + { + + printk("%s(): NULL pointer input\n", __FUNCTION__); + return -1; + } + for(ret=0; *nptr; nptr++) + { + + + if((base==16 && *nptr>='A' && *nptr<='F') || + (base==16 && *nptr>='a' && *nptr<='f') || + (base>=10 && *nptr>='0' && *nptr<='9') || + (base>=8 && *nptr>='0' && *nptr<='7') ) + { + ret *= base; + if(base==16 && *nptr>='A' && *nptr<='F') + ret += *nptr-'A'+10; + else if(base==16 && *nptr>='a' && *nptr<='f') + ret += *nptr-'a'+10; + else if(base>=10 && *nptr>='0' && *nptr<='9') + ret += *nptr-'0'; + else if(base>=8 && *nptr>='0' && *nptr<='7') + ret += *nptr-'0'; + } + else + return ret; + } + return ret; +} + +static ssize_t es8323_store(struct device *dev, + struct device_attribute *attr, + const char *_buf, size_t _count) +{ + const char * p=_buf; + u32 reg, val; + + if(!strncmp(_buf, "get", strlen("get"))) + { + p+=strlen("get"); + cur_reg=(u32)strtol(p, 16); + val=snd_soc_read(es8323_codec, cur_reg); + printk("%s(): get 0x%04x=0x%04x\n", __FUNCTION__, cur_reg, val); + } + else if(!strncmp(_buf, "put", strlen("put"))) + { + p+=strlen("put"); + reg=strtol(p, 16); + p=strchr(_buf, '='); + if(p) + { + ++ p; + val=strtol(p, 16); + snd_soc_write(es8323_codec, reg, val); + printk("%s(): set 0x%04x=0x%04x\n", __FUNCTION__, reg, val); + } + else + printk("%s(): Bad string format input!\n", __FUNCTION__); + } + else + printk("%s(): Bad string format input!\n", __FUNCTION__); + + return _count; +} + +static struct device *es8323_dev = NULL; +static struct class *es8323_class = NULL; +static DEVICE_ATTR(es8323, 0664, es8323_show, es8323_store); +static __devinit int es8323_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + printk("hjc:@es8323.c>>>>%s\n",__func__); + struct es8323_priv *es8323; + int ret = -1; + struct i2c_adapter *adapter = to_i2c_adapter(i2c->dev.parent); + char reg; + char tmp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_I2C\n"); + return -EIO; + } + + es8323 = kzalloc(sizeof(struct es8323_priv), GFP_KERNEL); + if (es8323 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, es8323); + es8323->control_type = SND_SOC_I2C; + + reg = ES8323_IFACE; + ret = i2c_master_reg8_recv(i2c,reg, &tmp, 1 ,200 * 1000); + //ret =i2c_master_reg8_recv(client, 0x00, buf, 2, 200*1000);//i2c_write_bytes(client, &test_data, 1); //Test I2C connection. + if (ret < 0){ + printk("es8323 probe error\n"); + kfree(es8323); + return ret; + } + + printk("es8323 probe ok\n"); + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_es8323, &es8323_dai, 1); + printk("hjc:@es8323.c,snd_soc_register_codec %s,ret=%d\n",__func__,ret); + if (ret < 0) { + kfree(es8323); + return ret; + } + printk("hjc:@es8323.c 1 %s,\n",__func__); + es8323_class = class_create(THIS_MODULE, "es8323"); + printk("hjc:@es8323.c 2 %s,\n",__func__); + if (IS_ERR(es8323_class)) + { + printk("Create class audio_es8323.\n"); + return -ENOMEM; + } + printk("hjc:@es8323.c 3 %s,\n",__func__); + es8323_dev = device_create(es8323_class, NULL, MKDEV(0, 1), NULL, "dev"); + device_create_file(es8323_dev, &dev_attr_es8323); + printk("hjc:@es8323.c 4 %s,\n",__func__); + return ret; +} + +static __devexit int es8323_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + kfree(i2c_get_clientdata(client)); + return 0; +} + +static const struct i2c_device_id es8323_i2c_id[] = { + { "es8323", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, es8323_i2c_id); + +void es8323_i2c_shutdown(struct i2c_client *client) +{ + printk("Chenzy-------hkw-------%s\n", __func__); + + gpio_direction_output(SPK_CON,0); + +#if 0 +#if 1 + gpio_direction_output(SPK_CON,0); + //gpio_request(RK30_PIN0_PC7, NULL); + //gpio_direction_output(RK30_PIN0_PC7,0); +#endif + + on_off_ext_amp(0); + // es8323_set_bias_level(es8323_codec, SND_SOC_BIAS_OFF); + +//#define SPK_CTL RK29_PIN6_PB6 +// #ifdef SPK_CTL +// //gpio_direction_output(SPK_CTL, GPIO_LOW); +// gpio_set_value(SPK_CTL, i); +// DBG("*** %s() SPEAKER set as %d\n", __FUNCTION__, i); +// #endif +//#undef SPK_CTL + u16 i; + snd_soc_write(es8323_codec, ES8323_DACCONTROL3, 0x06);//0xe6); + for(i = 0; i <= 0x1d; i++) + { + snd_soc_write(es8323_codec, ES8323_LOUT2_VOL, 0x1d - i);//0x1c); // + snd_soc_write(es8323_codec, ES8323_ROUT2_VOL, 0x1d - i);//0x1c); // + } + snd_soc_write(es8323_codec, ES8323_ADCPOWER, 0xFF); + snd_soc_write(es8323_codec, ES8323_DACPOWER, 0xFC); + snd_soc_write(es8323_codec, ES8323_CHIPPOWER, 0xf3); +#endif + return 0; + + mdelay(100); +} +#define I2C_CLK_NAME GPIO0B0_I2S8CHCLK_NAME +#define I2C_CLK_GPIO_MODE GPIO0B_GPIO0B0 +#define I2C_GPIO_OUTPUT GPIO_LOW +#define I2C_CLK_CLK_MODE GPIO0B_I2S_8CH_CLK +#define I2C_CLK_GPIO RK30_PIN0_PB0 + +#define I2C_MCLK_NAME GPIO0B1_I2S8CHSCLK_NAME +#define I2C_MCLK_GPIO_MODE GPIO0B_GPIO0B1 +#define I2C_MGPIO_OUTPUT GPIO_LOW +#define I2C_MCLK_CLK_MODE GPIO0B_I2S_8CH_SCLK +#define I2C_MCLK_GPIO RK30_PIN0_PB1 +static int es8323_i2c_suspend (struct i2c_client *client) +{ +#if 0 + rk30_mux_api_set(I2C_CLK_NAME,I2C_CLK_GPIO_MODE); + if (gpio_request(I2C_CLK_GPIO, NULL)) { + printk("func %s, line %d: request gpio fail\n", __FUNCTION__, __LINE__); + return -1; + } + + gpio_direction_output(I2C_CLK_GPIO,I2C_GPIO_OUTPUT); + + rk30_mux_api_set(I2C_MCLK_NAME,I2C_MCLK_GPIO_MODE); + if (gpio_request(I2C_MCLK_GPIO, NULL)) { + printk("func %s, line %d: request gpio fail\n", __FUNCTION__, __LINE__); + return -1; + } + + gpio_direction_output(I2C_MCLK_GPIO,I2C_MGPIO_OUTPUT); +#endif + iomux_set(GPIO1_C1); + if (gpio_request(RK30_PIN1_PC1, NULL)) { + printk("func %s, line %d: request gpio fail\n", __FUNCTION__, __LINE__); + return -1; + } + gpio_direction_input(RK30_PIN1_PC1); + gpio_pull_updown(RK30_PIN1_PC1, PullDisable); + +#if 0 + iomux_set(GPIO1_C2); + gpio_direction_input(RK30_PIN1_PC2); + gpio_pull_updown(RK30_PIN1_PC2, PullDisable); + + iomux_set(GPIO1_C3); + gpio_direction_input(RK30_PIN1_PC3); + gpio_pull_updown(RK30_PIN1_PC3, PullDisable); + + iomux_set(GPIO1_C4); + gpio_direction_input(RK30_PIN1_PC4); + gpio_pull_updown(RK30_PIN1_PC4, PullDisable); + + iomux_set(GPIO1_C5); + gpio_direction_input(RK30_PIN1_PC5); + gpio_pull_updown(RK30_PIN1_PC5, PullDisable); +#endif + + return 0; +} + +static int es8323_i2c_resume(struct i2c_client *client) +{ +#if 0 + gpio_free(I2C_MCLK_GPIO); + gpio_free(I2C_CLK_GPIO); + + rk30_mux_api_set(I2C_MCLK_NAME,I2C_MCLK_CLK_MODE); + rk30_mux_api_set(I2C_CLK_NAME,I2C_CLK_CLK_MODE); +#endif + + gpio_free(RK30_PIN1_PC1); + iomux_set(I2S0_SCLK); + + return 0; +} + +static struct i2c_driver es8323_i2c_driver = { + .driver = { + .name = "ES8323", + .owner = THIS_MODULE, + }, + .probe = es8323_i2c_probe, + .remove = __devexit_p(es8323_i2c_remove), + .shutdown = es8323_i2c_shutdown, + .suspend = es8323_i2c_suspend, + .resume = es8323_i2c_resume, + .id_table = es8323_i2c_id, +}; +#endif + +static int __init es8323_modinit(void) +{ + //if(0 == tcsi_get_value(TCSI_CODEC_ES8323)) + // return; +#if 1 + //extern int get_sound_card_exist() ; + //extern void set_sound_card_exist(int i) ; + //extern int i2c0_prober_verify(u32 dev_addr, u16 reg, u32 reg_addr_len, u32 reg_val_len, u32 id); + //typedef void (*fp_codec_set_spk)(bool on); + //extern void set_codec_set_spk(fp_codec_set_spk fp); + //if(get_sound_card_exist()) { + // printk("%s():Sound card already exist!\n", __FUNCTION__); + // return -ENODEV; + //} + //if(i2c0_prober_verify(0x10, 0x35, 1, 1, 0x0000) != 0) { + // printk("%s(): Ping error with 0x1a\n", __FUNCTION__); + // return -ENODEV; + //} + //else + // printk("%s(): Ping OK with 0x1a\n", __FUNCTION__); + //set_sound_card_exist(0x8323); + //set_codec_set_spk(es8323_codec_set_spk); +#endif + printk("hjc:@es8323.c>>>>%s\n",__func__); + return i2c_add_driver(&es8323_i2c_driver); +} +module_init(es8323_modinit); + +static void __exit es8323_exit(void) +{ + +// if(0 == tcsi_get_value(TCSI_CODEC_ES8323)) +// return; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&es8323_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&es8323_spi_driver); +#endif +} +module_exit(es8323_exit); + + +MODULE_DESCRIPTION("ASoC es8323 driver"); +MODULE_AUTHOR("Mark Brown "); +MODULE_LICENSE("GPL"); + diff --git a/sound/soc/codecs/es8323.h b/sound/soc/codecs/es8323.h new file mode 100755 index 000000000000..794be7887761 --- /dev/null +++ b/sound/soc/codecs/es8323.h @@ -0,0 +1,157 @@ +/* + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * Based on ES8323.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef _ES8323_H +#define _ES8323_H + +#define CONFIG_HHTECH_MINIPMP 1 + +/* ES8323 register space */ + +#define ES8323_CONTROL1 0x00 +#define ES8323_CONTROL2 0x01 +#define ES8323_CHIPPOWER 0x02 +#define ES8323_ADCPOWER 0x03 +#define ES8323_DACPOWER 0x04 +#define ES8323_CHIPLOPOW1 0x05 +#define ES8323_CHIPLOPOW2 0x06 +#define ES8323_ANAVOLMANAG 0x07 +#define ES8323_MASTERMODE 0x08 +#define ES8323_ADCCONTROL1 0x09 +#define ES8323_ADCCONTROL2 0x0a +#define ES8323_ADCCONTROL3 0x0b +#define ES8323_ADCCONTROL4 0x0c +#define ES8323_ADCCONTROL5 0x0d +#define ES8323_ADCCONTROL6 0x0e +#define ES8323_ADCCONTROL7 0x0f +#define ES8323_ADCCONTROL8 0x10 +#define ES8323_ADCCONTROL9 0x11 +#define ES8323_ADCCONTROL10 0x12 +#define ES8323_ADCCONTROL11 0x13 +#define ES8323_ADCCONTROL12 0x14 +#define ES8323_ADCCONTROL13 0x15 +#define ES8323_ADCCONTROL14 0x16 + +#define ES8323_DACCONTROL1 0x17 +#define ES8323_DACCONTROL2 0x18 +#define ES8323_DACCONTROL3 0x19 +#define ES8323_DACCONTROL4 0x1a +#define ES8323_DACCONTROL5 0x1b +#define ES8323_DACCONTROL6 0x1c +#define ES8323_DACCONTROL7 0x1d +#define ES8323_DACCONTROL8 0x1e +#define ES8323_DACCONTROL9 0x1f +#define ES8323_DACCONTROL10 0x20 +#define ES8323_DACCONTROL11 0x21 +#define ES8323_DACCONTROL12 0x22 +#define ES8323_DACCONTROL13 0x23 +#define ES8323_DACCONTROL14 0x24 +#define ES8323_DACCONTROL15 0x25 +#define ES8323_DACCONTROL16 0x26 +#define ES8323_DACCONTROL17 0x27 +#define ES8323_DACCONTROL18 0x28 +#define ES8323_DACCONTROL19 0x29 +#define ES8323_DACCONTROL20 0x2a +#define ES8323_DACCONTROL21 0x2b +#define ES8323_DACCONTROL22 0x2c +#define ES8323_DACCONTROL23 0x2d +#define ES8323_DACCONTROL24 0x2e +#define ES8323_DACCONTROL25 0x2f +#define ES8323_DACCONTROL26 0x30 +#define ES8323_DACCONTROL27 0x31 +#define ES8323_DACCONTROL28 0x32 +#define ES8323_DACCONTROL29 0x33 +#define ES8323_DACCONTROL30 0x34 + +#define ES8323_LADC_VOL ES8323_ADCCONTROL8 +#define ES8323_RADC_VOL ES8323_ADCCONTROL9 + +#define ES8323_LDAC_VOL ES8323_DACCONTROL4 +#define ES8323_RDAC_VOL ES8323_DACCONTROL5 + +#define ES8323_LOUT1_VOL ES8323_DACCONTROL24 +#define ES8323_ROUT1_VOL ES8323_DACCONTROL25 +#define ES8323_LOUT2_VOL ES8323_DACCONTROL26 +#define ES8323_ROUT2_VOL ES8323_DACCONTROL27 + +#define ES8323_ADC_MUTE ES8323_ADCCONTROL7 +#define ES8323_DAC_MUTE ES8323_DACCONTROL3 + + + +#define ES8323_IFACE ES8323_MASTERMODE + +#define ES8323_ADC_IFACE ES8323_ADCCONTROL4 +#define ES8323_ADC_SRATE ES8323_ADCCONTROL5 + +#define ES8323_DAC_IFACE ES8323_DACCONTROL1 +#define ES8323_DAC_SRATE ES8323_DACCONTROL2 + + + +#define ES8323_CACHEREGNUM 53 +#define ES8323_SYSCLK 0 + +struct es8323_setup_data { + int i2c_bus; + unsigned short i2c_address; +}; + +#if 1 //lzcx +#define ES8323_PLL1 0 +#define ES8323_PLL2 1 + +/* clock inputs */ +#define ES8323_MCLK 0 +#define ES8323_PCMCLK 1 + +/* clock divider id's */ +#define ES8323_PCMDIV 0 +#define ES8323_BCLKDIV 1 +#define ES8323_VXCLKDIV 2 + +/* PCM clock dividers */ +#define ES8323_PCM_DIV_1 (0 << 6) +#define ES8323_PCM_DIV_3 (2 << 6) +#define ES8323_PCM_DIV_5_5 (3 << 6) +#define ES8323_PCM_DIV_2 (4 << 6) +#define ES8323_PCM_DIV_4 (5 << 6) +#define ES8323_PCM_DIV_6 (6 << 6) +#define ES8323_PCM_DIV_8 (7 << 6) + +/* BCLK clock dividers */ +#define ES8323_BCLK_DIV_1 (0 << 7) +#define ES8323_BCLK_DIV_2 (1 << 7) +#define ES8323_BCLK_DIV_4 (2 << 7) +#define ES8323_BCLK_DIV_8 (3 << 7) + +/* VXCLK clock dividers */ +#define ES8323_VXCLK_DIV_1 (0 << 6) +#define ES8323_VXCLK_DIV_2 (1 << 6) +#define ES8323_VXCLK_DIV_4 (2 << 6) +#define ES8323_VXCLK_DIV_8 (3 << 6) +#define ES8323_VXCLK_DIV_16 (4 << 6) + +#define ES8323_DAI_HIFI 0 +#define ES8323_DAI_VOICE 1 + +#define ES8323_1536FS 1536 +#define ES8323_1024FS 1024 +#define ES8323_768FS 768 +#define ES8323_512FS 512 +#define ES8323_384FS 384 +#define ES8323_256FS 256 +#define ES8323_128FS 128 +#endif + +#endif diff --git a/sound/soc/rk29/Kconfig b/sound/soc/rk29/Kconfig index d014bcc47106..b6b6af2f410b 100755 --- a/sound/soc/rk29/Kconfig +++ b/sound/soc/rk29/Kconfig @@ -60,6 +60,16 @@ config SND_RK29_SOC_SPDIF depends on SND_RK29_SOC_I2S help This supports the use of SPDIF interface on rk29 processors +config SND_RK29_SOC_ES8323 + tristate "SoC I2S Audio support for rockchip - ES8323" + depends on SND_RK29_SOC + select SND_RK29_SOC_I2S + select SND_SOC_ES8323 + help + Say Y if you want to add support for SoC audio on rockchip + with the ES8323. + + config SND_RK29_SOC_WM8988 tristate "SoC I2S Audio support for rockchip - WM8988" depends on SND_RK29_SOC @@ -243,7 +253,7 @@ config SND_RK_SOC_RK2928 Say Y if you want to add support for SoC audio on rockchip with the RK2928 internal codec. -if SND_RK29_SOC_I2S_2CH || SND_RK29_SOC_I2S_8CH || SND_RK_SOC_I2S2_2CH +if SND_RK29_SOC_I2S_2CH || SND_RK29_SOC_I2S_8CH || SND_RK_SOC_I2S2_2CH || SND_RK29_SOC_ES8323 choice bool "Set i2s type" default SND_RK29_CODEC_SOC_SLAVE diff --git a/sound/soc/rk29/Makefile b/sound/soc/rk29/Makefile index 1734a7f7380b..14ef5ba92c82 100755 --- a/sound/soc/rk29/Makefile +++ b/sound/soc/rk29/Makefile @@ -30,6 +30,7 @@ snd-soc-hdmi-objs := rk29_hdmi.o snd-soc-rk610-objs := rk29_jetta_codec.o snd-soc-aic3262-objs := rk29_aic3262.o snd-soc-rk2928-objs := rk2928-card.o +snd-soc-es8323-objs := rk29_es8323.o obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o @@ -49,3 +50,4 @@ obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o obj-$(CONFIG_SND_RK_SOC_RK2928) += snd-soc-rk2928.o +obj-$(CONFIG_SND_RK29_SOC_ES8323) += snd-soc-es8323.o diff --git a/sound/soc/rk29/rk29_es8323.c b/sound/soc/rk29/rk29_es8323.c new file mode 100755 index 000000000000..d1cd4215e44d --- /dev/null +++ b/sound/soc/rk29/rk29_es8323.c @@ -0,0 +1,243 @@ +/* + * rk29_es8323.c -- SoC audio for rockchip + * + * Driver for rockchip es8323 audio + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include "../codecs/es8323.h" +#include "rk29_pcm.h" +#include "rk29_i2s.h" + +#include + +#if 1 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) +#endif + +//static void *rk29_speaker = NULL; + +static int rk29_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int pll_out = 0; + int ret; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + /*by Vincent Hsiung for EQ Vol Change*/ + #define HW_PARAMS_FLAG_EQVOL_ON 0x21 + #define HW_PARAMS_FLAG_EQVOL_OFF 0x22 + if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF)) + { + ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent + 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; + } + switch(params_rate(params)) { + case 8000: + case 16000: + case 24000: + case 32000: + case 48000: + pll_out = 12288000; + break; + case 11025: + case 22050: + case 44100: + pll_out = 11289600; + break; + default: + DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); + return -EINVAL; + break; + } + DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params)); + + #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); + #endif + + DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params)); + return 0; +} + +static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = { + SND_SOC_DAPM_LINE("Audio Out", NULL), + SND_SOC_DAPM_LINE("Line in", NULL), + SND_SOC_DAPM_MIC("Micn", NULL), + SND_SOC_DAPM_MIC("Micp", NULL), +}; + +static const struct snd_soc_dapm_route audio_map[]= { + + {"Audio Out", NULL, "LOUT1"}, + {"Audio Out", NULL, "ROUT1"}, + {"Line in", NULL, "RINPUT1"}, + {"Line in", NULL, "LINPUT1"}, + {"Micn", NULL, "RINPUT2"}, + {"Micp", NULL, "LINPUT2"}, +}; + +/* + * Logic for a es8323 as connected on a rockchip board. + */ +static int rk29_es8323_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_dapm_context *dapm = &codec->dapm; + int ret; + + DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, + /*12000000*/11289600, SND_SOC_CLOCK_IN); + if (ret < 0) { + printk(KERN_ERR "Failed to set es8323 SYSCLK: %d\n", ret); + return ret; + } + + /* Add specific widgets */ + snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets, + ARRAY_SIZE(rk29_dapm_widgets)); + //snd_soc_dapm_nc_pin(codec, "LOUT2"); + //snd_soc_dapm_nc_pin(codec, "ROUT2"); + + /* Set up specific audio path audio_mapnects */ + snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_sync(dapm); + + return 0; +} + +static struct snd_soc_ops rk29_ops = { + .hw_params = rk29_hw_params, +}; + +static struct snd_soc_dai_link rk29_dai = { + .name = "ES8323", + .stream_name = "ES8323 PCM", + .codec_name = "ES8323.4-0010", // ES8323.0-0010 + .platform_name = "rockchip-audio", +#if defined(CONFIG_SND_RK29_SOC_I2S_8CH) + .cpu_dai_name = "rk29_i2s.0", +#elif defined(CONFIG_SND_RK29_SOC_I2S_2CH) + .cpu_dai_name = "rk29_i2s.1", //Ó²¼þÉÏÊǽӵ½IIS0ÉÏ£¬µ«ÊÇÓÉÓÚxxÔ­Òò£¬Õâ±ß¶¨ÒåΪIIS1ÉÏ +#else + .cpu_dai_name = "rk29_i2s.2", +#endif + .codec_dai_name = "ES8323 HiFi", + .init = rk29_es8323_init, + .ops = &rk29_ops, +}; + +static struct snd_soc_card snd_soc_card_rk29 = { + .name = "RK29_ES8323", + .dai_link = &rk29_dai, + .num_links = 1, +}; + +static struct platform_device *rk29_snd_device; + +static int __init audio_card_init(void) +{ + int ret =0; + DBG("ES8323 audio_card_init\n"); +#if 0 + extern int get_sound_card_exist() ; + extern void set_sound_card_exist(int i) ; + extern int i2c0_prober_verify(u32 dev_addr, u16 reg, u32 reg_addr_len, u32 reg_val_len, u32 id); + if(i2c0_prober_verify(0x10, 0x35, 1, 1, 0x0000) != 0) { + printk("%s(): Ping error with 0x1a\n", __FUNCTION__); + return -ENODEV; + } + else + printk("%s(): Ping OK with 0x1a\n", __FUNCTION__); +#endif +//leaf if(0 == tcsi_get_value(TCSI_CODEC_ES8323)) +//leaf2012-7-26 return; + DBG("XXXXEnter::%s--1--%d\n",__FUNCTION__,__LINE__); + rk29_snd_device = platform_device_alloc("soc-audio", -1); + DBG("XXXXEnter::%s--2--%d\n",__FUNCTION__,__LINE__); + if (!rk29_snd_device) { + DBG("XXXXEnter::%s--3--%d\n",__FUNCTION__,__LINE__); + DBG("platform device allocation failed\n"); + ret = -ENOMEM; + return ret; + } + DBG("XXXXEnter::%s--4--%d\n",__FUNCTION__,__LINE__); + platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29); + DBG("XXXXEnter::%s--5--%d\n",__FUNCTION__,__LINE__); + ret = platform_device_add(rk29_snd_device); + DBG("XXXXEnter::%s--6--%d\n",__FUNCTION__,__LINE__); + if (ret) { + DBG("platform device add failed\n"); + platform_device_put(rk29_snd_device); + return ret; + } + + return ret; +} +static void __exit audio_card_exit(void) +{ +//leaf 2012-7-26 if(0 == tcsi_get_value(TCSI_CODEC_ES8323)) +//leaf 2012-7-26 return; + platform_device_unregister(rk29_snd_device); + //rk29_speaker_deinit(rk29_speaker); +} + +module_init(audio_card_init); +module_exit(audio_card_exit); +/* Module information */ +MODULE_AUTHOR("rockchip"); +MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface"); +MODULE_LICENSE("GPL"); + -- 2.34.1