CX20701 USB Codec: add CX20701 support in RK3188_tb_sdk
authorzhangjun <zhangjun@rock-chips.com>
Tue, 17 Sep 2013 07:14:22 +0000 (15:14 +0800)
committerzhangjun <zhangjun@rock-chips.com>
Tue, 17 Sep 2013 07:14:22 +0000 (15:14 +0800)
13 files changed:
arch/arm/mach-rk30/board-rk3168-tb.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/cx2070x-i2c.h [new file with mode: 0644]
sound/soc/codecs/cx2070x.c [new file with mode: 0644]
sound/soc/codecs/cx2070x.h [new file with mode: 0644]
sound/soc/codecs/cxdebug.c [new file with mode: 0644]
sound/soc/codecs/cxdebug.h [new file with mode: 0644]
sound/soc/codecs/cxpump.c [new file with mode: 0644]
sound/soc/codecs/cxpump.h [new file with mode: 0644]
sound/soc/rk29/Kconfig
sound/soc/rk29/Makefile
sound/soc/rk29/rk29_cx2070x.c [new file with mode: 0644]

index c32a63e322c4967b6a483114a7a85e87f706d9ed..09709ba14ca010c2691433260ac9b4f69ac6f4a5 100755 (executable)
@@ -1630,6 +1630,13 @@ static struct i2c_board_info __initdata i2c0_info[] = {
         },
 #endif
 
+#if defined (CONFIG_SND_SOC_CX2070X)
+        {
+                .type                   = "cx2070x",
+                .addr                   = 0x14,
+                .flags                  = 0,
+        },
+#endif
 
 #if defined (CONFIG_SND_SOC_RT5640) 
            {
index b978303b0ebcf5904a78239a9dd9a7c915ae8d20..4ef07128b60c141563c0f2462f28f3575e52a82b 100755 (executable)
@@ -115,6 +115,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
        select SND_SOC_WM9712 if SND_SOC_AC97_BUS
        select SND_SOC_WM9713 if SND_SOC_AC97_BUS
+       select SND_SOC_CX2070X if SND_SOC_I2C_AND_SPI
         help
           Normally ASoC codec drivers are only built if a machine driver which
           uses them is also built since they are only usable with a machine
@@ -478,3 +479,5 @@ config SND_SOC_RK3026
 
 config SND_SOC_RT5512
        tristate
+config SND_SOC_CX2070X
+       tristate        
index 849b837570ad8eada7aae15b1442e67fc8fdd777..c52948c0f4a450545cb7821a7565c92bb546d7db 100755 (executable)
@@ -104,6 +104,7 @@ snd-soc-rk2928-objs := rk2928_codec.o
 snd-soc-rk3026-objs := rk3026_codec.o
 snd-soc-rt5639-objs := rt5639.o rt5639_ioctl.o rt56xx_ioctl.o 
 snd-soc-rt5512-objs := rt5512.o
+snd-soc-cx2070x-objs := cx2070x.o cxdebug.o cxpump.o
 
 # Amp
 snd-soc-lm4857-objs := lm4857.o
@@ -217,6 +218,7 @@ obj-$(CONFIG_SND_SOC_RK616) += snd-soc-rk616.o
 obj-$(CONFIG_SND_SOC_RK2928)   += snd-soc-rk2928.o
 obj-$(CONFIG_SND_SOC_RK3026)   += snd-soc-rk3026.o
 obj-$(CONFIG_SND_SOC_RT5512)   += snd-soc-rt5512.o
+obj-$(CONFIG_SND_SOC_CX2070X)   += snd-soc-cx2070x.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_LM4857)   += snd-soc-lm4857.o
diff --git a/sound/soc/codecs/cx2070x-i2c.h b/sound/soc/codecs/cx2070x-i2c.h
new file mode 100644 (file)
index 0000000..096fc8f
--- /dev/null
@@ -0,0 +1,411 @@
+/*          
+ *  Cx2070x ASoc codec driver.   
+ *
+ * Copyright:   (C) 2010/2011 Conexant Systems
+ *
+ * Based on sound/soc/codecs/tlv320aic2x.c by Vladimir Barinov
+ *
+ * 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.
+ *
+ * The software is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY 
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with 
+ * this software.  If not, see <http//www.gnu.org/licenses/>
+ *
+ * All copies of the software must include all unaltered copyright notices, 
+ * disclaimers of warranty, all notices that refer to the General Public License 
+ * and the absence of any warranty.
+ *
+ *  History
+ *  Added support for CX2070x codec [www.conexant.com]
+*/
+
+
+// force to enable TX/RX on 2nd PCM interface.
+
+#ifndef _PASS1_COMPLETE_
+# ifdef CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_3_13F
+# endif
+# ifdef CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_4_30F
+# endif
+#endif
+
+  __REG(PLAYBACK_REGISTER, 0xffff, 0xffff, 0x00, 0, DM, B)
+  __REG(CAPTURE_REGISTER, 0xffff, 0xffff, 0x00, 0, DM, B)
+  __REG(MICBIAS_REGISTER, 0xffff, 0xffff, 0x00, 0, DM, B)
+
+/////////////////////////////////////////////////////////////////////////
+//  General codec operations registers
+/////////////////////////////////////////////////////////////////////////
+//      id                                     addr    data     bias type
+  __REG(ABORT_CODE,                    0x1000, 0x1000, 0x00,       0, RO,B)
+  __REG(FIRMWARE_VERSION,              0x1001, 0x1001, 0x00,       0, RO,W)
+  __REG(PATCH_VERSION,                 0x1003, 0x1003, 0x00,       0, RO,W)
+  __REG(CHIP_VERSION,                  0x1005, 0x1005, 0x00,       0, RO,B)
+  __REG(RELEASE_TYPE,                  0x1006, 0x1006, 0x00,       0, RO,B)
+
+  __REG(ROM_PATCH_VER_HB,              0x1584, 0xFFFF, 0x00,       0, RO,B)
+  __REG(ROM_PATCH_VER_MB,              0x1585, 0xFFFF, 0x00,       0, RO,B)
+  __REG(ROM_PATCH_VER_LB,              0x1586, 0xFFFF, 0x00,       0, RO,B)
+  
+  __REG(DAC1_GAIN_LEFT,                        0x100D, 0x100D, 0xc9,    0x4A, RW,B)
+  __REG(DAC2_GAIN_RIGHT,               0x100E, 0x100E, 0xc9,    0x4A, RW,B)
+  __REG(DSP_MAX_VOLUME,                        0x100F, 0x100F, 0x00,       0, RW,B)
+
+  __REG(CLASS_D_GAIN,                  0x1011, 0x1010, b_00000000, 0, RW,B)
+#ifndef _PASS1_COMPLETE_
+#define CLASS_D_GAIN_2W8                               b_00000000      // 2.8W
+#define CLASS_D_GAIN_2W6                               b_00000001      // 2.6W
+#define CLASS_D_GAIN_2W5                               b_00000010      // 2.5W
+#define CLASS_D_GAIN_2W4                               b_00000011      // 2.4W
+#define CLASS_D_GAIN_2W3                               b_00000100      // 2.3W
+#define CLASS_D_GAIN_2W2                               b_00000101      // 2.2W
+#define CLASS_D_GAIN_2W1                               b_00000110      // 2.1W
+#define CLASS_D_GAIN_2W0                               b_00000111      // 2.0W
+#define CLASS_D_GAIN_1W3                               b_00001000      // 1.3W
+#define CLASS_D_GAIN_1W25                              b_00001001      // 1.25W
+#define CLASS_D_GAIN_1W2                               b_00001010      // 1.2W
+#define CLASS_D_GAIN_1W15                              b_00001011      // 1.15W
+#define CLASS_D_GAIN_1W1                               b_00001100      // 1.1W
+#define CLASS_D_GAIN_1W05                              b_00001101      // 1.05W
+#define CLASS_D_GAIN_1W0                               b_00001110      // 1.0W
+#define CLASS_D_GAIN_0W9                               b_00001111      // 0.9W
+#endif
+
+  __REG(DAC3_GAIN_SUB,                 0x1012, 0x1011, 0x00,    0x4A, RW,B)
+
+  __REG(ADC1_GAIN_LEFT,                        0x1013, 0x1012, 0x00,    0x4A, RW,B)
+  __REG(ADC1_GAIN_RIGHT,               0x1014, 0x1013, 0x00,    0x4A, RW,B)
+  __REG(ADC2_GAIN_LEFT,                        0x1015, 0x1014, 0x00,    0x4A, RW,B)
+  __REG(ADC2_GAIN_RIGHT,               0x1016, 0x1015, 0x00,    0x4A, RW,B)
+  __REG(DSP_MAX_MIC_GAIN,              0x1017, 0x1016, 0x00,       0, RW,B)
+
+  __REG(VOLUME_MUTE,                   0x1018, 0x1017, 0, 0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define LEFT_AUX_MUTE                                  b_01000000
+#define RIGH_AUX_MUTE                                  b_00100000
+#define LEFT_MIC_MUTE                                  b_00010000
+#define RIGH_MIC_MUTE                                  b_00001000
+#define SUB_SPEAKER_MUTE                               b_00000100
+#define LEFT_SPEAKER_MUTE                              b_00000010
+#define RIGH_SPEAKER_MUTE                              b_00000001
+#define VOLUME_MUTE_ALL                                        b_01111111
+#endif
+
+//since the playback path is determined in register value,we have to enable one port. 
+  __REG(OUTPUT_CONTROL,                        0x1019, 0x1018, b_10000000, 0, WC,B)  //class -d is selected by default. 
+#ifndef _PASS1_COMPLETE_
+#define OUT_CTRL_AUTO                                  b_10000000      // Automatic FW Control base on Jack Sense and DAC enables, 1= Auto, 0= Manual
+#define OUT_CTRL_SUB_DIFF                              b_01000000      // Sub Differential control, 1=Differential, 0=Single Ended
+#define OUT_CTRL_LO_DIFF                               b_00100000      // Line Out Differential control, 1=Differential, 0=Single Ended
+#define OUT_CTRL_CLASSD_OUT                            b_00010000      // ClassD Output, 1=PWM, 0=Speakers
+#define OUT_CTRL_CLASSD_MONO                    b_00001000     // ClassD Mono, 1=Mono, 0=Stereo
+#define OUT_CTRL_CLASSD_EN                             b_00000100      // If OutCTL[7]=0, 1=Enable ClassD Speakers, 0=Disable ClassD Speakers
+#define OUT_CTRL_LO_EN                                 b_00000010      // If OutCTL[7]=0, 1=Enable Line Out, 0=Disable Line Out
+#define OUT_CTRL_HP_EN                                 b_00000001      // If OutCTL[7]=0, 1=Enable Headphone, 0=Disable Headphone
+#endif
+
+  __REG(INPUT_CONTROL,                 0x101A, 0x1019, b_10000000, 0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define IN_CTRL_AUTO                                   b_10000000      // Automatic FW Control base on Jack Sense and ADC enables, 1=Auto, 0=Manual
+#define IN_CTRL_L1_DIFF                                        b_00001000      // Line In 1 Differential control, 1=Differential, 0=Single Ended
+#define IN_CTRL_L3_EN                                  b_00000100      // If LineCTL[7]=0, 1=Enable Line In 3, 0=Disable Line In 3
+#define IN_CTRL_L2_EN                                  b_00000010      // If LineCTL[7]=0, 1=Enable Line In 2, 0=Disable Line In 2
+#define IN_CTRL_L1_EN                                  b_00000001      // If LineCTL[7]=0, 1=Enable Line In 1, 0=Disable Line In 1
+#endif
+
+  __REG(LINE1_GAIN,                    0x101B, 0x101A, b_00000000, 0, RW,B)
+#ifndef _PASS1_COMPLETE_
+#define LINE1_MUTE                                     b_10000000      // 1=mute, 0=unmute
+#define LINE1_GAIN_MASK                                        b_00011111      // range 0x00-0x1F (-35.5dB to +12dB)
+#endif
+
+  __REG(LINE2_GAIN,                    0x101C, 0x101B, b_00000000, 0, RW,B)
+#ifndef _PASS1_COMPLETE_
+#define LINE2_MUTE                                     b_10000000      // 1=mute, 0=unmute
+#define LINE2_GAIN_MASK                                        b_00011111      // range 0x00-0x1F (-35.5dB to +12dB)
+#endif
+
+  __REG(LINE3_GAIN,                    0x101D, 0x101C, b_00000000, 0, RW,B)
+#ifndef _PASS1_COMPLETE_
+#define LINE3_MUTE                                     b_10000000      // 1=mute, 0=unmute
+#define LINE3_GAIN_MASK                                        b_00011111      // range 0x00-0x1F (-35.5dB to +12dB)
+#endif
+
+  __REG(MIC_CONTROL,                   0x101E, 0x101D, b_00000110, 0, WC,B)
+#ifndef _PASS1_COMPLETE_
+#define MICROPHONE_POWER_ALWAYS                                b_00010000      // 1 = leave microphone and bias always on to avoid pops (burns power), 0 = microphone powered up as needed, mute for 400ms to remove pops
+#define        MICROPHONE_BIAS SELECT                          b_00001000      // 1= 80%, 0= 50%
+#define        MICROPHONE_BOOST_MASK                           b_00000111      // 2:0 MicCTL [2:0]     Microphone Boost in 6dB Steps, 0= 0dB, 7= +42dB
+#endif
+
+#if defined(CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_3_13E)
+// adc
+  __REG(STREAM1_MIX,                   0xffff, 0x101E, b_00000000, 0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define STREAM1_MUTE                                   b_10000000      // 1=mute, 0=unmute
+#define STREAM1_GAIN_MASK                              b_00011111      // range 0x00-0x4A (0dB to -74dB)
+#endif
+// i2s
+  __REG(STREAM3_MIX,                   0xffff, 0x101F, b_00000000, 0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define STREAM3_MUTE                                   b_10000000      // 1=mute, 0=unmute
+#define STREAM3_GAIN_MASK                              b_00011111      // range 0x00-0x4A (0dB to -74dB)
+#endif
+// usb?
+  __REG(STREAM4_MIX,                   0xffff, 0x1020, b_00000000, 0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define STREAM4_MUTE                                   b_10000000      // 1=mute, 0=unmute
+#define STREAM4_GAIN_MASK                              b_00011111      // range 0x00-0x4A (0dB to -74dB)
+#endif
+#endif
+#if defined(CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_4_30F)
+  __REG(MIX0_INPUT0,                   0x101F, 0xffff, b_00000000, 0, WI,B)    // stream1 out
+  __REG(MIX0_INPUT1,                   0x1020, 0xffff, b_00000000, 0, WI,B)    // stream3 out
+  __REG(MIX0_INPUT2,                   0x1021, 0xffff, b_00000000, 0, WI,B)    // stream4 out
+  __REG(MIX0_INPUT3,                   0x1022, 0xffff, b_10000000, 0, WI,B)    // none
+  __REG(MIX1_INPUT0,                   0x1023, 0xffff, b_10000000, 0, WI,B)    // none
+  __REG(MIX1_INPUT1,                   0x1024, 0xffff, b_10000000, 0, WI,B)    // none
+  __REG(MIX1_INPUT2,                   0x1025, 0xffff, b_10000000, 0, WI,B)    // none
+  __REG(MIX1_INPUT3,                   0x1026, 0xffff, b_10000000, 0, WI,B)    // nonw
+  __REG(MIX0_SOURCE0,                  0x1184, 0xffff, b_00000000, 0, WI,B)    // stream1 out
+  __REG(MIX0_SOURCE1,                  0x1185, 0xffff, b_00000011, 0, WI,B)    // stream3 out
+  __REG(MIX0_SOURCE2,                  0x1186, 0xffff, b_00000100, 0, WI,B)    // stream4 out
+  __REG(MIX0_SOURCE3,                  0x1187, 0xffff, b_00000000, 0, WI,B)    // none
+  __REG(MIX1_SOURCE0,                  0x1188, 0xffff, b_00000001, 0, WI,B)    // none
+  __REG(MIX1_SOURCE1,                  0x1189, 0xffff, b_00000000, 0, WI,B)    // none
+  __REG(MIX1_SOURCE2,                  0x118a, 0xffff, b_00000000, 0, WI,B)    // none
+  __REG(MIX1_SOURCE3,                  0x118b, 0xffff, b_00000000, 0, WI,B)    // none
+  __REG(VOICE_IN_SOURCE,               0x118c, 0xffff, b_00000010, 0, WI,B)    // stream2
+  //__REG(VOICE_IN_SOURCE,             0x118c, 0xffff, 0x04, 0, WI,B)  // stream2
+#endif
+
+/////////////////////////////////////////////////////////////////////////
+// Hardware registers
+/////////////////////////////////////////////////////////////////////////
+//      id                                     addr    data     bias type
+//  __REG(CLOCK_DIVIDER,                       0x0F50, 0x0F50, b_00001111, 0, WI,B)  // Port1 external clock enabled
+    __REG(CLOCK_DIVIDER,                       0x0F50, 0x0F50, 0xFF, 0, WI,B)  // Port1 slave, Port2 Master 2.048 MHz
+#ifndef _PASS1_COMPLETE_
+#define PORT2_DIV_SEL_6_144MHz                         b_00000000      // 0x0 = 6.144 MHz
+#define PORT2_DIV_SEL_4_096MHz                         b_00010000      // 0x1 = 4.096 MHz
+#define PORT2_DIV_SEL_3_072MHz                         b_00100000      // 0x2 = 3.072 MHz
+#define PORT2_DIV_SEL_2_048MHz                         b_00110000      // 0x3 = 2.048 MHz
+#define PORT2_DIV_SEL_1_536MHz                         b_01000000      // 0x4 = 1.536 MHz
+#define PORT2_DIV_SEL_1_024MHz                         b_01010000      // 0x5 = 1.024 MHz
+#define PORT2_DIV_SEL_768kHz                           b_01100000      // 0x6 = 768kHz
+#define PORT2_DIV_SEL_512kHz                           b_01110000      // 0x7 = 512 kHz
+#define PORT2_DIV_SEL_384kHz                           b_10000000      // 0x8 = 384 kHz
+#define PORT2_DIV_SEL_256kHz                           b_10010000      // 0x9 = 256 kHz
+#define PORT2_DIV_SEL_5_644MHz                         b_10100000      // 0xa = 5.644 MHz
+#define PORT2_DIV_SEL_2_822MHz                         b_10110000      // 0xb = 2.822 MHz
+#define PORT2_DIV_SEL_1_411MHz                         b_11000000      // 0xc = 1.411 MHz
+#define PORT2_DIV_SEL_705kHz                           b_11010000      // 0xd = 705 kHz
+#define PORT2_DIV_SEL_352kHz                           b_11100000      // 0xe = 352 kHz
+#define PORT2_DIV_SEL_EXT                              b_11110000      // 0xf = external clock enabled
+#define PORT1_DIV_SEL_6_144MHz                         b_00000000      // 0x0 = 6.144 MHz
+#define PORT1_DIV_SEL_4_096MHz                         b_00000001      // 0x1 = 4.096 MHz
+#define PORT1_DIV_SEL_3_072MHz                         b_00000010      // 0x2 = 3.072 MHz
+#define PORT1_DIV_SEL_2_048MHz                         b_00000011      // 0x3 = 2.048 MHz
+#define PORT1_DIV_SEL_1_536MHz                         b_00000100      // 0x4 = 1.536 MHz
+#define PORT1_DIV_SEL_1_024MHz                         b_00000101      // 0x5 = 1.024 MHz
+#define PORT1_DIV_SEL_768kHz                           b_00000110      // 0x6 = 768kHz
+#define PORT1_DIV_SEL_512kHz                           b_00000111      // 0x7 = 512 kHz
+#define PORT1_DIV_SEL_384kHz                           b_00001000      // 0x8 = 384 kHz
+#define PORT1_DIV_SEL_256kHz                           b_00001001      // 0x9 = 256 kHz
+#define PORT1_DIV_SEL_5_644MHz                         b_00001010      // 0xa = 5.644 MHz
+#define PORT1_DIV_SEL_2_822MHz                         b_00001011      // 0xb = 2.822 MHz
+#define PORT1_DIV_SEL_1_411MHz                         b_00001100      // 0xc = 1.411 MHz
+#define PORT1_DIV_SEL_705kHz                           b_00001101      // 0xd = 705 kHz
+#define PORT1_DIV_SEL_352kHz                           b_00001110      // 0xe = 352 kHz
+#define PORT1_DIV_SEL_EXT                              b_00001111      // 0xf = external clock enabled
+#endif
+
+  __REG(PORT1_CONTROL,                 0x0F51, 0x0F51, b_10110000, 0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define PORT1_DELAY                                    b_10000000      // 1=Data delayed 1 bit (I2S standard), 0=no delay (sony mode)
+#define PORT1_JUSTR_LSBF                       b_01000000      // [1/0]=Right/Left Justify (I2S) or LSB/MSB First (PCM)
+#define PORT1_RX_EN                                    b_00100000      // 1=RX Clock Enable, 0=RX Clock Disabled
+#define PORT1_TX_EN                                    b_00010000      // 1=TX Clock Enable, 0=TX Clock Disabled
+//#define PORT1_                                       b_00001000      //
+#define PORT1_BITCLK_POL                               b_00000100      // 0=Normal clock, 1=Inverted clock
+#define PORT1_WS_POL                                   b_00000010      // 0=Rising Edge Active for Word Strobe, 1=Falling Edge Active for Word Strobe
+#define PORT1_PCM_MODE                                 b_00000001      // 0=I2S mode, 1=PCM Mode
+#endif
+
+  __REG(PORT1_TX_CLOCKS_PER_FRAME_PHASE,0x0F52,        0x0F52, b_00000011, 0, WI,B)  // clocks/frame=(N+1)*8
+  __REG(PORT1_RX_CLOCKS_PER_FRAME_PHASE,0x0F53,        0x0F53, b_00000011, 0, WI,B)  // clocks/frame=(N+1)*8
+  __REG(PORT1_TX_SYNC_WIDTH,           0x0F54, 0x0F54, b_00001111, 0, WI,B)  // clocks=(N+1)
+  __REG(PORT1_RX_SYNC_WIDTH,           0x0F55, 0x0F55, b_00001111, 0, WI,B)  // clocks=(N+1)
+
+  __REG(PORT1_CONTROL_2,               0x0F56, 0x0F56, b_00000101, 0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define PORT1_CTRL_TX_PT                               b_00100000      // Tx passthrough mode,  0=off, 1=on
+#define PORT1_CTRL_RX_PT                               b_00010000      // Rx passthrough mode,  0=off, 1=on
+#define PORT1_CTRL_RX_SIZE_8                           b_00000000      // RX Sample Size, 00=8 bits
+#define PORT1_CTRL_RX_SIZE_16                          b_00000100      // RX Sample Size, 01=16 bit
+#define PORT1_CTRL_RX_SIZE_24T                         b_00001000      // RX Sample Size, 10=24 bit truncated to 16 bits
+#define PORT1_CTRL_RX_SIZE_24                          b_00001100      // RX Sample Size, 11=24 bit
+#define PORT1_CTRL_TX_SIZE_8                           b_00000000      // TX Sample Size, 00=8 bits
+#define PORT1_CTRL_TX_SIZE_16                          b_00000001      // TX Sample Size, 01=16 bit
+#define PORT1_CTRL_TX_SIZE_24T                         b_00000010      // TX Sample Size, 10=24 bit truncated to 16 bits
+#define PORT1_CTRL_TX_SIZE_24                          b_00000011      // TX Sample Size, 11=24 bit
+#endif
+
+/////////////////////////////////////////////////////////////////////////
+// Codec registers, most need NEWC to be set
+/////////////////////////////////////////////////////////////////////////
+//      id                                     addr    data     bias type
+  __REG(STREAM2_RATE,                  0x116b, 0xffff, 0xa2,       0, WI,B) // Mic
+#ifndef _PASS1_COMPLETE_
+#define STREAM2_STREAM_MONO_LEFT                       0x00            // 
+#define STREAM2_STREAM_MONO_RIGHT                      0x40            // 
+#define STREAM2_STREAM_STEREO                          0x80            // 
+#define STREAM2_SAMPLE_A_LAW                           0x00            // 8-bit A law
+#define STREAM2_SAMPLE_U_LAW                           0x10            // 8-bit Âµ law
+#define STREAM2_SAMPLE_16_LIN                          0x20            // 16 bit linear
+#define STREAM2_SAMPLE_24_LIN                          0x30            // 24 bit linear
+#define STREAM2_RATE_8000                              0x00            //  8000 samples/sec
+#define STREAM2_RATE_11025                             0x01            // 11025 samples/sec
+#define STREAM2_RATE_16000                             0x02            // 16000 samples/sec
+#define STREAM2_RATE_22050                             0x03            // 22050 samples/sec
+#define STREAM2_RATE_24000                             0x04            // 24000 samples/sec
+#define STREAM2_RATE_32000                             0x05            // 32000 samples/sec
+#define STREAM2_RATE_44100                             0x06            // 44100 samples/sec
+#define STREAM2_RATE_48000                             0x07            // 48000 samples/sec
+#define STREAM2_RATE_88200                             0x08            // 88200 samples/sec
+#define STREAM2_RATE_96000                             0x09            // 96000 samples/sec
+#endif
+
+  __REG(STREAM5_RATE,                  0x1171, 0x112D, 0x26,       0, WI,B) // Mic -> I2S (5 wire)
+#ifndef _PASS1_COMPLETE_
+#define STREAM5_SAMPLE_A_LAW                           0x00            // 8-bit A law
+#define STREAM5_SAMPLE_U_LAW                           0x10            // 8-bit Âµ law
+#define STREAM5_SAMPLE_16_LIN                          0x20            // 16 bit linear
+#define STREAM5_SAMPLE_24_LIN                          0x30            // 24 bit linear
+#define STREAM5_RATE_8000                              0x00            //  8000 samples/sec
+#define STREAM5_RATE_11025                             0x01            // 11025 samples/sec
+#define STREAM5_RATE_16000                             0x02            // 16000 samples/sec
+#define STREAM5_RATE_22050                             0x03            // 22050 samples/sec
+#define STREAM5_RATE_24000                             0x04            // 24000 samples/sec
+#define STREAM5_RATE_32000                             0x05            // 32000 samples/sec
+#define STREAM5_RATE_44100                             0x06            // 44100 samples/sec
+#define STREAM5_RATE_48000                             0x07            // 48000 samples/sec
+#define STREAM5_RATE_88200                             0x08            // 88200 samples/sec
+#define STREAM5_RATE_96000                             0x09            // 96000 samples/sec
+#endif
+
+  __REG(STREAM3_RATE,                  0x116D, 0x112F, 0xA6,       0, WI,B) // 44.1kHz, 16 bit linear
+#ifndef _PASS1_COMPLETE_
+#define STREAM3_STREAM_MONO_LEFT                       0x00            // 
+#define STREAM3_STREAM_MONO_RIGHT                      0x40            // 
+#define STREAM3_STREAM_STEREO                          0x80            // 
+#define STREAM3_SAMPLE_A_LAW                           0x00            // 8-bit A law
+#define STREAM3_SAMPLE_U_LAW                           0x10            // 8-bit Âµ law
+#define STREAM3_SAMPLE_16_LIN                          0x20            // 16 bit linear
+#define STREAM3_SAMPLE_24_LIN                          0x30            // 24 bit linear
+#define STREAM3_RATE_8000                              0x00            //  8000 samples/sec
+#define STREAM3_RATE_11025                             0x01            // 11025 samples/sec
+#define STREAM3_RATE_16000                             0x02            // 16000 samples/sec
+#define STREAM3_RATE_22050                             0x03            // 22050 samples/sec
+#define STREAM3_RATE_24000                             0x04            // 24000 samples/sec
+#define STREAM3_RATE_32000                             0x05            // 32000 samples/sec
+#define STREAM3_RATE_44100                             0x06            // 44100 samples/sec
+#define STREAM3_RATE_48000                             0x07            // 48000 samples/sec
+#define STREAM3_RATE_88200                             0x08            // 88200 samples/sec
+#define STREAM3_RATE_96000                             0x09            // 96000 samples/sec
+#endif
+
+  __REG(STREAM_3_ROUTING,              0x116E, 0x1130, 0x02,       0, WI,B)
+#ifndef _PASS1_COMPLETE_
+#define STREAM3_ROUTE_SRC_D1                           0x00          // Source = Digital Port1
+#define STREAM3_ROUTE_SRC_D2                           0x10          // Source = Digital Port2
+#define STREAM3_ROUTE_DST_D1                           0x00          // Destination = Digital Port1
+#define STREAM3_ROUTE_DST_D2                           0x01          // Destination = Digital Port2
+#define STREAM3_ROUTE_DST_DAC                          0x02          // Destination = DAC
+#define STREAM3_ROUTE_DST_SUB                          0x03          // Destination = DAC (sub)
+#define STREAM3_ROUTE_DST_SPDIF                                0x04          // Destination = SPDIF
+#define STREAM3_ROUTE_DST_USB                          0x05          // Destination = USB
+#endif
+
+  __REG(EQ_GAIN,                       0x10D7, 0x10D1, 0x1000,     0, WI,W)
+  __REG(EQS_GAIN,                      0x10D9, 0x10D3, 0x1000,     0, WI,W)
+
+//  __REG(SPDIF_CODE,                  0x1178, 0x1134, 0x00,       0, WI,B)
+//  __REG(SPDIF_CONTROL,               0x1179, 0x1135, 0x00,       0, WI,B)
+
+  __REG(DSP_PROCESSING_ENABLE_1,       0x117A, 0x1136, 0x00,       0, WC,B)
+#ifndef _PASS1_COMPLETE_
+#define        RIGHT_MIKE                                      b_01000000
+#define        IN_NOISE_REDUCTION                              b_00100000
+#define        MIC_AGC                                         b_00010000
+#define        BEAM_FORMING                                    b_00001000
+#define        NOICE_REDUCTION                                 b_00000100
+#define        LEC                                             b_00000010
+#define        AEC                                             b_00000001
+#endif
+  __REG(DSP_PROCESSING_ENABLE_2,       0x117B, 0x1137, 0x00,       0, WC,B)
+#ifndef _PASS1_COMPLETE_
+#define        DSP_MONO_OUTPUT                                 b_00100000      // 0=Stereo, 1=Mono (L+R)=L (L+R)=R
+#define        LOUDNESS_ADAPTER                                b_00010000      // 1=Enable, 0=Disable
+#define        STAGE_ENHANCER                                  b_00001000      // 1=Enable 3D processing, 0=Disable
+#define        DYNAMIC_RANGE_COMPRESSION                       b_00000100      // 1=Enable, 0=Disable
+#define        SUBWOOFER_CROSSOVER                             b_00000010      // 1=Enable, 0=Disable
+#define        EQUALIZER_10_BAND                               b_00000001      // 1=Enable, 0=Disable
+#endif
+
+#if defined(CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_4_30F)
+  __REG(DSP_INIT_H,                    0x117C, 0xffff, 0x00,       0, WI,B) // special
+  __REG(DSP_INIT,                      0x117D, 0xffff, 0x00,       0, WC,B) // special
+  __REG(DSP_POWER,                     0x117E, 0xffff, 0xE0,       0, WC,B) // special
+
+#ifndef _PASS1_COMPLETE_
+#define DSP_INIT_NEWC                                  b_00000001
+#define DSP_INIT_STREAM_OFF                            b_00000001
+#define DSP_INIT_STREAM_3                              b_10001001      // enable stream 3 and 7
+#define DSP_INIT_STREAM_5                              b_00100101      // enable stream 2 and 5
+#define DSP_INIT_STREAM_5_3                            b_10101101      // enable streams 2,3,5,7
+#endif
+#else
+  __REG(DSP_INIT,                      0xffff, 0x1138, 0x00,       0, WI,B) // special
+#ifndef _PASS1_COMPLETE_000000000000000000000000
+#define DSP_INIT_NEWC                                  b_00000001
+#define DSP_INIT_STREAM_OFF                            b_00000001
+#define DSP_INIT_STREAM_3                              b_00001001
+#define DSP_INIT_STREAM_5                              b_00100001
+#define DSP_INIT_STREAM_5_3                            b_00101001
+#endif
+#endif
+
+#ifdef CX20709_TRISTATE_EEPROM
+  __REG(PAD,                           0x0004, 0x0004, 0x00,       0, WO,B)
+  __REG(PBD,                           0x0005, 0x0005, 0x00,       0, W0,B)
+#endif
+// temp code.
+//  added rerouting render stream to second I2S output ( 16 Kbps/ 16BITS)
+  __REG(STREAM4_RATE,                  0x116F, 0xffff, 0xA7,       0, WI,B) // dsp -> PCM-2 8Kbps output
+  __REG(STREAM4_ROUTING,               0x1170, 0xffff, 0x12,       0, WI,B)
+  __REG(STREAM6_RATE,                  0x1172, 0xffff, 0x27,       0, WI,B) // dsp -> PCM-2 8Kbps output
+  __REG(STREAM7_RATE,                  0x1173, 0xffff, 0x07,       0, WC,B) // dsp -> I2S-2 (5 wire)
+  __REG(STREAMOP_ROUTING,              0x1176, 0xffff, 0x60,       0, WC,B) // AEC narrow band. 48 KHz
+  __REG(STREAM6_ROUTING,               0x1182, 0xffff, 0x06,       0, WI,B)
+  __REG(STREAM7_SOURCE,                        0x117F, 0xffff, 0x05,       0, WI,B) // dsp -> I2S-2 (5 wire)
+  __REG(STREAM8_SOURCE,         0x1180, 0xffff, 0x05,        0, WC,B)
+  __REG(STREAM8_RATE,                  0x1175, 0xffff, 0x07,       0, WC,B) 
+  __REG(PORT2_CONTROL,                 0x0F5E, 0x0F5E, 0XB0,        0, WI,B)  // Delay 1 bit, RX/TX en, mode =i2s
+  __REG(PORT2_CLOCK_PER_FRAME,         0x0F5F, 0x0F5F, 0X07,        0, WI,B)  // 64-bits per frame.
+  __REG(PORT2_SYNC_WIDTH,                      0x0F60, 0x0F60, 0X0f,        0, WI,B)  // clocks=(N+1)
+  __REG(PORT2_SAMPLE_WIDTH,            0x0F61, 0x0F61, 0X01,        0, WI,B)  // 16 bits.
+  __REG(PORT2_RX_STREAM1,              0x0F62, 0x0F62, 0X20,        0, WI,B)  // RX 1 <- Slot 0
+  __REG(PORT2_RX_STREAM2,              0x0F63, 0x0F63, 0X24,        0, WI,B)  // RX 2 <- Slot 4
+  __REG(PORT2_TX_STREAM1,              0x0F65, 0x0F65, 0X20,        0, WI,B)  // TX 1 -> Slot 0
+  __REG(PORT2_TX_STREAM2,              0x0F66, 0x0F66, 0X24,        0, WI,B)  // TX 2 -> Slot 4
+
+#ifndef _PASS1_COMPLETE_
+#define _PASS1_COMPLETE_
+#endif
diff --git a/sound/soc/codecs/cx2070x.c b/sound/soc/codecs/cx2070x.c
new file mode 100644 (file)
index 0000000..6c4e840
--- /dev/null
@@ -0,0 +1,2041 @@
+/*
+* ALSA SoC CX2070X codec driver
+*
+* Copyright:   (C) 2009/2010 Conexant Systems
+*
+* Based on sound/soc/codecs/tlv320aic2x.c by Vladimir Barinov
+*
+* 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.
+*
+* 
+*      
+*************************************************************************
+*  Modified Date:  09/14/12
+*  File Version:   3.1.10.13
+*************************************************************************
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/gpio.h>
+#include <sound/jack.h>
+#include <linux/slab.h>
+
+#include "cx2070x.h"
+
+#define CX2070X_DRIVER_VERSION AUDDRV_VERSION( 3, 1 ,0x10 ,0x13) 
+
+#ifdef USING_I2C
+#include <linux/i2c.h>
+#endif 
+
+#ifdef USING_SPI 
+#include <linux/spi/spi.h>
+#endif 
+
+#if defined(CONFIG_SND_CXLIFEGUARD)
+#include "cxdebug.h"
+#endif 
+
+#ifdef CONFIG_SND_CX2070X_LOAD_FW
+#ifdef CONFIG_SND_CX2070X_USE_FW_H
+#include "cx2070x_fw.h"
+#else
+#include <linux/firmware.h>
+#endif
+#include "cxpump.h" 
+#endif
+
+
+#define CX2070X_TRISTATE_EEPROM        0
+#define CX2070X_REG_NAMES      1
+#define CX2070X_REG_WIDE       1
+
+
+#define AUDIO_NAME     "cx2070x"
+
+
+#define CX2070X_RATES  ( \
+       SNDRV_PCM_RATE_8000  \
+    | SNDRV_PCM_RATE_11025 \
+    | 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 )
+    
+#if defined(CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_4_30F)
+
+#define CX2070X_FORMATS ( SNDRV_PCM_FMTBIT_S16_LE \
+    | SNDRV_PCM_FMTBIT_S16_BE \
+    | SNDRV_PCM_FMTBIT_MU_LAW \
+    | SNDRV_PCM_FMTBIT_A_LAW )
+#else
+#define CX2070X_FORMATS ( SNDRV_PCM_FMTBIT_S16_LE \
+    | SNDRV_PCM_FMTBIT_S16_BE )
+#endif
+
+
+
+#define noof(a) (sizeof(a)/sizeof(a[0]))
+#define NOINLINE __attribute__((__noinline__))
+//#ifdef DEBUG
+#if 1
+# define INFO(fmt,...) printk(KERN_INFO fmt, ##__VA_ARGS__)
+# define _INFO(fmt,...)        printk(KERN_INFO fmt, ##__VA_ARGS__)
+# define _INFO_                1
+#else
+# define INFO(fmt,...) 
+# define _INFO(fmt,...)
+# define _INFO_                1
+#endif
+#define MSG(fmt,...)   printk(KERN_INFO fmt, ##__VA_ARGS__)
+#define ERROR(fmt,...) printk(KERN_ERR fmt, ##__VA_ARGS__)
+
+enum {
+    b_00000000,b_00000001,b_00000010,b_00000011, b_00000100,b_00000101,b_00000110,b_00000111,
+    b_00001000,b_00001001,b_00001010,b_00001011, b_00001100,b_00001101,b_00001110,b_00001111,
+    b_00010000,b_00010001,b_00010010,b_00010011, b_00010100,b_00010101,b_00010110,b_00010111,
+    b_00011000,b_00011001,b_00011010,b_00011011, b_00011100,b_00011101,b_00011110,b_00011111,
+    b_00100000,b_00100001,b_00100010,b_00100011, b_00100100,b_00100101,b_00100110,b_00100111,
+    b_00101000,b_00101001,b_00101010,b_00101011, b_00101100,b_00101101,b_00101110,b_00101111,
+    b_00110000,b_00110001,b_00110010,b_00110011, b_00110100,b_00110101,b_00110110,b_00110111,
+    b_00111000,b_00111001,b_00111010,b_00111011, b_00111100,b_00111101,b_00111110,b_00111111,
+    b_01000000,b_01000001,b_01000010,b_01000011, b_01000100,b_01000101,b_01000110,b_01000111,
+    b_01001000,b_01001001,b_01001010,b_01001011, b_01001100,b_01001101,b_01001110,b_01001111,
+    b_01010000,b_01010001,b_01010010,b_01010011, b_01010100,b_01010101,b_01010110,b_01010111,
+    b_01011000,b_01011001,b_01011010,b_01011011, b_01011100,b_01011101,b_01011110,b_01011111,
+    b_01100000,b_01100001,b_01100010,b_01100011, b_01100100,b_01100101,b_01100110,b_01100111,
+    b_01101000,b_01101001,b_01101010,b_01101011, b_01101100,b_01101101,b_01101110,b_01101111,
+    b_01110000,b_01110001,b_01110010,b_01110011, b_01110100,b_01110101,b_01110110,b_01110111,
+    b_01111000,b_01111001,b_01111010,b_01111011, b_01111100,b_01111101,b_01111110,b_01111111,
+    b_10000000,b_10000001,b_10000010,b_10000011, b_10000100,b_10000101,b_10000110,b_10000111,
+    b_10001000,b_10001001,b_10001010,b_10001011, b_10001100,b_10001101,b_10001110,b_10001111,
+    b_10010000,b_10010001,b_10010010,b_10010011, b_10010100,b_10010101,b_10010110,b_10010111,
+    b_10011000,b_10011001,b_10011010,b_10011011, b_10011100,b_10011101,b_10011110,b_10011111,
+    b_10100000,b_10100001,b_10100010,b_10100011, b_10100100,b_10100101,b_10100110,b_10100111,
+    b_10101000,b_10101001,b_10101010,b_10101011, b_10101100,b_10101101,b_10101110,b_10101111,
+    b_10110000,b_10110001,b_10110010,b_10110011, b_10110100,b_10110101,b_10110110,b_10110111,
+    b_10111000,b_10111001,b_10111010,b_10111011, b_10111100,b_10111101,b_10111110,b_10111111,
+    b_11000000,b_11000001,b_11000010,b_11000011, b_11000100,b_11000101,b_11000110,b_11000111,
+    b_11001000,b_11001001,b_11001010,b_11001011, b_11001100,b_11001101,b_11001110,b_11001111,
+    b_11010000,b_11010001,b_11010010,b_11010011, b_11010100,b_11010101,b_11010110,b_11010111,
+    b_11011000,b_11011001,b_11011010,b_11011011, b_11011100,b_11011101,b_11011110,b_11011111,
+    b_11100000,b_11100001,b_11100010,b_11100011, b_11100100,b_11100101,b_11100110,b_11100111,
+    b_11101000,b_11101001,b_11101010,b_11101011, b_11101100,b_11101101,b_11101110,b_11101111,
+    b_11110000,b_11110001,b_11110010,b_11110011, b_11110100,b_11110101,b_11110110,b_11110111,
+    b_11111000,b_11111001,b_11111010,b_11111011, b_11111100,b_11111101,b_11111110,b_11111111,
+};
+
+#define REG_TYPE_RO    0       // read only,  read during initialization
+#define REG_TYPE_RW    1       // read/write, read during initialization
+#define REG_TYPE_WI    2       // write only, written during initialization
+#define REG_TYPE_WC    3       // write/init, needs NEWC to be set when written
+#define REG_TYPE_DM    4       // dummy register, read/write to cache only
+#if CX2070X_REG_WIDE
+# define REG_TYPE_MASK 0x0F
+# define REG_WIDTH_B   0x00    //  8-bit data
+# define REG_WIDTH_W   0x10    // 16-bit data
+# define REG_WIDTH_MASK        0xF0
+#endif
+enum {
+#define __REG(a,b2,b1,c,d,e,f) a,
+#include "cx2070x-i2c.h"
+#undef __REG
+};
+
+#if CX2070X_REG_WIDE
+typedef u16 cx2070x_reg_t;
+#else
+typedef u8 cx2070x_reg_t;
+#endif
+static const cx2070x_reg_t cx2070x_data[]=
+{
+#define __REG(a,b2,b1,c,d,e,f) c,
+#include "cx2070x-i2c.h"
+#undef __REG
+};
+
+struct cx2070x_reg
+{
+#if CX2070X_REG_NAMES
+    char *name;
+#endif
+    u16   addr;
+    u8    bias;
+    u8    type;
+};
+
+static const struct cx2070x_reg cx2070x_regs[]=
+{
+#if defined(CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_3_13E)
+# if CX2070X_REG_NAMES
+#  define __REG(a,b2,b1,c,d,e,f) { #a,b1,d,REG_TYPE_##e|REG_WIDTH_##f },
+# else
+#  define __REG(a,b2,b1,c,d,e,f) { b1,d,REG_TYPE_##e|REG_WIDTH_##f },
+# endif
+#elif defined(CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_4_30F)
+# if CX2070X_REG_NAMES
+#  define __REG(a,b2,b1,c,d,e,f) { #a,b2,d,REG_TYPE_##e|REG_WIDTH_##f },
+# else
+#  define __REG(a,b2,b1,c,d,e,f) { b2,d,REG_TYPE_##e|REG_WIDTH_##f },
+# endif
+#else
+# if CX2070X_REG_NAMES
+#  define __REG(a,b2,b1,c,d,e,f) { #a,b2,d,REG_TYPE_##e|REG_WIDTH_##f },
+# else
+#  define __REG(a,b2,b1,c,d,e,f) { b2,d,REG_TYPE_##e|REG_WIDTH_##f },
+# endif
+#endif
+#include "cx2070x-i2c.h"
+#undef __REG
+};
+
+// codec private data
+struct cx2070x_priv
+{
+    enum snd_soc_control_type control_type;
+    void *control_data;
+    unsigned int sysclk;
+    int               master;
+    enum Cx_INPUT_SEL input_sel;
+    enum Cx_OUTPUT_SEL output_sel;
+       unsigned int mute;
+};
+
+#define get_cx2070x_priv(_codec_) ((struct cx2070x_priv *)snd_soc_codec_get_drvdata(codec))
+
+#if defined(CONFIG_CXNT_SOFTWOARE_SIMULATION)
+static int bNoHW = 1;
+#else
+static int bNoHW = 0;
+#endif 
+
+
+/*
+ * Playback Volume 
+ *
+ * max : 0x00 : 0 dB
+ *       ( 1 dB step )
+ * min : 0xB6 : -74 dB
+ */
+static const DECLARE_TLV_DB_SCALE(dac_tlv, -7400 , 100, 0);
+
+
+/*
+ * Capture Volume 
+ *
+ * max : 0x00 : 0 dB
+ *       ( 1 dB step )
+ * min : 0xB6 : -74 dB
+ */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -7400 , 100, 0);
+
+
+#if defined (CONFIG_SND_CX2070X_GPIO_JACKSENSE)
+// TODO : the jack sensing code should be moved to machine layer.
+static struct snd_soc_jack hs_jack ;
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+    {
+        /*.list_head list*/{},
+            /*.pin*/"Headphone",
+            /*.mask*/SND_JACK_HEADPHONE,
+            /*.invert*/1
+    },
+    {
+        /*.list_head list*/{},
+            /*.pin*/"INT SPK",
+            /*.mask*/SND_JACK_HEADPHONE,
+            /*.invert*/0
+    }
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+    {
+        /*.gpio*/ JACK_SENSE_GPIO_PIN,
+            /*.name*/ "hsdet-gpio",
+            /*.report*/ SND_JACK_HEADSET,
+            /*.invert*/ 0,
+            /*.debounce_time*/ 200,
+            /*.jack*/ NULL,
+            /*.work*/ NULL,
+    },
+};
+
+#endif //CONFIG_SND_CX2070X_GPIO_JACKSENSE
+
+#if defined(CONFIG_SND_CX2070X_LOAD_FW)
+int I2cWrite( struct snd_soc_codec *codec, unsigned char ChipAddr, unsigned long cbBuf, unsigned char* pBuf);
+int I2cWriteThenRead( struct snd_soc_codec *codec, unsigned char ChipAddr, unsigned long cbBuf,
+    unsigned char* pBuf, unsigned long cbReadBuf, unsigned char*pReadBuf);
+#endif 
+
+#define GET_REG_CACHE(_codec_) (cx2070x_reg_t *) (_codec_)->reg_cache
+static inline unsigned int cx2070x_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg)
+{
+    cx2070x_reg_t *reg_cache;
+    if (reg >= noof(cx2070x_regs))
+        return (unsigned int)0;
+    reg_cache  =  GET_REG_CACHE(codec);
+    return reg_cache[reg];
+}
+
+static inline void cx2070x_write_reg_cache(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+{
+    cx2070x_reg_t *reg_cache;
+    if (reg >= noof(cx2070x_regs))
+        return;
+    reg_cache=GET_REG_CACHE(codec);
+    reg_cache[reg] = value;
+}
+
+#ifdef USING_SPI
+static int NOINLINE cx2070x_real_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+{  /* SPI bus */
+    int ret;
+    u8                  data[4];
+    struct spi_device * spi =   (struct spi_device *) codec->control_data;
+    int len=0;
+    const struct cx2070x_reg *ri;
+
+    ri=&cx2070x_regs[reg];
+
+
+    switch(ri->type&REG_TYPE_MASK)
+    {
+    case REG_TYPE_RO:          // read only,  read during initialization
+#if CX2070X_REG_NAMES
+        ERROR("%s(): write to Read-only register '%s'\n",__func__,ri->name);
+#endif
+        break;
+
+    case REG_TYPE_RW:          // read/write, read during initialization
+    case REG_TYPE_WI:          // write only, written during initialization
+    case REG_TYPE_WC:          // write/init, needs NEWC to be set when written
+        // msg[0].addr  = client->addr;
+        //      msg[0].flags = client->flags & I2C_M_TEN;
+        data[0]=(u8)(ri->addr>>8);
+        data[1]=(u8)(ri->addr>>0);
+        switch(ri->type&REG_WIDTH_MASK)
+        {
+        case REG_WIDTH_B:
+            data[2]=(u8)(value-ri->bias);
+            len=3;
+            break;
+        case REG_WIDTH_W:
+            data[2]=(u8)((value-ri->bias)>>0)&0xFF;
+            data[3]=(u8)((value-ri->bias)>>8)&0xFF;
+            len=4;
+            break;
+        default:
+            return -EIO;
+        }
+        data[0] |= 0x80; //Write flag.
+#ifdef DBG_MONITOR_REG 
+        printk(KERN_ERR "Write REG %02x%02x  %02x\n",data[0],data[1],data[2]);
+#endif 
+        spi_write(spi, data, len);
+        break;
+
+#if defined(REG_TYPE_DM)
+    case REG_TYPE_DM:          // dummy register, no I2C transfers
+        break;
+#endif
+    }
+
+    cx2070x_write_reg_cache(codec,reg,value);
+    return 0;
+}
+
+static int NOINLINE cx2070x_real_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+    struct spi_device * spi =   (struct spi_device *) codec->control_data;
+    int len=0;
+
+    u8                     data[4];
+    const struct cx2070x_reg *ri;
+    int                            dat;
+    int ret;
+    ri=&cx2070x_regs[reg];
+
+    if ((ri->type&REG_TYPE_MASK)==REG_TYPE_DM)
+        return cx2070x_read_reg_cache(codec,reg);
+
+    data[0]=(u8)(ri->addr>>8);
+    data[1]=(u8)(ri->addr>>0);
+    len   = ((ri->type&REG_WIDTH_MASK)==REG_WIDTH_W)?2:1;
+    data[2] = 0;
+    if (spi_write_then_read(spi, &data[0], 3, &data[2],len))
+    {
+
+    } 
+    switch(ri->type&REG_WIDTH_MASK)
+    {
+    case REG_WIDTH_B:
+        dat=ri->bias+data[2];
+        break;
+    case REG_WIDTH_W:
+        dat=ri->bias+(data[2]<<0)+(data[3]<<8);
+        break;
+    default:
+        return -EIO;
+    }
+    cx2070x_write_reg_cache(codec,reg,dat);
+    return dat;
+}
+#else
+static int NOINLINE cx2070x_real_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+{
+    struct i2c_client  *client = (struct i2c_client  *) codec->control_data;
+    struct i2c_adapter *adap   = client->adapter;
+    struct i2c_msg      msg[2];
+    u8                  data[4];
+    const struct cx2070x_reg *ri;
+    if(reg == MIC_CONTROL)
+        printk(">>>>>>>>>>>>>%s value = %0x\n", __func__, value);
+    if(reg == MIC_CONTROL)
+        dump_stack();
+
+    ri=&cx2070x_regs[reg];
+
+    switch(ri->type&REG_TYPE_MASK)
+    {
+    case REG_TYPE_RO:          // read only,  read during initialization
+#if CX2070X_REG_NAMES
+        ERROR("%s(): write to Read-only register '%s'\n",__func__,ri->name);
+#endif
+        break;
+
+    case REG_TYPE_RW:          // read/write, read during initialization
+    case REG_TYPE_WI:          // write only, written during initialization
+    case REG_TYPE_WC:          // write/init, needs NEWC to be set when written
+        msg[0].addr  = client->addr;
+        msg[0].flags = client->flags & I2C_M_TEN;
+        msg[0].buf   = &data[0];
+        data[0]=(u8)(ri->addr>>8);
+        data[1]=(u8)(ri->addr>>0);
+        switch(ri->type&REG_WIDTH_MASK)
+        {
+        case REG_WIDTH_B:
+            data[2]=(u8)(value-ri->bias);
+            msg[0].len=3;
+            break;
+        case REG_WIDTH_W:
+            data[2]=(u8)((value-ri->bias)>>0)&0xFF;
+            data[3]=(u8)((value-ri->bias)>>8)&0xFF;
+            msg[0].len=4;
+            break;
+        default:
+            return -EIO;
+        }
+#ifdef DBG_MONITOR_REG 
+        printk(KERN_ERR "Write REG %02x%02x  %02x\n",data[0],data[1],data[2]);
+#endif 
+
+        if (i2c_transfer(adap,msg,1)!=1)
+            return -EIO;
+        break;
+
+#if defined(REG_TYPE_DM)
+    case REG_TYPE_DM:          // dummy register, no I2C transfers
+        break;
+#endif
+    }
+
+    cx2070x_write_reg_cache(codec,reg,value);
+    return 0;
+}
+
+static int NOINLINE cx2070x_real_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+    struct i2c_client     *client =(struct i2c_client  *) codec->control_data;
+    struct i2c_adapter    *adap   = client->adapter;
+    struct i2c_msg         msg[2];
+    u8                     data[4];
+    const struct cx2070x_reg *ri;
+    int                            dat;
+
+    ri=&cx2070x_regs[reg];
+
+    if ((ri->type&REG_TYPE_MASK)==REG_TYPE_DM)
+        return cx2070x_read_reg_cache(codec,reg);
+
+    data[0]=(u8)(ri->addr>>8);
+    data[1]=(u8)(ri->addr>>0);
+
+    msg[0].addr  = client->addr;
+    msg[0].flags = client->flags & I2C_M_TEN;
+    msg[0].len   = 2;
+    msg[0].buf   = &data[0];
+
+    msg[1].addr  = client->addr;
+    msg[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
+    msg[1].len   = ((ri->type&REG_WIDTH_MASK)==REG_WIDTH_W)?2:1;
+    msg[1].buf   = &data[2];
+
+    if (i2c_transfer(adap,msg,2)!=2)
+        return -EIO;
+
+    switch(ri->type&REG_WIDTH_MASK)
+    {
+    case REG_WIDTH_B:
+        dat=ri->bias+data[2];
+        break;
+    case REG_WIDTH_W:
+        dat=ri->bias+(data[2]<<0)+(data[3]<<8);
+        break;
+    default:
+        return -EIO;
+    }
+    cx2070x_write_reg_cache(codec,reg,dat);
+    return dat;
+}
+#endif //#!ENABLE_SPI
+
+// reset codec via gpio pin.
+#if defined(CONFIG_SND_CX2070X_GPIO_RESET)
+static int cx2070x_reset_device(void)
+{
+
+    int err = 0;
+    int reset_pin = CODEC_RESET_GPIO_PIN;
+    INFO("%lu: %s() called\n",jiffies,__func__);
+    if (gpio_is_valid(reset_pin)) {
+        if (gpio_request(reset_pin, "reset_pin")) {
+            printk( KERN_ERR "cx2070x: reset pin %d not available\n",reset_pin);
+            err = -ENODEV;
+        } else {
+            gpio_direction_output(reset_pin, 1);
+            mdelay(3);
+            gpio_set_value(reset_pin, 0);
+            //udelay(1);// simon :need to re-check the reset timing.
+            mdelay(3);
+            gpio_set_value(reset_pin, 1);
+            gpio_free(reset_pin); 
+            mdelay(200); //simon :not sure how long the device become ready.
+        }
+    }
+    else
+    {
+        printk( KERN_ERR "cx2070x: reset pin %d is not valid\n",reset_pin);
+        err = -ENODEV;
+    }
+    return err;
+}
+#endif //#if defined(CONFIG_SND_CX2070X_GPIO_RESET)
+
+
+static int cx2070x_dsp_init(struct snd_soc_codec *codec,unsigned mode)
+{
+    unsigned r;
+    cx2070x_real_write(codec,DSP_INIT,mode);
+    printk("******************%s mode = %0x\n",__func__, mode);
+    // maximum time for the NEWC to clear is about 2ms.
+    for(r=1000;;) 
+        if (!(cx2070x_real_read(codec,DSP_INIT)&DSP_INIT_NEWC))
+            return 0;
+        else if (--r==0)
+            return -EIO;
+        else
+            msleep(1);
+}
+
+static int NOINLINE cx2070x_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+{
+    int err = 0;
+
+    if ((err=cx2070x_real_write(codec,reg,value))<0)
+        return err;
+
+    switch(cx2070x_regs[reg].type&REG_TYPE_MASK)
+    {
+    case REG_TYPE_WC:
+        printk("^^^^^^^^^%0x\n",cx2070x_read_reg_cache(codec,DSP_INIT));
+        printk("^^^^^^^^^%0x\n",cx2070x_read_reg_cache(codec,DSP_INIT)|DSP_INIT_NEWC);
+        return cx2070x_dsp_init(codec,cx2070x_read_reg_cache(codec,DSP_INIT)|DSP_INIT_NEWC);
+    default:
+        return err;
+    }
+}
+
+
+static int output_select_event_set(struct snd_kcontrol *kcontrol,
+struct snd_ctl_elem_value *ucontrol)
+{
+
+    int changed = 0;
+    struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+    struct soc_enum *control = (struct soc_enum *)kcontrol->private_value;
+    struct cx2070x_priv  *channel = get_cx2070x_priv(codec);
+
+   // unsigned short sel;
+
+    /* Refuse any mode changes if we are not able to control the codec. */
+    if (!codec->control_data)
+        return -EUNATCH;
+
+    if (ucontrol->value.enumerated.item[0] >= control->max)
+        return -EINVAL;
+
+    mutex_lock(&codec->mutex);
+
+    /* Translate selection to bitmap */
+    channel->output_sel = (enum Cx_OUTPUT_SEL) ucontrol->value.enumerated.item[0];
+
+    
+    switch(ucontrol->value.enumerated.item[0])
+    {
+        case Cx_OUTPUT_SEL_BY_GPIO:
+            {
+                //disable BT output.
+                snd_soc_dapm_disable_pin(&codec->dapm, "BT OUT");
+                //snd_soc_dapm_disable_pin(codec, "Headphone");
+                snd_soc_dapm_disable_pin(&codec->dapm, "BT OUT");
+                //enable analog pin 
+#if defined(CONFIG_SND_CX2070X_GPIO_JACKSENSE)
+                                                       #ifdef CONFIG_GPIOLIB
+               // snd_soc_jack_gpio_detect(&hs_jack_gpios[0]);
+                //snd_soc_dapm_enable_pin(codec, "INT SPK");
+              #else
+                snd_soc_dapm_enable_pin(&codec->dapm, "INT SPK");
+              #endif
+#else
+                snd_soc_dapm_enable_pin(&codec->dapm, "INT SPK");
+#endif //if defined(CONFIG_SND_CX2070X_GPIO_JACKSENSE)
+                break;
+            }
+        case Cx_OUTPUT_SEL_SPK:
+        case Cx_OUTPUT_SEL_LINE:
+            {
+                snd_soc_dapm_disable_pin(&codec->dapm, "BT OUT");
+                snd_soc_dapm_disable_pin(&codec->dapm, "Headphone");
+
+                snd_soc_dapm_enable_pin(&codec->dapm, "INT SPK");
+                break;
+            }
+        case Cx_OUTPUT_SEL_HP:
+            {
+                snd_soc_dapm_disable_pin(&codec->dapm, "BT OUT");
+                snd_soc_dapm_disable_pin(&codec->dapm, "INT SPK");
+                snd_soc_dapm_enable_pin(&codec->dapm, "Headphone");
+                break;
+            }
+        case Cx_OUTPUT_SEL_DPORT2:
+            {
+                snd_soc_dapm_disable_pin(&codec->dapm, "INT SPK");
+                snd_soc_dapm_disable_pin(&codec->dapm, "Headphone");
+                snd_soc_dapm_enable_pin(&codec->dapm, "BT OUT");
+                break;
+            }
+        default:;
+            printk( KERN_ERR "output mode is not valid\n");
+    }
+
+    snd_soc_dapm_sync(&codec->dapm);
+    mutex_unlock(&codec->mutex);
+    return changed;
+}
+
+static int output_select_event_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+    struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
+    struct cx2070x_priv  *channel = get_cx2070x_priv(codec);
+    ucontrol->value.enumerated.item[0] = channel->output_sel;
+    return 0;
+}
+
+
+static const char *output_select_mode[] =
+{"AUTO",  "SPK" ,"LINE",  "HP" ,"PCM2"};
+
+static const struct soc_enum output_select_enum[] = {
+    SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(output_select_mode),
+    output_select_mode),
+};
+
+static const char *input_select_mode[] =
+{"MIC",  "PCM" };
+    
+static const struct soc_enum input_select_enum[] = {
+    SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_select_mode),
+    input_select_mode),
+};
+
+static const struct snd_kcontrol_new input_select_controls =
+SOC_DAPM_ENUM("Route", input_select_enum);
+
+static const struct snd_kcontrol_new cx2070x_snd_controls[]=
+{
+    // Output
+    SOC_DOUBLE_R_TLV("Master Playback Volume", DAC1_GAIN_LEFT,         DAC2_GAIN_RIGHT, 0, 74, 0,dac_tlv),
+    SOC_SINGLE(  "EQ Switch",                          DSP_PROCESSING_ENABLE_2,                        0, 0x01, 0),
+    SOC_SINGLE(  "SWC Switch",                         DSP_PROCESSING_ENABLE_2,                        1, 0x01, 0),
+    SOC_SINGLE(  "DRC Switch",                         DSP_PROCESSING_ENABLE_2,                        2, 0x01, 0),
+    SOC_SINGLE(  "Stage Enhancer Switch",                      DSP_PROCESSING_ENABLE_2,                        3, 0x01, 0),
+    SOC_SINGLE(  "Loudness Switch",                    DSP_PROCESSING_ENABLE_2,                        4, 0x01, 0),
+    SOC_SINGLE(  "DSP Mono Out Switch",                        DSP_PROCESSING_ENABLE_2,                        5, 0x01, 0),
+
+    //// Input
+
+    SOC_DOUBLE_R_TLV("Mic Pga Volume", ADC2_GAIN_LEFT,         ADC2_GAIN_RIGHT, 0, 74, 0,adc_tlv),
+    SOC_SINGLE(  "Right Microphone Switch",            DSP_PROCESSING_ENABLE_1,                        6, 0x01, 0),
+    SOC_SINGLE(  "Inbound Noice Reduction Switch",     DSP_PROCESSING_ENABLE_1,                        5, 0x01, 0),
+    SOC_SINGLE(  "Mic AGC Switch",                     DSP_PROCESSING_ENABLE_1,                        4, 0x01, 0),
+    SOC_SINGLE(  "Beam Forming Switch",                        DSP_PROCESSING_ENABLE_1,                        3, 0x01, 0),
+    SOC_SINGLE(  "Noise Reduction Switch",             DSP_PROCESSING_ENABLE_1,                        2, 0x01, 0),
+    SOC_SINGLE(  "LEC Switch",                         DSP_PROCESSING_ENABLE_1,                        1, 0x01, 0),
+    SOC_SINGLE(  "AEC Switch",                         DSP_PROCESSING_ENABLE_1,                        0, 0x01, 0),
+    SOC_ENUM_EXT("Master Playback Switch", output_select_enum[0], output_select_event_get, output_select_event_set),
+};
+
+// add non dapm controls
+static int cx2070x_add_controls(struct snd_soc_codec *codec)
+{
+    INFO("%lu: %s() called\n",jiffies,__func__);
+
+    return (snd_soc_add_controls(codec, cx2070x_snd_controls, ARRAY_SIZE(cx2070x_snd_controls)));
+}
+
+static int hpportpga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int old;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on = 0x1;
+    old = cx2070x_read_reg_cache(codec,OUTPUT_CONTROL);
+    old &=~ on;
+    old &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        cx2070x_write(codec,OUTPUT_CONTROL,old|on );
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,OUTPUT_CONTROL,old);
+        break;
+    }
+    return 0;
+
+}
+
+static int lineoutpga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int val;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on = (unsigned int)1<<1;
+    val = cx2070x_read_reg_cache(codec,OUTPUT_CONTROL);
+    val &=~ on;
+    val &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        cx2070x_write(codec,OUTPUT_CONTROL,val|on);
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,OUTPUT_CONTROL,val);
+        break;
+    }
+    return 0;
+}
+static int clsdportpga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int val;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on = (unsigned int)1<<2;
+    val = cx2070x_read_reg_cache(codec,OUTPUT_CONTROL);
+    val &=~ on;
+    val &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        cx2070x_write(codec,OUTPUT_CONTROL,val|on);
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,OUTPUT_CONTROL,val);
+        break;
+    }
+    return 0;
+}
+
+static int lineinpga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    //unsigned int val;
+    //struct snd_soc_codec * codec = w->codec;
+    //unsigned int on = (unsigned int)1<<2;
+    //val = cx2070x_read_reg_cache(codec,OUTPUT_CONTROL);
+    //val &=~ on;
+    //val &= 0xFF;
+    //switch (event) {
+    //case SND_SOC_DAPM_POST_PMU:
+    //    cx2070x_write(codec,OUTPUT_CONTROL,val|on);
+    //    break;
+    //case SND_SOC_DAPM_POST_PMD:
+    //    cx2070x_write(codec,OUTPUT_CONTROL,val);
+    //    break;
+    //}
+    return 0;
+}
+
+static int micportpga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    //unsigned int val;
+    //struct snd_soc_codec * codec = w->codec;
+    //unsigned int on = (unsigned int)1<<1;
+    //val = cx2070x_read_reg_cache(codec,OUTPUT_CONTROL);
+    //val &=~ on;
+    //val &= 0xFF;
+    //switch (event) {
+    //case SND_SOC_DAPM_POST_PMU:
+    //    cx2070x_write(codec,OUTPUT_CONTROL,val|on);
+    //    break;
+    //case SND_SOC_DAPM_POST_PMD:
+    //    cx2070x_write(codec,OUTPUT_CONTROL,val);
+    //    break;
+    //}
+    return 0;
+}
+
+static int aout_pga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int val;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on   = (unsigned int)1<<7; //steam 7
+    unsigned int reg  = DSP_INIT;
+    val = cx2070x_read_reg_cache(codec,reg);
+    val &=~ on;
+    val &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        cx2070x_write(codec,STREAMOP_ROUTING,0x60 );  // scal_out
+        cx2070x_write(codec,STREAM7_SOURCE,5 );  //Scale_out
+        cx2070x_write(codec,reg,val|on );
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,STREAM7_SOURCE,0 );  //disconnect
+        cx2070x_write(codec,reg,val);
+        break;
+    }
+    return 0;
+}
+
+static int dout_pga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int val;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on   = (unsigned int)1<<4;
+    unsigned int reg  = DSP_INIT;
+    val = cx2070x_read_reg_cache(codec,reg);
+    val &=~ on;
+    val &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        cx2070x_write(codec,STREAMOP_ROUTING,0x60 );  // scal_out
+        snd_soc_update_bits(codec, MIC_CONTROL, 3, 1);
+        //cx2070x_write(codec,STREAM6_ROUTING,5 );  // scal_out
+        cx2070x_write(codec,reg,val|on );
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,STREAMOP_ROUTING,0x62 );  // scal_out
+        cx2070x_write(codec,STREAM6_ROUTING,0 );  //disconnect
+        cx2070x_write(codec,reg,val);
+        break;
+    }
+    return 0;
+}
+
+static int ain_pga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int val;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on   = (unsigned int)1<<2; //steam 2
+    unsigned int reg  = DSP_INIT;
+    val = cx2070x_read_reg_cache(codec,reg);
+    val &=~ on;
+    val &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        //cx2070x_write(codec,VOICE_IN_SOURCE, 0x2 );  //stream 2 -> Voice In
+        cx2070x_write(codec,reg,val|on );
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,reg,val);
+        break;
+    }
+    return 0;
+}
+
+static int din_pga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int val;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on   = (unsigned int)1<<4; //stream 4
+    unsigned int reg  = DSP_INIT;
+    val = cx2070x_read_reg_cache(codec,reg);
+    val &=~ on;
+    val &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        cx2070x_write(codec,VOICE_IN_SOURCE, 0x4 ); //stream 4 -> Voice In
+        cx2070x_write(codec,reg,val|on );
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,reg,val);
+        break;
+    }
+    return 0;
+}
+
+static int adc_pga_event(struct snd_soc_dapm_widget *w,
+struct snd_kcontrol *kcontrol, int event)
+{
+    unsigned int val;
+    struct snd_soc_codec * codec = w->codec;
+    unsigned int on   = (unsigned int)1<<5; //stream 5
+    unsigned int reg  = DSP_INIT;
+    val = cx2070x_read_reg_cache(codec,reg);
+    val &=~ on;
+    val &= 0xFF;
+    switch (event) {
+    case SND_SOC_DAPM_POST_PMU:
+        cx2070x_write(codec,reg,val|on );
+        break;
+    case SND_SOC_DAPM_POST_PMD:
+        cx2070x_write(codec,reg,val);
+        break;
+    }
+    return 0;
+}
+
+static const struct snd_soc_dapm_widget cx2070x_dapm_widgets[]=
+{
+
+    //Playback 
+    SND_SOC_DAPM_DAC(  "DAC",          "Playback",     DSP_INIT,3,0), //stream 3
+
+    SND_SOC_DAPM_PGA_E("AOUT PGA", SND_SOC_NOPM,
+    0, 0, NULL, 0, aout_pga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    SND_SOC_DAPM_PGA_E("DOUT PGA", SND_SOC_NOPM,
+    0, 0, NULL, 0, dout_pga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    SND_SOC_DAPM_PGA_E("HP Port", SND_SOC_NOPM,
+    0, 0, NULL, 0, hpportpga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    SND_SOC_DAPM_PGA_E("CLASSD Port", SND_SOC_NOPM,
+    0, 0, NULL, 0, clsdportpga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    SND_SOC_DAPM_PGA_E("LINEOUT Port", SND_SOC_NOPM,
+    0, 0, NULL, 0, lineoutpga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    //Output Pin.
+    SND_SOC_DAPM_OUTPUT("SPK OUT"),
+    SND_SOC_DAPM_OUTPUT("LINE OUT"),
+    SND_SOC_DAPM_OUTPUT("HP OUT"),
+    SND_SOC_DAPM_OUTPUT("PCM OUT"),
+
+    //
+    // Captuer
+    //
+    SND_SOC_DAPM_ADC_E("ADC", "Capture", SND_SOC_NOPM,
+       0, 0, adc_pga_event,
+       SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+
+    SND_SOC_DAPM_PGA_E("AIN PGA", SND_SOC_NOPM,
+    0, 0, NULL, 0, ain_pga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    SND_SOC_DAPM_PGA_E("DIN PGA", SND_SOC_NOPM,
+    0, 0, NULL, 0, din_pga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    SND_SOC_DAPM_PGA_E("MIC Port", SND_SOC_NOPM,
+    0, 0, NULL, 0, micportpga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    SND_SOC_DAPM_PGA_E("LINEIN Port", SND_SOC_NOPM,
+    0, 0, NULL, 0, lineinpga_event,
+    SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
+
+    //DECLARE_TLV_DB_SCALE
+
+    SND_SOC_DAPM_INPUT("MIC IN"),
+    SND_SOC_DAPM_INPUT("PCM IN"),
+    SND_SOC_DAPM_INPUT("LINE IN"),
+
+    SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
+        &input_select_controls),
+
+    SND_SOC_DAPM_MICBIAS("Mic Bias",MIC_CONTROL,3,0),
+#if 0
+    //machina layer.
+    SND_SOC_DAPM_MIC("INT MIC", NULL),
+    SND_SOC_DAPM_MIC("BT IN", NULL),
+    SND_SOC_DAPM_HP("BT OUT", NULL),
+    SND_SOC_DAPM_SPK("INT SPK", NULL),
+    SND_SOC_DAPM_HP("Headphone", NULL),
+#endif
+};
+
+static const struct snd_soc_dapm_route cx2070x_routes[] = 
+{
+    //playback.
+    { "AOUT PGA",           NULL,"DAC"          },
+    { "DOUT PGA",           NULL,"DAC"          },
+
+    { "HP Port",            NULL,"AOUT PGA"     },
+    { "LINEOUT Port",       NULL,"AOUT PGA"     },
+    { "CLASSD Port",        NULL,"AOUT PGA"     },
+
+    { "HP OUT",             NULL,"HP Port"      },
+    { "LINE OUT",           NULL,"LINEOUT Port" },
+    { "SPK OUT",            NULL,"CLASSD Port"  },
+    { "PCM OUT",            NULL,"DOUT PGA"     },
+
+    //capture. 
+    { "ADC",                NULL,"Capture Source"       },
+
+    { "Capture Source",             "MIC","AIN PGA"     },
+    { "Capture Source",             "PCM","DIN PGA"     },
+
+    { "AIN PGA",            NULL,"MIC Port"     },
+   // { "MIC Port",           NULL,"Mic Bias"     },
+    { "MIC Port",           NULL,"MIC IN"     },
+
+  //  { "Mic Bias",           NULL,"MIC IN"       },
+    { "DIN PGA",            NULL,"PCM IN"       },
+#if 0
+    //machina layer.
+    { "Headphone",          NULL,"HP OUT"       },
+    { "INT SPK",            NULL,"SPK OUT"      },
+    { "BT OUT",             NULL,"PCM OUT"      },
+    { "MIC IN",             NULL,"INT MIC"       },
+    { "PCM IN",             NULL,"BT IN"         },
+#endif
+};
+
+static int cx2070x_add_widgets(struct snd_soc_codec *codec)
+{
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       
+    INFO("%lu: %s() called\n",jiffies,__func__);
+
+    snd_soc_dapm_new_controls(dapm, cx2070x_dapm_widgets, ARRAY_SIZE(cx2070x_dapm_widgets));
+    snd_soc_dapm_add_routes(dapm, cx2070x_routes, ARRAY_SIZE(cx2070x_routes));
+    return 0;
+}
+
+static int cx2070x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+
+{
+    struct snd_soc_codec *codec  = dai->codec;
+    unsigned int s5,s3,i2s,dsp;
+#define _3_3_f_f_5 1
+#define _1_1_7_7_0 0
+    int err =0;
+
+    ERROR("%lu: %s() called\n",jiffies,__func__);
+    ERROR("\tformat:%u speed:%u\n",params_format(params),params_rate(params));
+    
+    switch(params_format(params))
+    {
+    case SNDRV_PCM_FORMAT_S16_LE: s5=STREAM5_SAMPLE_16_LIN; s3=STREAM5_SAMPLE_16_LIN; i2s=_3_3_f_f_5; break;
+    case SNDRV_PCM_FORMAT_S16_BE: s5=STREAM5_SAMPLE_16_LIN; s3=STREAM5_SAMPLE_16_LIN; i2s=_3_3_f_f_5; break;
+    case SNDRV_PCM_FORMAT_MU_LAW: s5=STREAM5_SAMPLE_U_LAW;  s3=STREAM5_SAMPLE_U_LAW;  i2s=_1_1_7_7_0; break;
+    case SNDRV_PCM_FORMAT_A_LAW:  s5=STREAM5_SAMPLE_A_LAW;  s3=STREAM5_SAMPLE_A_LAW;  i2s=_1_1_7_7_0; break;
+    default:
+        printk(KERN_ERR "cx2070x: unsupported PCM format 0x%u\n",params_format(params));
+        return -EINVAL;
+    }
+
+    switch(params_rate(params))
+    {
+    case  8000:        s5|=                      STREAM5_RATE_8000;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_8000;  break;
+    case 11025:        s5|=                      STREAM5_RATE_11025;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_11025; break;
+    case 16000:        s5|=                      STREAM5_RATE_16000;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_16000; break;
+    case 22050:        s5|=                      STREAM5_RATE_22050;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_22050; break;
+    case 24000:        s5|=                      STREAM5_RATE_24000;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_24000; break;
+    case 32000:        s5|=                      STREAM5_RATE_32000;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_32000; break;
+    case 44100:        s5|=                      STREAM5_RATE_44100;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_44100; break;
+    case 48000:        s5|=                      STREAM5_RATE_48000;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_48000; break;
+    case 88200:        s5|=                      STREAM5_RATE_88200;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_88200; break;
+    case 96000:        s5|=                      STREAM5_RATE_96000;
+        s3|=STREAM3_STREAM_STEREO|STREAM3_RATE_96000; break;
+    default:
+        printk(KERN_ERR "cx2070x: unsupported rate  %d\n",params_rate(params));
+        return -EINVAL;
+    }
+
+    cx2070x_real_write(codec,PORT1_TX_CLOCKS_PER_FRAME_PHASE,i2s?0x07:0x01);
+    cx2070x_real_write(codec,PORT1_RX_CLOCKS_PER_FRAME_PHASE,i2s?0x07:0x01);
+    cx2070x_real_write(codec,PORT1_TX_SYNC_WIDTH,            i2s?0x0f:0x07);
+    cx2070x_real_write(codec,PORT1_RX_SYNC_WIDTH,            i2s?0x0f:0x07);
+    cx2070x_real_write(codec,PORT1_CONTROL_2,                i2s?0x05:0x00);
+    /*params for port2 by showy.zhang*/
+    cx2070x_real_write(codec,STREAM5_RATE,s5);
+    cx2070x_real_write(codec,STREAM3_RATE,s3);// cause by incorrect parameter
+
+    dsp=cx2070x_read_reg_cache(codec,DSP_INIT);
+
+    if ((err=cx2070x_dsp_init(codec,dsp|DSP_INIT_NEWC))<0)
+        return err;
+
+    return 0;
+}
+
+static int cx2070x_mute(struct snd_soc_dai *dai, int mute)
+{
+    struct snd_soc_codec *codec = dai->codec;
+
+    ERROR("%lu: %s(%d) called\n",jiffies,__func__,mute);
+
+    cx2070x_real_write(codec,VOLUME_MUTE,mute?VOLUME_MUTE_ALL:b_00000000);
+
+/*
+    if( mute)
+    {
+        cx2070x_real_write(codec,DSP_POWER,0xe0); // deep sleep mode
+        cx2070x_dsp_init(codec,DSP_INIT_STREAM_OFF);
+    }
+    else
+    {
+        cx2070x_dsp_init(codec,DSP_INIT_NEWC | 0xff);
+    }
+*/
+    return 0;
+}
+
+static int cx2070x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir)
+{
+    struct snd_soc_codec *codec = dai->codec;
+    struct cx2070x_priv  *channel = get_cx2070x_priv(codec);
+
+    INFO("%lu: %s() called\n",jiffies,__func__);
+
+    // sysclk is not used where, but store it anyway
+    channel->sysclk = freq;
+    return 0;
+}
+
+static int cx2070x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+    struct snd_soc_codec *codec = dai->codec;
+    struct cx2070x_priv *channel = get_cx2070x_priv(codec);
+
+    INFO("%lu: %s() called\n",jiffies,__func__);
+
+    // set master/slave audio interface
+    switch (fmt & SND_SOC_DAIFMT_MASTER_MASK)
+    {
+    case SND_SOC_DAIFMT_CBS_CFS:       // This design only supports slave mode
+        channel->master = 0;
+        break;
+    default:
+       printk(KERN_ERR "unsupport DAI format, driver only supports slave mode\n");
+        return -EINVAL;
+    }
+
+    switch (fmt & SND_SOC_DAIFMT_INV_MASK)
+    {
+    case SND_SOC_DAIFMT_NB_NF:         // This design only supports normal bclk + frm
+        break;
+    default:
+       printk(KERN_ERR "unsupport DAI format, driver only supports normal bclk+ frm\n");
+        return -EINVAL;
+    }
+
+    // interface format
+    switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK)
+    {
+    case SND_SOC_DAIFMT_I2S:           // This design only supports I2S
+        break;
+    default:
+       printk( KERN_ERR "unspoort DAI format, driver only supports I2S interface.\n");
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+struct snd_soc_dai_ops cx2070x_dai_ops = 
+{
+    .set_sysclk=cx2070x_set_dai_sysclk,
+    .set_fmt = cx2070x_set_dai_fmt,
+    .digital_mute=cx2070x_mute,
+    .hw_params = cx2070x_hw_params,
+};
+
+struct snd_soc_dai_driver soc_codec_cx2070x_dai = 
+{
+    .name = "cx2070x-hifi",
+    .ops = &cx2070x_dai_ops,
+    .capture = {
+        .stream_name="Capture",
+            .formats = CX2070X_FORMATS,
+            .rates = CX2070X_RATES,
+            .channels_min = 1,
+            .channels_max = 2,
+    },
+    .playback= {
+         .stream_name="Playback",
+            .formats = CX2070X_FORMATS,
+            .rates = CX2070X_RATES,
+            .channels_min = 1,
+            .channels_max = 2,
+        },
+       .symmetric_rates = 1,
+};
+EXPORT_SYMBOL_GPL(soc_codec_cx2070x_dai);
+
+static int cx2070x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+{
+    INFO("%lu: %s(,%d) called\n",jiffies,__func__,level);
+
+    switch (level)
+    {
+        // Fully on
+    case SND_SOC_BIAS_ON:
+        cx2070x_real_write(codec,DSP_POWER,0x20);
+        // all power is driven by DAPM system
+        break;
+
+        // Partial on
+    case SND_SOC_BIAS_PREPARE:
+        break;
+
+        // Off, with power
+    case SND_SOC_BIAS_STANDBY:
+        //cx2070x_real_write(codec,VOLUME_MUTE,VOLUME_MUTE_ALL); // mute all
+        //cx2070x_real_write(codec,DSP_POWER,0xe0); // deep sleep mode
+        //cx2070x_dsp_init(codec,DSP_INIT_STREAM_OFF);
+       
+        // TODO: power down channel
+        break;
+
+        // Off, without power
+    case SND_SOC_BIAS_OFF:
+        cx2070x_real_write(codec,VOLUME_MUTE,VOLUME_MUTE_ALL); // mute all
+        cx2070x_real_write(codec,DSP_POWER,0xe0); // deep sleep mode
+        cx2070x_dsp_init(codec,DSP_INIT_STREAM_OFF);
+        // TODO: put channel into deep-sleep
+        break;
+    }
+
+    return 0;
+}
+
+int I2cWrite( struct snd_soc_codec *codec, unsigned char ChipAddr, unsigned long cbBuf, unsigned char* pBuf)
+{
+#ifdef USING_SPI
+    struct spi_device * spi =   (struct spi_device *) codec->control_data;
+    pBuf[0] |= 0x80; //SPI_WRITE
+    spi_write(spi,pBuf,cbBuf);
+    return true;
+#else //#ifdef ENABLE_SPI
+    struct i2c_client  *client = (struct i2c_client  *)codec->control_data;
+    struct i2c_adapter *adap   = client->adapter;
+    struct i2c_msg      msg[1];
+
+
+    msg[0].addr  = client->addr;
+    msg[0].flags = client->flags & I2C_M_TEN;
+    msg[0].buf   = pBuf;
+    msg[0].len   = cbBuf;
+    if (i2c_transfer(adap,msg,1)!=1)
+    {
+        printk(KERN_ERR "cx2070x: I2cWriteThenRead failed.\n");
+
+        return 0;
+    }
+    else
+    {
+        return 1;
+    }
+#endif //#!ENABLE_SPI
+}
+
+int I2cWriteThenRead( struct snd_soc_codec *codec, unsigned char ChipAddr, unsigned long cbBuf,
+    unsigned char* pBuf, unsigned long cbReadBuf, unsigned char*pReadBuf)
+{
+    
+#ifdef USING_SPI
+    u8  reg[3];
+    struct spi_device * spi =   (struct spi_device *) codec->control_data;
+    reg[0] = pBuf[0];
+    reg[1] = pBuf[1];
+    reg[2] = 0;
+    spi_write_then_read(spi, reg, 3, pReadBuf,cbReadBuf);
+    return true;
+#else //#ifdef USING_SPI
+    struct i2c_client  *client = (struct i2c_client  *)codec->control_data;
+    struct i2c_adapter *adap   = client->adapter;
+    struct i2c_msg      msg[2];
+
+    msg[0].addr  = client->addr;
+    msg[0].flags = client->flags & I2C_M_TEN;
+    msg[0].len   = cbBuf;
+    msg[0].buf   = pBuf;
+
+    msg[1].addr  = client->addr;
+    msg[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
+    msg[1].len   = cbReadBuf;
+    msg[1].buf   = pReadBuf;
+
+    if (i2c_transfer(adap,msg,2)!=2)
+    {
+        printk(KERN_ERR "cx2070x: I2cWriteThenRead failed.\n");
+        return 0;
+    }
+    else 
+    {
+        return 1;
+    }
+#endif //#!ENABLE_SPI
+}
+
+
+#if defined(CONFIG_SND_CX2070X_LOAD_FW)
+static int cx2070x_apply_firmware_patch(struct snd_soc_codec *codec)
+{
+       int ret = 0;
+    const struct firmware *fw = NULL;
+    const unsigned char *dsp_code  = NULL;
+    struct device *dev = codec->dev;   
+
+#if defined(CONFIG_SND_CX2070X_USE_FW_H)
+    // load firmware from c head file.
+    dsp_code = ChannelFW;
+#else
+    // load firmware from file.
+    ret = request_firmware(&fw, CX2070X_FIRMWARE_FILENAME, dev); 
+    if (ret < 0) {
+        printk( KERN_ERR "%s(): Firmware %s not available %d",
+                                       __func__, CX2070X_FIRMWARE_FILENAME, ret);
+               return ret;
+    }
+    dsp_code = fw->data;
+#endif
+    
+    ret = ApplyDSPChanges(dsp_code);
+    if (ret) {
+        printk(KERN_ERR "cx2070x: patch firmware failed, Error %d\n", ret);
+    } else {
+        printk(KERN_INFO "cx2070x: patch firmware successfully.\n");   
+    }
+    
+       return ret;
+}
+
+static int cx2070x_download_firmware(struct snd_soc_codec        *codec)
+{
+    int                        ret        = 0;
+    char                       *buf       = NULL;
+    const struct firmware       *fw        = NULL;
+    const unsigned char         *dsp_code  = NULL;
+#if !defined(CONFIG_SND_CX2070X_USE_FW_H)
+    struct device              *dev       = codec->dev;        
+#endif 
+
+    // load firmware to memory.
+#if defined(CONFIG_SND_CX2070X_USE_FW_H)
+    // load firmware from c head file.
+    dsp_code = ChannelFW;
+#else
+    // load firmware from file.
+    ret = request_firmware(&fw, CX2070X_FIRMWARE_FILENAME,dev); 
+    if( ret < 0)
+    {
+        printk( KERN_ERR "%s(): Firmware %s not available %d",__func__,CX2070X_FIRMWARE_FILENAME,ret);
+       goto LEAVE;
+    }
+    dsp_code = fw->data;
+#endif // #if defined(CONFIG_SND_CX2070X_USE_FW_H)
+    //
+    // Load rom data from a array.
+    //
+    buf = (char*)kzalloc(0x200,GFP_KERNEL);
+    if (buf  == NULL)
+    {
+        printk(KERN_ERR "cx2070x: out of memory .\n");
+        ret = -ENOMEM;
+        goto LEAVE;
+    }
+
+    //
+    // Setup the i2c callback function.
+    //
+    SetupI2cWriteCallback( (void *) codec, (fun_I2cWrite) I2cWrite,32);
+    SetupI2cWriteThenReadCallback( (void *) codec, (fun_I2cWriteThenRead) I2cWriteThenRead); 
+
+    // download
+    SetupMemoryBuffer(buf);
+    
+    ret = DownloadFW(dsp_code);
+    if(ret)
+    {
+        printk(KERN_ERR "cx2070x: download firmware failed, Error %d\n",ret);
+    }
+    else
+    {
+        printk(KERN_INFO "cx2070x: download firmware successfully.\n");        
+    }
+    if (buf)
+    {
+        kfree(buf);
+    }
+LEAVE:
+
+#if defined(CONFIG_SND_CX2070X_LOAD_FW) && !defined(CONFIG_SND_CX2070X_USE_FW_H)
+    if(fw)
+    {
+        release_firmware(fw);
+    }
+#endif 
+    return ret;
+
+}
+#endif
+
+unsigned int cx2070x_hw_read( struct snd_soc_codec *codec, unsigned int regaddr)
+{
+    unsigned char data;
+    unsigned char chipaddr = 0;
+    unsigned char reg[2];
+#ifdef USING_I2C
+    struct i2c_client  *client = (struct i2c_client  *) codec->control_data;
+    chipaddr = client->addr;
+#endif
+    reg[0] = regaddr>>8;
+    reg[1] = regaddr&0xff;
+    I2cWriteThenRead(codec,chipaddr, 2, reg, 1,&data);
+    return (unsigned int)data;
+}
+
+unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
+
+//
+// Initialise the cx2070x  driver
+// Register the mixer and dsp interfaces with the kernel
+//
+static int NOINLINE cx2070x_init(struct snd_soc_codec* codec)
+{
+    struct cx2070x_priv     *cx2070x = get_cx2070x_priv(codec);
+    int                   n,vl,vh,vm,fh, fl,ret = 0;
+    cx2070x_reg_t             *reg_cache;
+
+    printk(">>>>>>>%s",__func__);
+    INFO("%lu: %s() called\n",jiffies,__func__);
+
+    codec->control_data = cx2070x->control_data;
+
+
+#if defined(CONFIG_SND_CX2070X_GPIO_RESET)
+    cx2070x_reset_device();
+#endif 
+
+#if CX2070X_TRISTATE_EEPROM
+    // If CX2070X  has to float the pins to the NVRAM, enable this code
+    for(;;)
+    {
+        int pad,pbd;
+        pad=cx2070x_real_read(codec,PAD);
+        pbd=cx2070x_real_read(codec,PBD);
+        printk("%s(): PAD/PBD=%02x/%02x\n",__func__,pad,pbd);
+
+        _cx2070x_real_write(codec,PAD,pad&~(1<<4));
+        _cx2070x_real_write(codec,PBD,pbd&~(1<<6));
+        msleep(1000);
+    }
+#endif
+
+
+#if defined(CONFIG_SND_CX2070X_LOAD_FW)
+    ret = cx2070x_download_firmware(codec);
+    if( ret < 0)
+    {
+       printk(KERN_ERR "%s: failed to download firmware\n",__func__);
+       return ret;
+    }
+
+#endif
+    // Verify that Channel/Balboa is ready.
+    // May have to wait for ~5sec becore Channel/Balboa comes out of reset
+    for(n=5000;!bNoHW;)
+    {
+        int abcode=cx2070x_real_read(codec,ABORT_CODE);
+     //   int abcode=cx2070x_real_read(codec,CHIP_VERSION);
+        printk(">>>>>>>>>>>>>>>%s abcode = %d",__func__, abcode);
+        if (abcode==0x01)
+            break;  // initialization done!
+        if (--n==0)
+        {
+            printk(KERN_ERR "Timeout waiting for cx2070x to come out of reset!\n");
+            return -EIO;
+        }
+        msleep(1);
+    }
+
+    cx2070x_real_read(codec,FIRMWARE_VERSION);
+    cx2070x_real_read(codec,PATCH_VERSION);
+    cx2070x_real_read(codec,CHIP_VERSION);
+    cx2070x_real_read(codec,RELEASE_TYPE);
+
+    reg_cache = GET_REG_CACHE(codec);
+    fl=(reg_cache[FIRMWARE_VERSION]>>0)&0xFF;
+    fl=(fl>>4)*10+(fl&0xf);
+    fh=(reg_cache[FIRMWARE_VERSION]>>8)&0xFF;
+    
+    // determine whether the codec is ROM version or not.
+    if( fh == 5)
+    {   //firmware 5.x
+       //shows the firmware patch version.
+        cx2070x_real_read(codec,ROM_PATCH_VER_HB);
+        cx2070x_real_read(codec,ROM_PATCH_VER_MB);
+        cx2070x_real_read(codec,ROM_PATCH_VER_LB);
+        vh =  reg_cache[ROM_PATCH_VER_HB];
+        vm =  reg_cache[ROM_PATCH_VER_MB];
+        vl =  reg_cache[ROM_PATCH_VER_LB];
+        printk("cx2070x: firmware version %u.%u, patch %u.%u.%u, chip CX2070%u (ROM)\n",fh,fl,vh,vm,vl,reg_cache[CHIP_VERSION]);
+    }
+    else if( fh == 4)
+    {
+        //firmware 4.x
+        printk("cx2070x: firmware version %u.%u,  chip CX2070%u (RAM), ",fh,fl,reg_cache[CHIP_VERSION]);
+        // shows the firmware release type.
+       switch(reg_cache[RELEASE_TYPE])
+       {
+       case 12: printk("Custom Release\n"); break;
+       case 14: printk("Engineering Release\n"); break;
+       case 15: printk("Field Release\n"); break;
+       default: printk("Release %u?\n",reg_cache[RELEASE_TYPE]); break;
+       }
+    }
+    else
+    {
+        printk("cx2070x: Unsupported firmware version %u.%u!!!\n",fh,fl);
+        ret = -EINVAL;
+       goto card_err;
+    }
+    
+
+    if (reg_cache[PATCH_VERSION])
+    {
+       vl=(reg_cache[PATCH_VERSION]>>0)&0xFF;
+       vh=(reg_cache[PATCH_VERSION]>>8)&0xFF;
+               printk("%s(): CX2070X patch version %u.%u\n",__func__,vh,vl);
+    }
+
+    // Initialize the CX2070X regisers and/or read them as needed.
+    for(n=0;n<noof(cx2070x_regs);n++)
+        switch(cx2070x_regs[n].type&REG_TYPE_MASK)
+    {
+        case REG_TYPE_RO:
+        case REG_TYPE_RW:
+            cx2070x_real_read(codec,n);
+            break;
+        case REG_TYPE_WI:
+        case REG_TYPE_WC:
+            cx2070x_real_write(codec,n,cx2070x_data[n]);
+            break;
+#if defined(REG_TYPE_DM)
+        case REG_TYPE_DM:
+            break;
+#endif
+        default:
+            snd_BUG();
+    }
+    
+#if defined(CONFIG_SND_CX2070X_LOAD_FW)
+    cx2070x_apply_firmware_patch(codec);
+#endif
+
+    cx2070x_add_controls(codec);
+    cx2070x_add_widgets(codec);
+
+    //snd_soc_dapm_nc_pin(&codec->dapm, "LINE IN");
+    //snd_soc_dapm_nc_pin( &codec->dapm, "LINE OUT");
+    //snd_soc_dapm_enable_pin( &codec->dapm, "INT MIC");
+    //snd_soc_dapm_enable_pin( &codec->dapm, "INT SPK");
+    //snd_soc_dapm_disable_pin( &codec->dapm, "BT IN");
+    //snd_soc_dapm_enable_pin( &codec->dapm, "Headphone");
+    //snd_soc_dapm_disable_pin( &codec->dapm, "BT OUT");
+
+
+#if defined(CONFIG_SND_CX2070X_GPIO_JACKSENSE)
+    /* Headset jack detection */
+    ret = snd_soc_jack_new(codec, "Headset Jack",
+        SND_JACK_HEADSET, &hs_jack);
+    if (ret)    
+    {
+        printk(KERN_ERR "CX2070X: failed to register Headset Jack\n");
+        goto card_err;
+    }
+
+    ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+        hs_jack_gpios);
+    if (ret)    
+    {
+        printk(KERN_ERR "CX2070X: failed to add jack gpios.\n");
+        goto card_err;
+    }
+    
+    ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+        hs_jack_pins);
+    if (ret)    
+    {
+        printk(KERN_ERR "CX2070X: failed to add soc jack pin\n");
+        goto card_err;
+    }
+#else
+     snd_soc_dapm_sync( &codec->dapm);
+#endif //#if defined(CONFIG_SND_CX2070X_GPIO_JACKSENSE)
+
+#if defined(CONFIG_SND_CXLIFEGUARD)
+    cxdbg_dev_init(codec);
+#endif 
+    if( ret == 0)
+    {
+        printk(KERN_INFO "CX2070X: codec is ready.\n");
+    }
+    return ret;
+
+card_err:
+    return ret;
+}
+
+static int cx2070x_hw_reset(void)
+{
+       int err;
+       /* Reset */
+       err = gpio_request(CODEC_RESET_GPIO_PIN, "nCX2070X_Reset");
+        printk(KERN_ERR "channel reset gpio=%d\n", CODEC_RESET_GPIO_PIN);
+       if (err)
+               printk(KERN_ERR "#### failed to request GPH3_2 for Audio Reset\n");
+
+       gpio_direction_output(CODEC_RESET_GPIO_PIN, 0);
+       msleep(150);
+       gpio_direction_output(CODEC_RESET_GPIO_PIN, 1);
+       gpio_free(CODEC_RESET_GPIO_PIN);
+       msleep(150);
+
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+static struct snd_soc_codec *g_cx2070x_codec;
+
+static int cx2070x_dbg_show_regs(struct seq_file *s, void *unused)
+{
+       
+       int reg_no = (int)s->private;
+       int i = 0;
+       
+       if (reg_no == noof(cx2070x_regs)) {
+               seq_printf(s, "Offset\tType\tValue\tName\n");
+               for (i = 0; i < reg_no; i++) {
+                       seq_printf(s, "0x%02X\t", cx2070x_regs[i].addr);
+                       switch (cx2070x_regs[i].type) {
+                       case REG_TYPE_RO:
+                               seq_printf(s, "R");
+                               break;
+                       case REG_TYPE_RW:
+                               seq_printf(s, "RW");
+                               break;
+                       case REG_TYPE_WC:
+                               seq_printf(s, "WC");
+                               break;
+                       case REG_TYPE_WI:
+                               seq_printf(s, "WI");
+                               break;
+                       default:
+                               seq_printf(s, "UNKNOWN\t");
+                       }
+                       seq_printf(s, "\t0x%02X\t%s\n", cx2070x_read_reg_cache(g_cx2070x_codec, i),
+                                                                                       cx2070x_regs[i].name);
+               }
+               return 0;
+       }
+       
+       seq_printf(s, "Offset:\t0x%02X\n", cx2070x_regs[reg_no].addr);
+       
+       seq_printf(s, "Type:\t");
+       switch (cx2070x_regs[reg_no].type) {
+       case REG_TYPE_RO:
+               seq_printf(s, "R");
+               break;
+       case REG_TYPE_RW:
+               seq_printf(s, "RW");
+               break;
+       case REG_TYPE_WC:
+               seq_printf(s, "WC");
+               break;
+       case REG_TYPE_WI:
+               seq_printf(s, "WI");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN");
+       }
+       seq_printf(s, "\n");
+       
+       seq_printf(s, "Value:\t0x%02X\n", cx2070x_read_reg_cache(g_cx2070x_codec, reg_no));
+
+       return 0;
+}
+
+static int cx2070x_dbg_reg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, cx2070x_dbg_show_regs, inode->i_private);
+}
+
+static ssize_t cx2070x_dbg_reg_write(struct file *file,
+                                                               const char __user *ubuf,                                                                        
+                                size_t count, loff_t *off)
+{
+       struct seq_file *seq = file->private_data;
+       char buf[8];
+       unsigned long val;
+       int reg_no = (int)seq->private;
+       int ret = 0;
+
+       if (count >= sizeof(buf)) {
+               ERROR("%s, The buffer is not enough.\n", __func__);
+               return -EINVAL;
+       } if (copy_from_user(buf, ubuf, count)) {
+               ERROR("%s, Faied to copy data from user space.\n", __func__);
+               return -EFAULT;
+       }
+               
+       buf[count] = 0;
+       
+       ret = strict_strtoul(buf, 16, &val);
+       if (ret < 0) {
+               ERROR("%s, Failed to convert a string to an unsinged long integer.\n", __func__);
+               return ret;
+       }
+               
+       switch (cx2070x_regs[reg_no].type) {
+       case REG_TYPE_RO:
+               ERROR("%s, A read-only register 0x%02x cannot be written.\n",
+                               __func__, cx2070x_regs[reg_no].addr);
+               return -EINVAL; 
+       case REG_TYPE_WI:
+       case REG_TYPE_WC:
+       case REG_TYPE_RW:
+               ret = cx2070x_write(g_cx2070x_codec, reg_no, (u8)val); 
+               if (ret) {
+                       ERROR("%s, Failed to write register 0x%02x.\n", __func__,
+                                       cx2070x_regs[reg_no].addr);
+                       return ret;
+               }
+               break;
+       default:
+               ERROR("%s, Unknown type register\n", __func__);
+               return -EINVAL;
+       }
+       
+       return count;
+}          
+
+static const struct file_operations cx2070x_debug_reg_fops = {
+       .open           = cx2070x_dbg_reg_open,
+       .read           = seq_read,
+       .write                  = cx2070x_dbg_reg_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+#endif
+
+static int cx2070x_probe(struct snd_soc_codec *codec)
+{
+#ifdef CONFIG_DEBUG_FS
+    struct dentry *d, *regs;
+    int n = 0;
+#endif
+
+    INFO("%lu: %s() called\n",jiffies,__func__);
+    printk(KERN_INFO "cx2070x codec driver version: %02x,%02x,%02x,%02x\n",(u8)((CX2070X_DRIVER_VERSION)>>24), 
+      (u8)((CX2070X_DRIVER_VERSION)>>16),
+      (u8)((CX2070X_DRIVER_VERSION)>>8),
+      (u8)((CX2070X_DRIVER_VERSION)));
+    
+#ifdef CONFIG_DEBUG_FS
+       g_cx2070x_codec = codec;
+    d = debugfs_create_dir("cx2070x", NULL);
+       if (IS_ERR(d))
+               return PTR_ERR(d);
+               
+    regs = debugfs_create_dir("regs", d);
+       if (IS_ERR(regs))
+               return PTR_ERR(regs);
+       
+       for (n = 0; n < noof(cx2070x_regs); n++)        
+               debugfs_create_file(cx2070x_regs[n].name, 0644, regs, (void *)n,
+                                                               &cx2070x_debug_reg_fops);
+                                                               
+       debugfs_create_file("ALL", 0644, regs, (void *)n,
+                                                       &cx2070x_debug_reg_fops);
+#endif
+
+    return cx2070x_init(codec);
+}
+
+static int cx2070x_remove(struct snd_soc_codec *codec)
+{
+    INFO("%lu: %s() called\n",jiffies,__func__);
+    // power down chip
+    cx2070x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+#if defined (CONFIG_SND_CX2070X_GPIO_JACKSENSE)
+    snd_soc_jack_free_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+        hs_jack_gpios);
+#endif//#if defined (CONFIG_SND_CX2070X_GPIO_JACKSENSE)
+    return 0;
+}
+
+static int cx2070x_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+    INFO("%lu: %s() called\n",jiffies,__func__);
+    cx2070x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+    return 0;
+}
+
+static int cx2070x_resume(struct snd_soc_codec *codec)
+{
+    int                       n;
+    INFO("%lu: %s() called\n",jiffies,__func__);
+
+    // Sync reg_cache with the hardware
+    for(n=0;n<noof(cx2070x_regs);n++)
+        switch(cx2070x_regs[n].type&REG_TYPE_MASK)
+    {
+        case REG_TYPE_RO:
+            break;
+        case REG_TYPE_RW:
+        case REG_TYPE_WI:
+        case REG_TYPE_WC:
+            cx2070x_real_write(codec,n,cx2070x_read_reg_cache(codec,n));
+            break;
+#if defined(REG_TYPE_DM)
+        case REG_TYPE_DM:
+            break;
+#endif
+        default: 
+            snd_BUG();
+    }
+    cx2070x_dsp_init(codec,cx2070x_read_reg_cache(codec,DSP_INIT)|DSP_INIT_NEWC);
+    cx2070x_set_bias_level(codec, SND_SOC_BIAS_ON);
+    return 0;
+}
+
+static inline unsigned int cx2070x_read(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+    return 0;
+}
+
+struct snd_soc_codec_driver soc_codec_dev_cx2070x=
+{
+    .probe =cx2070x_probe,
+    .remove = cx2070x_remove,
+    .suspend = cx2070x_suspend,
+    .resume = cx2070x_resume,
+    .read = cx2070x_read,
+    .write = cx2070x_write,
+    .reg_cache_size = sizeof(cx2070x_data),
+    .reg_cache_step = 1,
+    .reg_word_size = sizeof(u8),
+    .reg_cache_default = cx2070x_data,
+    .set_bias_level = cx2070x_set_bias_level,
+
+};
+
+#if defined(USING_I2C)
+static int cx2070x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+    struct cx2070x_priv      *cx2070x;
+    int     ret = 0;
+
+    INFO("%lu: %s() called\n", jiffies, __func__);
+    
+    cx2070x = (struct cx2070x_priv*)kzalloc(sizeof(struct cx2070x_priv), GFP_KERNEL);
+    if (cx2070x == NULL)
+    {
+        return -ENOMEM;
+    }
+
+    i2c_set_clientdata(i2c, cx2070x);
+
+    cx2070x->control_data = (void*)i2c;
+    cx2070x->control_type =  SND_SOC_I2C;
+
+    cx2070x->input_sel = Cx_INPUT_SEL_BY_GPIO;
+    cx2070x->output_sel = Cx_OUTPUT_SEL_BY_GPIO;
+
+    ret =  snd_soc_register_codec(&i2c->dev,
+        &soc_codec_dev_cx2070x, &soc_codec_cx2070x_dai, 1);
+    printk(">>>>>>>%s ret = %d ",__func__,ret);
+
+    if (ret < 0)
+        INFO("%s() failed ret = %d\n", __func__, ret);
+    return ret;
+}
+
+static int cx2070x_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+#if defined(CONFIG_SND_CXLIFEGUARD)
+    cxdbg_dev_exit();
+#endif 
+       kfree(i2c_get_clientdata(client));
+    return 0;
+}
+
+static const struct i2c_device_id cx2070x_i2c_id[] = 
+{
+    { "cx2070x", 0 },
+    { }
+};
+
+MODULE_DEVICE_TABLE(i2c, cx2070x_i2c_id);
+static struct i2c_driver cx2070x_i2c_driver = {
+    .driver = {
+       .name = "cx2070x",
+       .owner = THIS_MODULE,
+     },
+    .probe=cx2070x_i2c_probe,
+    .remove=__devexit_p(cx2070x_i2c_remove),
+    .id_table=cx2070x_i2c_id,
+};
+
+#elif defined(USING_SPI)
+static int cx2070x_spi_probe(struct spi_device *spi)
+{
+    INFO("%lu: %s() called\n", jiffies, __func__);
+
+    struct cx2070x_priv      *cx2070x;
+    int     ret = 0;
+
+    //printk(KERN_INFO "Channel Audio Codec %08x\n", CX2070X_DRIVER_VERSION);
+
+    cx2070x = (struct cx2070x_priv      *)kzalloc(sizeof(struct cx2070x_priv), GFP_KERNEL);
+    if (cx2070x == NULL)
+    {
+        return -ENOMEM;
+    }
+
+    spi_set_drvdata(spi, cx2070x);
+
+    cx2070x->control_data = (void*)spi;
+    cx2070x->control_type =  SND_SOC_SPI;
+
+    cx2070x->input_sel = Cx_INPUT_SEL_BY_GPIO;
+    cx2070x->output_sel = Cx_OUTPUT_SEL_BY_GPIO;
+
+    ret =  snd_soc_register_codec(&spi->dev,
+        &soc_codec_dev_cx2070x, &soc_codec_cx2070x_dai, 1);
+
+    if (ret < 0)
+        INFO("%s() failed ret = %d\n", __func__, ret);
+    return ret;
+}
+
+static int cx2070x_spi_remove(struct spi_device *client)
+{
+    struct snd_soc_codec *codec = (struct snd_soc_codec *)spi_get_drvdata(client);
+
+    kfree(codec->reg_cache);
+    return 0;
+}
+
+static const struct spi_device_id cx2070x_spi_id[]={
+    { CX2070X_SPI_DRIVER_NAME,NULL},
+};
+
+static struct spi_driver cx2070x_spi_driver = {
+       .driver = {
+               .name   = "cx2070x-codec",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = cx2070x_spi_probe,
+       .remove         = __devexit_p(cx2070x_spi_remove),
+};
+#endif
+
+static  int __init cx2070x_modinit(void)
+{
+    int ret;
+    INFO("%lu: %s() called\n",jiffies,__func__);
+#if defined(USING_I2C)
+       ret = i2c_add_driver(&cx2070x_i2c_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register CX2070X I2C driver: %d\n",
+                      ret);
+       }
+#elif defined(USING_SPI)
+       ret = spi_register_driver(&cx2070x_spi_driver);
+       if (ret != 0) {
+               printk(KERN_ERR "Failed to register CX2070X SPI driver: %d\n",
+                      ret);
+       }
+#endif
+    return ret;
+}
+module_init(cx2070x_modinit);
+
+static void __exit cx2070x_exit(void)
+{
+    INFO("%lu: %s() called\n",jiffies,__func__);
+#if defined(USING_I2C)
+       i2c_del_driver(&cx2070x_i2c_driver);
+#elif defined(USING_SPI)
+       spi_unregister_driver(&cx2070x_spi_driver);
+#endif
+}
+module_exit(cx2070x_exit);
+
+int CX_AUDDRV_VERSION = CX2070X_DRIVER_VERSION;
+EXPORT_SYMBOL_GPL(CX_AUDDRV_VERSION);
+EXPORT_SYMBOL_GPL(soc_codec_dev_cx2070x);
+MODULE_DESCRIPTION("ASoC cx2070x Codec Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/cx2070x.h b/sound/soc/codecs/cx2070x.h
new file mode 100644 (file)
index 0000000..5b04e8f
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * ALSA SoC CX2070X Channel codec driver
+ *
+ * Copyright:   (C) 2009/2010 Conexant Systems
+ *
+ * Based on sound/soc/codecs/tlv320aic2x.c by Vladimir Barinov
+ *
+ * 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 _CX2070X_H
+#define _CX2070X_H
+
+
+#define CONFIG_SND_DIGICOLOR_SOC_CHANNEL_VER_4_30F 1
+
+#ifdef CONFIG_SND_SOC_CNXT_FW_UPDATE
+#define CONFIG_SND_CX2070X_LOAD_FW 1
+#endif
+//#define CONFIG_SND_CX2070X_USE_FW_H 1
+//#define CONFIG_CNXT_USING_SPI_BUS 1
+
+#ifdef CONFIG_SND_SOC_CNXT_JACKSENSE
+#define CONFIG_SND_CX2070X_GPIO_JACKSENSE 1
+#endif 
+//#define CONFIG_SND_CX2070X_GPIO_RESET    1
+#define CONFIG_SND_CXLIFEGUARD 1
+//#define CONFIG_CXNT_SOFTWOARE_SIMULATION      1
+#define  DBG_MONITOR_REG  1
+
+//#define GPIO_HP_JACKSENSE 178 //Tegra 250
+//.#define JACK_SENSE_GPIO_PIN    178 // Tegra
+//#define CODEC_RESET_GPIO_PIN   184 //  Tegra
+
+#define JACK_SENSE_GPIO_PIN   151 //s5pc110 GPH2_5
+#define CODEC_RESET_GPIO_PIN  157 //s5pc110 reset pin.
+#define FOR_MID 0
+
+#if (defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) ) && !defined(CONFIG_CNXT_USING_SPI_BUS)
+#define USING_I2C 1
+#endif 
+
+#if defined(CONFIG_SPI_MASTER) && defined(CONFIG_CNXT_USING_SPI_BUS)
+#define USING_SPI 1
+#endif 
+
+
+enum Cx_INPUT_SEL{
+    Cx_INPUT_SEL_BY_GPIO = 0,
+    Cx_INPUT_SEL_MIC,
+    Cx_INPUT_SEL_LINE,
+    Cx_INPUT_SEL_DPORT2,
+};
+
+enum Cx_OUTPUT_SEL{
+    Cx_OUTPUT_SEL_BY_GPIO = 0,
+    Cx_OUTPUT_SEL_SPK,
+    Cx_OUTPUT_SEL_LINE,
+    Cx_OUTPUT_SEL_HP,
+    Cx_OUTPUT_SEL_DPORT2,
+};
+
+#define CX2070X_I2C_DRIVER_NAME        "cx2070x-i2c"
+#define CX2070X_SPI_DRIVER_NAME        "cx2070x-spi"
+#define CX2070X_FIRMWARE_FILENAME "cnxt/cx2070x.fw"
+#define AUDDRV_VERSION(major0,major1, minor, build ) ((major0)<<24|(major1)<<16| (minor)<<8 |(build))
+
+#endif 
diff --git a/sound/soc/codecs/cxdebug.c b/sound/soc/codecs/cxdebug.c
new file mode 100644 (file)
index 0000000..43c4ab4
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+* ALSA SoC CX20709 Channel codec driver
+*
+* Copyright:   (C) 2009/2010 Conexant Systems
+*
+*
+* 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.
+*
+* 
+*      
+*************************************************************************
+*  Modified Date:  12/01/11
+*  File Version:   2.26.35.11
+*************************************************************************
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>      /* Specifically, a module */
+#include <linux/fs.h>
+#include <asm/uaccess.h>       /* for get_user and put_user */
+//#include <sound/core.h>
+//#include <sound/pcm.h>
+//#include <sound/pcm_params.h>
+#include <sound/soc.h>
+//#include <sound/soc-dapm.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+//#define DEBUG 1
+
+#include "cxdebug.h"
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#include <linux/i2c.h>
+#endif 
+
+#if defined(CONFIG_SPI_MASTER)
+#include <linux/spi/spi.h>
+#endif 
+
+
+/*
+* 
+ * Is the device open right now? Used to prevent
+ * concurent access into the same device 
+ */
+static int Device_Open = 0;
+extern int CX_AUDDRV_VERSION;
+struct snd_soc_codec *g_codec = NULL;
+
+/* 
+ * This is called whenever a process attempts to open the device file 
+ */
+static int cxdbg_dev_open(struct inode *inode, struct file *file)
+{
+#ifdef DEBUG
+    printk(KERN_INFO "cxdbg_dev: device_open(%p)\n", file);
+#endif
+
+    /* 
+    * We don't want to talk to two processes at the same time 
+    */
+    if (Device_Open)
+        return -EBUSY;
+
+    Device_Open++;
+    /*
+    * Initialize the message 
+    */
+
+   // try_module_get(THIS_MODULE);
+    return 0;
+}
+
+/* 
+ * This is called whenever a process attempts to open the device file 
+ */
+static int cxdbg_dev_release(struct inode *inode, struct file *file)
+{
+#ifdef DEBUG
+    printk(KERN_INFO "cxdbg_dev: device_release(%p)\n", file);
+#endif
+
+
+    Device_Open--;
+    /*
+    * Initialize the message 
+    */
+
+    return 0;
+}
+static int codec_reg_write(struct CXDBG_IODATA  *reg)
+{
+    int errno = 0;
+
+    BUG_ON(!g_codec);
+    BUG_ON(!g_codec->hw_write);
+
+    if(g_codec&& g_codec->hw_write)
+    {
+        if( g_codec->hw_write(g_codec,(char*)reg->data,reg->len) 
+            !=reg->len)
+        {
+            errno =-EIO;
+            printk(KERN_ERR "cxdbg_dev: codec_reg_write failed\n");
+        }
+    }
+    else
+    {
+        errno = -EBUSY;
+        printk(KERN_ERR "cxdbg_dev: codec_reg_write failed, device is not ready.\n");
+    }
+    return errno;
+}
+
+static unsigned int codec_reg_read(struct CXDBG_IODATA  *reg)
+{
+    int errno = 0;
+    unsigned int regaddr;
+    unsigned int data;
+
+
+    BUG_ON(!g_codec);
+    BUG_ON(!g_codec->hw_read);
+
+    if (reg-> len == 2)
+    {
+        regaddr = (((unsigned int)reg->data[0])<<8) + reg->data[1];
+    }
+    else if (reg->len == 1)
+    {
+        regaddr = (unsigned int)reg->data[0];
+    }
+    else 
+    {
+       printk(KERN_ERR "cxdbg_dev: codec_reg_read failed, invalid parameter.\n");
+       return -EINVAL;
+    }
+    memset(reg,0,sizeof(*reg));
+    if(g_codec && g_codec->hw_read)
+    {
+        data = g_codec->hw_read(g_codec,regaddr);
+        reg->data[0] = data & 0xFF;
+        reg->len     = 1;
+    }
+    else
+    {
+        errno = -EBUSY;
+        printk(KERN_ERR "cxdbg_dev: codec_reg_read failed, device is not ready.\n");
+    }
+    return errno;
+    return 0;
+}
+
+long cxdbg_dev_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
+{
+    struct CXDBG_IODATA  *reg=NULL ;
+    int __user *ip = (int __user*) arg;
+    long err = -1;
+#ifdef DEBUG
+    printk(KERN_INFO "cxdbg_dev: ioctl, cmd=0x%02x, arg=0x%02lx\n", cmd, arg);
+#endif
+    
+    /* 
+    * Switch according to the ioctl called 
+    */
+    switch (cmd) {
+    case CXDBG_IOCTL_REG_SET:
+       reg = (struct CXDBG_IODATA*) kmalloc(sizeof(*reg),GFP_KERNEL);
+        err = copy_from_user((char*) reg, (char*)arg,sizeof(*reg));
+        if(err==0)
+        {
+            codec_reg_write(reg);
+        }
+        break;
+
+    case CXDBG_IOCTL_REG_GET:
+       reg = (struct CXDBG_IODATA*) kmalloc(sizeof(*reg),GFP_KERNEL);
+        err =copy_from_user((char*) reg, (char*)arg,sizeof(*reg));
+        if( err == 0)
+        {
+           codec_reg_read(reg);
+           err = copy_to_user((char*) arg, (char*)reg,sizeof(*reg));
+        }
+        break;
+    case CXDBG_IOCTL_PDRIVER_VERSION:
+       err = put_user(CX_AUDDRV_VERSION,ip);
+       break;  
+    default:
+        err =  -EINVAL;
+    }
+
+    if(reg)
+    {
+       kfree(reg);
+    }
+
+    return err;
+}
+
+
+#if defined(_MSC_VER)
+static const struct file_operations cxdbg_dev_fops =
+{
+    /*.owner = */THIS_MODULE,
+    /*.llseek*/NULL,
+    /*.read =          */NULL,
+    /*.write*/ NULL,
+    /*.aio_read*/ NULL,
+    /*.aio_write*/NULL,
+    /*readdir*/NULL,
+    /*.poll*/NULL,
+    /*ioctl*/ NULL /*i2cdev_ioctl*/,
+    /*.unlocked_ioctl*/cxdbg_dev_ioctl,
+    /*.compat_ioctl*/NULL,
+    /*.mmap*/NULL,
+    /*.open*/cxdbg_dev_open,
+    /*.flush*/NULL,
+    /*.release*/NULL,
+    /*.fsync*/NULL,
+    /*.aio_fsync*/NULL,
+    /*.fasync*/NULL,
+    /*.lock*/NULL,
+    /*.sendpage*/NULL,
+};
+#else
+static const struct file_operations cxdbg_dev_fops = {
+    .owner          = THIS_MODULE,
+    .unlocked_ioctl = cxdbg_dev_ioctl,
+    .open           = cxdbg_dev_open,
+    .release        = cxdbg_dev_release,
+};
+#endif
+
+
+/* 
+* Initialize the module - Register the character device 
+*/
+int cxdbg_dev_init(struct snd_soc_codec *socdev)
+{
+    int err;
+    printk(KERN_INFO "cxdbg_dev: entries driver\n");
+
+    g_codec = socdev;
+
+    err = register_chrdev(CXDBG_MAJOR, CXDBG_DEVICE_NAME, &cxdbg_dev_fops);
+    if (err)
+    {
+        printk(KERN_ERR "cxdbg_dev: Driver Initialisation failed\n");
+    }
+    return err;
+}
+
+void cxdbg_dev_exit(void)
+{
+    unregister_chrdev(CXDBG_MAJOR,CXDBG_DEVICE_NAME);
+}
+
+
+MODULE_AUTHOR("Simon Ho<simon.ho@conexant.com");
+MODULE_DESCRIPTION("debug driver");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/codecs/cxdebug.h b/sound/soc/codecs/cxdebug.h
new file mode 100644 (file)
index 0000000..9e5b12d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+* ALSA SoC CX20709 Channel codec driver
+*
+* Copyright:   (C) 2009/2010 Conexant Systems
+*
+*
+* 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.
+*
+* 
+*      
+*************************************************************************
+*  Modified Date:  11/02/11
+*  File Version:   2.26.35.11 
+*************************************************************************
+*/
+#ifndef CXDEBUG_H
+#define CXDEBUG_H
+
+#define CXDBG_MAJOR    168             /* Device major number          */
+
+
+/* Use 'k' as magic number */
+#define CXDBG_IOC_MAGIC 'S'
+
+#define MAX_DATA_LEN      64
+struct CXDBG_IODATA{
+    unsigned short len;
+    unsigned char  data[MAX_DATA_LEN];
+};
+
+#define CXDBG_IOCTL_REG_SET             _IOWR(CXDBG_IOC_MAGIC, 1, struct CXDBG_IODATA)
+#define CXDBG_IOCTL_REG_GET            _IOWR(CXDBG_IOC_MAGIC, 2, struct CXDBG_IODATA)
+#define CXDBG_IOCTL_PDRIVER_VERSION     _IOR( CXDBG_IOC_MAGIC, 3, int)
+
+#define CXDBG_DEVICE_NAME "cxdbg"
+
+#ifdef __KERNEL__
+int cxdbg_dev_init(struct snd_soc_codec * codec);
+void cxdbg_dev_exit(void);
+#endif 
+
+#endif //#ifndef CXDEBUG_H
+
+
diff --git a/sound/soc/codecs/cxpump.c b/sound/soc/codecs/cxpump.c
new file mode 100644 (file)
index 0000000..9a26996
--- /dev/null
@@ -0,0 +1,978 @@
+/*\r
+ * ALSA SoC CX20709 Channel codec driver\r
+ *\r
+ * Copyright:   (C) 2009/2010 Conexant Systems\r
+ *\r
+ * \r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License version 2 as\r
+ * published by the Free Software Foundation.\r
+ *\r
+ * This code is to download the firmware to CX2070x device. \r
+ *      \r
+ *************************************************************************\r
+ *  Modified Date:  01/24/11\r
+ *  File Version:   1.0.0.1\r
+ *************************************************************************\r
+ */\r
+#if defined(_MSC_VER) \r
+// microsoft windows environment.\r
+#define  __BYTE_ORDER       __LITTLE_ENDIAN\r
+#define  __LITTLE_ENDIAN    1234\r
+#include <stdlib.h>   // For _MAX_PATH definition\r
+#include <stdio.h>\r
+#include <string.h>\r
+#define msleep(_x_) \r
+int printk(const char *s, ...);\r
+#define KERN_ERR "<3>"\r
+#elif defined(__KERNEL__)  \r
+// linux kernel environment.\r
+#include <linux/module.h>\r
+#include <linux/moduleparam.h>\r
+#include <linux/init.h>\r
+#include <linux/delay.h>\r
+#else\r
+//\r
+// linux user mode environment.\r
+//\r
+#include <stdlib.h>   // For _MAX_PATH definition\r
+#include <stdio.h>\r
+#endif\r
+#include "cxpump.h"\r
+\r
+#if defined( __BIG_ENDIAN) && !defined(__BYTE_ORDER)\r
+#define __BYTE_ORDER __BIG_ENDIAN\r
+#elif defined( __LITTLE_ENDIAN ) && !defined(__BYTE_ORDER)\r
+#define __BYTE_ORDER __LITTLE_ENDIAN\r
+#endif \r
+\r
+\r
+#ifndef __BYTE_ORDER\r
+#error __BYTE_ORDER is undefined.\r
+#endif \r
+\r
+#define ENABLE_I2C_BURST_MODE\r
+\r
+#if defined(_MSC_VER) \r
+#pragma warning(disable:4127 4706 4101) // conditional experssion is constant\r
+typedef enum I2C_STATE{I2C_OK,I2C_ERR,I2C_RETRY} ;\r
+void ShowProgress(int curPos,bool bForceRedraw, I2C_STATE eState, const int MaxPos);\r
+void InitShowProgress(const int MaxPos);\r
+#elif defined(__KERNEL__)  \r
+//linux kernel mode\r
+#define ShowProgress(curPos,bForceRedraw,eState, axPos)\r
+#define InitShowProgress(MaxPos)\r
+#else \r
+//linux user mode\r
+#define InitShowProgress(MaxPos)\r
+#define ShowProgress(curPos,bForceRedraw,eState, axPos)\r
+#endif\r
+\r
+\r
+#ifndef NULL\r
+#define NULL 0\r
+#endif //#ifndef NULL\r
+\r
+#define S_DESC          "Cnxt Channel Firmware"  /*Specify the string that will show on head of rom file*/\r
+#define S_ROM_FILE_NAME "cx2070x.fw"            /*Specify the file name of rom file*/\r
+#define CHIP_ADDR        0x14                    /*Specify the i2c chip address*/\r
+#define MEMORY_UPDATE_TIMEOUT  300\r
+#define MAX_ROM_SIZE (1024*1024)\r
+//#define DBG_ERROR  "ERROR  : "\r
+#define DBG_ERROR  KERN_ERR\r
+#define LOG( _msg_ )  printk  _msg_ \r
+//#define LOG( _msg_ )  ;\r
+\r
+typedef struct CX_CODEC_ROM_DATA\r
+{\r
+#ifdef USE_TYPE_DEFINE\r
+    unsigned long      Type;\r
+#endif //#ifdef USE_TYPE_DEFINE\r
+    unsigned long      Length;\r
+    unsigned long      Address;\r
+    unsigned char      data[1];\r
+}CX_CODEC_ROM_DATA;\r
+\r
+#define ROM_DATA_TYPE_S37           0xAA55CC01 // S37 format.\r
+#define ROM_DATA_TYPE_CNXT          0xAA55CC04 // Conexant SPI format.\r
+#define ROM_DATA_SEPARATED_LINE     0x23232323 //()()()()\r
+\r
+typedef struct CX_CODEC_ROM{\r
+    char                        sDesc[24]; \r
+    char                        cOpenBracket;\r
+    char                        sVersion[5];\r
+    char                        cCloseBracket;\r
+    char                        cEOF;\r
+    unsigned long               FileSize;\r
+    unsigned long               LoaderAddr;\r
+    unsigned long               LoaderLen;\r
+    unsigned long               CtlAddr;\r
+    unsigned long               CtlLen;\r
+    unsigned long               SpxAddr;\r
+    unsigned long               SpxLen;\r
+    struct CX_CODEC_ROM_DATA    Data[1];\r
+}CX_CODEC_ROM;\r
+\r
+typedef struct CX_CODEC_APPENDED_DATA\r
+{\r
+    unsigned char      Address[2];      // The address of data.\r
+    unsigned char      padding;      // The actual firmware data.\r
+    unsigned char      data;      // The actual firmware data.\r
+}CX_CODEC_APPENDED_DATA;\r
+\r
+typedef struct CX_CODEC_ROM_APPENDED{\r
+    unsigned long               TuningAddr;\r
+    unsigned long               TuningLen;\r
+    CX_CODEC_APPENDED_DATA      data[1]; // following by Jira id and time.\r
+}CX_CODEC_ROM_APPENDED;\r
+\r
+typedef struct CX_CODEC_ROM_APPENDED_INFO{\r
+    char                        sJIRAID[16];\r
+    char                        sTime[16];\r
+}CX_CODEC_ROM_APPENDED_INFO;\r
+\r
+\r
+// To convert two digital ASCII into one BYTE.\r
+unsigned char ASCII_2_BYTE( char ah, char al) ;\r
+\r
+#define BUF_SIZE 0x1000\r
+#define BIBF(_x_) if(!(_x_)) break;\r
+#define BIF(_x_) if((ErrNo=(_x_)) !=0) break;\r
+\r
+\r
+#ifndef BIBF\r
+#define BIBF( _x_ ) if(!(_x_)) break;\r
+#endif \r
+\r
+enum { \r
+    MEM_TYPE_RAM     = 1 /* CTL*/, \r
+    MEM_TYPE_SPX     = 2,\r
+    MEM_TYPE_EEPROM  = 3,\r
+    MEM_TYPE_CPX     =0x04,\r
+    MEM_TYPE_EEPROM_RESET  = 0x8003, //reset after writing.\r
+}; \r
+\r
+\r
+fun_I2cWriteThenRead g_I2cWriteThenReadPtr      = NULL;\r
+fun_I2cWrite         g_I2cWritePtr              = NULL;\r
+unsigned char *      g_AllocatedBuffer          = NULL;\r
+unsigned char *      g_Buffer                   = NULL;\r
+unsigned long        g_cbMaxWriteBufSize        = 0;\r
+void *               g_pContextI2cWrite         = NULL;\r
+void *               g_pContextI2cWriteThenRead = NULL;\r
+\r
+\r
+/*\r
+* The SetupI2cWriteCallback sets the I2cWrite callback function.\r
+* \r
+* PARAMETERS\r
+*  \r
+*    pCallbackContext [in] - A pointer to a caller-defined structure of data items\r
+*                            to be passed as the context parameter of the callback\r
+*                            routine each time it is called. \r
+*\r
+*    I2cWritePtr      [in] - A pointer to a i2cwirte callback routine, which is to \r
+*                            write I2C data. The callback routine must conform to \r
+*                            the following prototype:\r
+* \r
+*                        int (*fun_I2cWrite)(  \r
+*                                void * pCallbackContext,\r
+*                                unsigned char ChipAddr,\r
+*                                unsigned long cbBuf, \r
+*                                unsigned char* pBuf\r
+*                             );\r
+*\r
+*                        The callback routine parameters are as follows:\r
+*\r
+*                        pCallbackContext [in] - A pointer to a caller-supplied \r
+*                                                context area as specified in the\r
+*                                                CallbackContext parameter of \r
+*                                                SetupI2cWriteCallback. \r
+*                        ChipAddr         [in] - The i2c chip address.\r
+*                        cbBuf            [in] - The size of the input buffer, in bytes.\r
+*                        pBuf             [in] - A pointer to the input buffer that contains \r
+*                                                the data required to perform the operation.\r
+*\r
+*\r
+*    cbMaxWriteBuf    [in] - Specify the maximux transfer size for a I2c continue \r
+*                            writing with 'STOP'. This is limited in I2C bus Master\r
+*                            device. The size can not less then 3 since Channel \r
+*                            requires 2 address bytes plus a data byte.\r
+*                              \r
+*\r
+*\r
+* RETURN\r
+*  \r
+*    None\r
+*\r
+*/\r
+void SetupI2cWriteCallback( void * pCallbackContext,\r
+    fun_I2cWrite         I2cWritePtr,\r
+    unsigned long        cbMaxWriteBufSize)\r
+{\r
+    g_pContextI2cWrite  = pCallbackContext;\r
+    g_I2cWritePtr       = I2cWritePtr;\r
+    g_cbMaxWriteBufSize = cbMaxWriteBufSize;\r
+}\r
+\r
+/*\r
+* The SetupI2cWriteThenReadCallback sets the SetupI2cWriteThenRead callback function.\r
+* \r
+* PARAMETERS\r
+*  \r
+*    pCallbackContext    [in] - A pointer to a caller-defined structure of data items\r
+*                               to be passed as the context parameter of the callback\r
+*                               routine each time it is called. \r
+*\r
+*    I2cWriteThenReadPtr [in] - A pointer to a i2cwirte callback routine, which is to \r
+*                               write I2C data. The callback routine must conform to \r
+*                               the following prototype:\r
+*\r
+*                        int (*fun_I2cWriteThenRead)(  \r
+*                                void * pCallbackContext,\r
+*                                unsigned char ChipAddr,\r
+*                                unsigned long cbBuf, \r
+*                                unsigned char* pBuf\r
+*                             );\r
+*\r
+*                        The callback routine parameters are as follows:\r
+*\r
+*                         pCallbackContext [in] - A pointer to a caller-supplied \r
+*                                                 context area as specified in the\r
+*                                                 CallbackContext parameter of \r
+*                                                 SetupI2cWriteCallback. \r
+*                         ChipAddr         [in] - The i2c chip address.\r
+*                         cbBuf            [in] - The size of the input buffer, in bytes.\r
+*                         pBuf             [in] - A pointer to the input buffer that contains \r
+*                                                 the data required to perform the operation.\r
+*\r
+* RETURN\r
+*      None\r
+* \r
+*/\r
+void SetupI2cWriteThenReadCallback( void * pCallbackContext,\r
+    fun_I2cWriteThenRead I2cWriteThenReadPtr)\r
+{\r
+    g_pContextI2cWriteThenRead  = pCallbackContext;\r
+    g_I2cWriteThenReadPtr       = I2cWriteThenReadPtr;\r
+}\r
+\r
+void SetupMemoryBuffer(void * pAllocedMemoryBuffer)\r
+{\r
+    g_AllocatedBuffer = (unsigned char*)pAllocedMemoryBuffer;\r
+    g_Buffer = g_AllocatedBuffer +2;\r
+}\r
+\r
+/*\r
+* Convert a 4-byte number from a ByteOrder into another ByteOrder.\r
+*/\r
+unsigned long ByteOrderSwapULONG(unsigned long i)\r
+{\r
+    return((i&0xff)<<24)+((i&0xff00)<<8)+((i&0xff0000)>>8)+((i>>24)&0xff);\r
+}\r
+\r
+/*\r
+* Convert a 2-byte number from a ByteOrder into another ByteOrder.\r
+*/\r
+unsigned short ByteOrderSwapWORD(unsigned short i)\r
+{\r
+    return ((i>>8)&0xff)+((i << 8)&0xff00);\r
+}\r
+\r
+/*\r
+* Convert a 4-byte number from generic byte order into Big Endia\r
+*/\r
+unsigned long ToBigEndiaULONG(unsigned long i)\r
+{\r
+#if __BYTE_ORDER == __LITTLE_ENDIAN\r
+    return ByteOrderSwapULONG(i);\r
+#else\r
+    return i;\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+* Convert a 2-byte number from generic byte order into Big Endia\r
+*/\r
+unsigned short ToBigEndiaWORD(unsigned short i)\r
+{\r
+#if __BYTE_ORDER == __LITTLE_ENDIAN\r
+    return ByteOrderSwapWORD(i);\r
+#else\r
+    return i;\r
+#endif\r
+}\r
+\r
+/*\r
+* Convert a 4-byte number from Big Endia into generic byte order.\r
+*/\r
+unsigned long FromBigEndiaULONG(unsigned long i)\r
+{\r
+#if __BYTE_ORDER == __LITTLE_ENDIAN\r
+    return ByteOrderSwapULONG(i);\r
+#else\r
+    return i;\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+* Convert a 2-byte number from Big Endia into generic byte order.\r
+*/\r
+unsigned short FromBigEndiaWORD(unsigned short i)\r
+{\r
+#if __BYTE_ORDER == __LITTLE_ENDIAN\r
+    return ByteOrderSwapWORD(i);\r
+#else\r
+    return i;\r
+#endif\r
+}\r
+\r
+\r
+/*\r
+* To convert two digital ASCII into one BYTE.\r
+*/\r
+unsigned char ASCII_2_BYTE( char ah, char al) \r
+{\r
+    unsigned char ret = '\0';\r
+    int i =2;\r
+\r
+    for(;i>0;i--)\r
+    {\r
+        if( 'a' <= ah && 'f' >= ah)\r
+        {\r
+            ret += ah - 'a'+10;\r
+        }\r
+        else if( 'A' <= ah && 'F' >= ah)\r
+        {\r
+            ret += ah -'A'+10;\r
+        }\r
+\r
+        else if( '0' <= ah && '9' >= ah)\r
+        {\r
+            ret += ah - '0';\r
+        }\r
+        else\r
+        {\r
+            LOG((DBG_ERROR "Invalid txt data.\n"));\r
+\r
+            // ErrNo = ERRNO_INVALID_DATA;\r
+            break;\r
+        }\r
+        ah =al;\r
+        if(i==2)\r
+            ret = (unsigned short)ret << 4;\r
+    }\r
+    return ret;\r
+}\r
+\r
+/*\r
+* Read a byte from the specified  register address.\r
+* \r
+* PARAMETERS\r
+*  \r
+*    RegAddr             [in] - Specifies the register address.\r
+*\r
+* RETURN\r
+*  \r
+*    Returns the byte that is read from the specified register address.\r
+*\r
+*/\r
+unsigned char ReadReg(unsigned short RegAddr)\r
+{\r
+\r
+    unsigned char RegData;\r
+\r
+    if(!g_I2cWriteThenReadPtr)\r
+    {\r
+        LOG((DBG_ERROR "i2C function is not set.\n"));\r
+        return 0;\r
+    }\r
+\r
+\r
+    RegAddr = ToBigEndiaWORD(RegAddr);\r
+\r
+    g_I2cWriteThenReadPtr(g_pContextI2cWriteThenRead,CHIP_ADDR,\r
+        2,(unsigned char*) &RegAddr,1,&RegData);\r
+\r
+    return RegData;\r
+}\r
+\r
+\r
+/*\r
+* Write a byte from the specified register address.\r
+* \r
+* PARAMETERS\r
+*  \r
+*    RegAddr             [in] - Specifies the register address.\r
+*\r
+* RETURN\r
+*  \r
+*    Returns the byte that is read from the specified register address.\r
+*\r
+* REMARK\r
+* \r
+*    The g_I2cWriteThenReadPtr must be set before calling this function.\r
+*/\r
+int WriteReg(unsigned short RegAddr, unsigned char RegData)\r
+{\r
+    unsigned char WrBuf[3];\r
+\r
+    if(!g_I2cWritePtr)\r
+    {\r
+        LOG((DBG_ERROR "i2C function is not set.\n"));\r
+        return -ERRNO_I2CFUN_NOT_SET;\r
+    }\r
+\r
+    *((unsigned short*) WrBuf) = ToBigEndiaWORD(RegAddr);\r
+    WrBuf[2] = RegData;\r
+\r
+    g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR,sizeof(WrBuf),WrBuf);\r
+\r
+    return ERRNO_NOERR;\r
+}\r
+\r
+/*\r
+*  Writes a number of bytes from a buffer to Channel via I2C bus.\r
+*  \r
+* PARAMETERS\r
+*  \r
+*    NumOfBytes         [in] - Specifies the number of bytes to be written\r
+*                              to the memory address.\r
+*    pData              [in] - Pointer to a buffer from an array of I2C data\r
+*                              are to be written.\r
+*  \r
+* RETURN\r
+*  \r
+*    If the operation completes successfully, the return value is ERRNO_NOERR.\r
+*    Otherwise, return ERRON_* error code. \r
+*/\r
+int ChannelI2cBulkWrite( unsigned long NumOfBytes, unsigned char *pData)\r
+{\r
+    int ErrNo           = ERRNO_NOERR;\r
+    unsigned short CurAddr;\r
+\r
+    //unsigned char  *pDataEnd            = pData + NumOfBytes;\r
+    unsigned char  *pCurData            = pData;\r
+    unsigned short *pCurAddrByte        = NULL;\r
+    unsigned long  BytesToProcess       = 0;\r
+    unsigned short backup               = 0;\r
+    const unsigned long cbAddressBytes  = 2;\r
+    const unsigned long cbMaxDataLen    = g_cbMaxWriteBufSize-cbAddressBytes;\r
+\r
+\r
+    if(!g_I2cWritePtr )\r
+    {\r
+        LOG((DBG_ERROR "i2C function is not set.\n"));\r
+        return -ERRNO_I2CFUN_NOT_SET;\r
+    }\r
+\r
+    //assert(NumOfBytes < 3);\r
+    CurAddr = FromBigEndiaWORD( *((unsigned short*)pData));\r
+\r
+    //skip first 2 bytes data (address).\r
+    NumOfBytes -= cbAddressBytes;\r
+    pCurData   += cbAddressBytes;\r
+\r
+    for(;NumOfBytes;)\r
+    {\r
+        BytesToProcess = NumOfBytes > cbMaxDataLen? cbMaxDataLen : NumOfBytes;\r
+        NumOfBytes-= BytesToProcess;\r
+        // save the pervious 2 bytes for later use.\r
+        pCurAddrByte = (unsigned short*) (pCurData -cbAddressBytes);\r
+        backup       = *pCurAddrByte;\r
+        *pCurAddrByte=  ToBigEndiaWORD(CurAddr);\r
+        BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, BytesToProcess + cbAddressBytes,(unsigned char*)pCurAddrByte));\r
+        //restore the data \r
+        *pCurAddrByte = backup;\r
+\r
+        pCurData += BytesToProcess;\r
+        CurAddr  += (unsigned short)BytesToProcess;\r
+    }\r
+    return ErrNo;\r
+}\r
+\r
+/*\r
+*  Writes a number of bytes from a buffer to the specified memory address.\r
+*\r
+* PARAMETERS\r
+*\r
+*    dwAddr             [in] - Specifies the memory address.\r
+*    NumOfBytes         [in] - Specifies the number of bytes to be written\r
+*                              to the memory address.\r
+*    pData              [in] - Pointer to a buffer from an struct of \r
+*                              CX_CODEC_ROM_DATA is to be written.\r
+*    MemType            [in] - Specifies the requested memory type, the value must be from \r
+*                              the following table.\r
+*\r
+*                              MEM_TYPE_RAM     = 1\r
+*                              MEM_TYPE_SPX     = 2\r
+*                              MEM_TYPE_EEPROM  = 3\r
+*\r
+* RETURN\r
+*  \r
+*    If the operation completes successfully, the return value is ERRNO_NOERR.\r
+*    Otherwise, return ERRON_* error code. \r
+*/\r
+int CxWriteMemory(unsigned long dwAddr, unsigned long NumOfBytes, unsigned char * pData, int MemType )\r
+{\r
+    int ErrNo           = ERRNO_NOERR;\r
+    unsigned char      Address[4];\r
+    unsigned char      WrData[8];\r
+    unsigned char      offset = 0;\r
+    const unsigned long MAX_BUF_LEN = 0x100;\r
+    unsigned char      cr = 0;\r
+    int                 bNeedToContinue = 0;\r
+    int                 i=0;\r
+\r
+\r
+    const unsigned long cbAddressBytes  = 2;\r
+\r
+    unsigned short *    pAddressByte;\r
+    unsigned char *pEndData  = pData + NumOfBytes;\r
+    unsigned short      RegMemMapAddr = ToBigEndiaWORD(0x300);\r
+    unsigned long       BytesToProcess = 0;\r
+\r
+    while(NumOfBytes)\r
+    {\r
+\r
+        BytesToProcess = NumOfBytes <= MAX_BUF_LEN ? NumOfBytes : MAX_BUF_LEN;\r
+        NumOfBytes -= BytesToProcess;\r
+        pEndData  = pData + BytesToProcess;\r
+\r
+        *((unsigned long*)&Address) = ToBigEndiaULONG(dwAddr);\r
+        //        dwAddr += offset;\r
+        offset = 0;\r
+\r
+        if( !bNeedToContinue )\r
+        {\r
+#ifdef ENABLE_I2C_BURST_MODE\r
+            //\r
+            //  Update the memory target address and buffer length.\r
+            //\r
+            WrData[0] = 0x02;    //update target address Low 0x02FC \r
+            WrData[1] = 0xFC;\r
+            WrData[2] = Address[3];\r
+            WrData[3] = Address[2];\r
+            WrData[4] = Address[1];\r
+            WrData[5] = (unsigned char)BytesToProcess -1 ;  // X bytes - 1\r
+            BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 6 , WrData));\r
+#else\r
+            //\r
+            //  Update the memory target address and buffer length.\r
+            //\r
+            WrData[0] = 0x02;    //update target address Low 0x02FC \r
+            WrData[1] = 0xFC;\r
+            WrData[2] = Address[3];\r
+            BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));\r
+\r
+            WrData[0] = 0x02;    //update target address Middle 0x02FD\r
+            WrData[1] = 0xFD;\r
+            WrData[2] = Address[2];\r
+            BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));\r
+\r
+            WrData[0] = 0x02;    //update target address High 0x02FE\r
+            WrData[1] = 0xFE;\r
+            WrData[2] = Address[1];\r
+            BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));\r
+\r
+            WrData[0] = 0x02;    //update Buffer Length.  0x02FF\r
+            WrData[1] = 0xFF;\r
+            WrData[2] = (unsigned char)BytesToProcess -1 ;  // X bytes - 1\r
+            BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));\r
+#endif\r
+        }\r
+\r
+        //\r
+        //  Update buffer.\r
+        //\r
+#ifdef ENABLE_I2C_BURST_MODE\r
+        pAddressByte = (unsigned short*) (pData - cbAddressBytes);\r
+        memcpy(g_Buffer, pAddressByte, BytesToProcess+cbAddressBytes);\r
+        *((unsigned short*)g_Buffer) = RegMemMapAddr;\r
+        ChannelI2cBulkWrite(BytesToProcess+cbAddressBytes, (unsigned char*)g_Buffer);\r
+        pData = pEndData;\r
+#else\r
+        for(offset=0;pData != pEndData;offset++,pData++)\r
+        {\r
+            WrData[0] = 0x03;   //update Buffer [0x0300 - 0x03ff]\r
+            WrData[1] = (unsigned char) offset;\r
+            WrData[2] = *pData;\r
+            BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));\r
+        }\r
+#endif \r
+\r
+        //\r
+        // Commit the changes and start to transfer buffer to memory.\r
+        //\r
+        if( MemType == MEM_TYPE_RAM)\r
+        {\r
+            cr = 0x81;\r
+        }\r
+        else if( MemType == MEM_TYPE_EEPROM)\r
+        {\r
+            cr = 0x83;\r
+        }\r
+        else if( MemType == MEM_TYPE_SPX)\r
+        {\r
+            cr = 0x85;\r
+            if( bNeedToContinue )\r
+            {\r
+                cr |= 0x08;\r
+            }\r
+        }\r
+\r
+        WrData[0] = 0x04;   // UpdateCtl [0x400]\r
+        WrData[1] = 0x00;\r
+        WrData[2] = cr;   // start to transfer  \r
+        BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));\r
+\r
+        for(i = 0;i<MEMORY_UPDATE_TIMEOUT;i++)\r
+        {\r
+\r
+            // loop until the writing is done.\r
+            WrData[0] = ReadReg(0x0400);\r
+            if(!( WrData[0] & 0x80 ))\r
+            {\r
+                //done\r
+                break;\r
+            }\r
+            else\r
+            {\r
+                //pending\r
+                if(MemType== MEM_TYPE_EEPROM)\r
+                {   \r
+                    //it needs more time for updating eeprom.\r
+                    msleep(5); // need more waiting  \r
+                }\r
+                else\r
+                {\r
+                    udelay(1);\r
+                }\r
+                continue;\r
+            }\r
+        }\r
+\r
+        if( i == MEMORY_UPDATE_TIMEOUT)\r
+        {\r
+            //writing failed.\r
+            LOG( (DBG_ERROR "memory update timeout.\n"));\r
+            ErrNo = -ERRNO_UPDATE_MEMORY_FAILED;\r
+\r
+            break;\r
+        }\r
+        if ( i >= 1) \r
+        {\r
+           printk( KERN_ERR "write pending loop =%d\n", i);\r
+        }      \r
+\r
+        bNeedToContinue = 1; \r
+    }while(0);\r
+\r
+    return ErrNo ;\r
+}\r
+\r
+#define WAIT_UNTIL_DEVICE_READY(_x_,_msg_) \\r
+for (timeout=0;timeout<dev_ready_time_out;timeout++) \\r
+{                                                    \\r
+    Ready = ReadReg(0x1000);                         \\r
+    if (Ready _x_) break;                       \\r
+    msleep(10);                                      \\r
+};                                                   \\r
+if( timeout == dev_ready_time_out)                   \\r
+{                                                    \\r
+    printk(KERN_ERR _msg_); \\r
+    ErrNo = -ERRNO_DEVICE_OUT_OF_CONTROL;             \\r
+    break;                                           \\r
+}            \r
+\r
+unsigned int CxGetFirmwarePatchVersion(void)\r
+{\r
+    unsigned int FwPatchVersion = 0;\r
+    int ErrNo;\r
+\r
+\r
+    if( NULL == g_I2cWriteThenReadPtr||\r
+        NULL == g_I2cWritePtr)\r
+    {\r
+        ErrNo = -ERRNO_I2CFUN_NOT_SET;\r
+        LOG( (DBG_ERROR "i2C function is not set.\n"));\r
+        return 0;\r
+    }\r
+\r
+    FwPatchVersion = ReadReg(0x1584);\r
+    FwPatchVersion <<= 8;\r
+    FwPatchVersion |= ReadReg(0x1585);\r
+    FwPatchVersion <<= 8;\r
+    FwPatchVersion |= ReadReg(0x1586);\r
+\r
+    return FwPatchVersion;\r
+}\r
+\r
+unsigned int CxGetFirmwareVersion(void)\r
+{\r
+    unsigned int FwVersion = 0;\r
+    int ErrNo;\r
+\r
+\r
+    if( NULL == g_I2cWriteThenReadPtr||\r
+        NULL == g_I2cWritePtr)\r
+    {\r
+        ErrNo = -ERRNO_I2CFUN_NOT_SET;\r
+        LOG( (DBG_ERROR "i2C function is not set.\n"));\r
+        return 0;\r
+    }\r
+\r
+    FwVersion = ReadReg(0x1002);\r
+    FwVersion <<= 8;\r
+    FwVersion |= ReadReg(0x1001);\r
+    FwVersion <<= 8;\r
+    FwVersion |= ReadReg(0x1006);\r
+\r
+    return FwVersion;\r
+}\r
+\r
+// return number, 0= failed. 1  = successful. \r
+int DownloadFW(const unsigned char * const pRomBin)\r
+{\r
+    int ErrNo = ERRNO_NOERR;\r
+    struct CX_CODEC_ROM      *pRom  = (struct CX_CODEC_ROM  *)pRomBin;\r
+    struct CX_CODEC_ROM_DATA *pRomData;\r
+    struct CX_CODEC_ROM_DATA *pRomDataEnd;\r
+    unsigned char            *pData;\r
+    unsigned char            *pDataEnd;\r
+    unsigned long            CurAddr = 0;\r
+    unsigned long            cbDataLen = 0;\r
+    unsigned char            Ready;\r
+    unsigned long            curProgress = 0;\r
+    unsigned long            TotalLen    = 0;\r
+    unsigned long            i = 0;\r
+    const unsigned long      dev_ready_time_out = 100;\r
+    int                      bIsRomVersion  = 0;           \r
+    const char               CHAN_PATH[]="CNXT CHANNEL PATCH";    \r
+    unsigned long            timeout;\r
+    unsigned long            fwVer;\r
+    unsigned long            fwPatchVer;\r
+\r
+    do{\r
+        if(pRom == NULL ||g_Buffer == NULL)\r
+        {\r
+            ErrNo = -ERRNO_INVALID_PARAMETER;\r
+            LOG( (DBG_ERROR "Invalid parameter.\n"));\r
+            break;\r
+        }\r
+\r
+        if( NULL == g_I2cWriteThenReadPtr||\r
+            NULL == g_I2cWritePtr)\r
+        {\r
+            ErrNo = -ERRNO_I2CFUN_NOT_SET;\r
+            LOG( (DBG_ERROR "i2C function is not set.\n"));\r
+            break;\r
+        }\r
+               \r
+        //check if codec is ROM version\r
+        if (0 == memcmp(CHAN_PATH,pRom->sDesc,sizeof(CHAN_PATH)-1)) {\r
+                       printk(KERN_INFO "[CNXT] sDesc = %s", pRom->sDesc);\r
+                       bIsRomVersion = 1;\r
+        }\r
+\r
+        if (bIsRomVersion) {\r
+            WAIT_UNTIL_DEVICE_READY(== 0X01,"cx2070x: Timed out waiting for codecto be ready!\n");\r
+        } else {\r
+            //Check if there is a FIRMWARE present. the Channel should get\r
+            // a clear reset signal before we download firmware to it.\r
+            if( (ReadReg(0x009) & 0x04) == 0) {\r
+                LOG((DBG_ERROR "cx2070x: did not get a clear reset..!"));\r
+                ErrNo = -ERRNO_DEVICE_NOT_RESET;\r
+                break;\r
+            }\r
+               }\r
+\r
+        TotalLen = FromBigEndiaULONG(pRom->LoaderLen) + FromBigEndiaULONG(pRom->CtlLen) + FromBigEndiaULONG(pRom->SpxLen);\r
+       // InitShowProgress(TotalLen);\r
+\r
+        //Download the loader.\r
+        pRomData    = (struct CX_CODEC_ROM_DATA *) ( (char*)pRom + FromBigEndiaULONG(pRom->LoaderAddr));\r
+        pRomDataEnd = (struct CX_CODEC_ROM_DATA *) ((char*)pRomData +FromBigEndiaULONG(pRom->LoaderLen));\r
+\r
+        for( ;pRomData!=pRomDataEnd;)\r
+        {\r
+#ifdef ENABLE_I2C_BURST_MODE\r
+            pData   = &pRomData->data[0];\r
+            pDataEnd= pData + FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned long); \r
+            memcpy(g_Buffer, pData-2, FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned short));\r
+            BIF(ChannelI2cBulkWrite( FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned short), g_Buffer));\r
+            curProgress +=  FromBigEndiaULONG(pRomData->Length) ;\r
+            ShowProgress(curProgress,false, I2C_OK,TotalLen);\r
+\r
+            pRomData = (struct CX_CODEC_ROM_DATA *)pDataEnd;\r
+\r
+#else\r
+            CurAddr = FromBigEndiaULONG(pRomData->Address);\r
+            pData   = &pRomData->data[0];\r
+            pDataEnd= pData + FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned long); \r
+            for( ;pData!=pDataEnd;pData++)\r
+            {\r
+                *((unsigned short*)writeBuf) = ToBigEndiaWORD((unsigned short)CurAddr);\r
+                writeBuf[2]= *pData;\r
+                g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR,3, writeBuf);\r
+                CurAddr++;\r
+            }\r
+            pRomData = (struct CX_CODEC_ROM_DATA *)pData;\r
+#endif \r
+\r
+        }\r
+\r
+        //* check if the device is ready.\r
+        if (bIsRomVersion) {\r
+            WAIT_UNTIL_DEVICE_READY(== 0X01,"cx2070x: Timed out waiting for cx2070x to be ready after loader downloaded!\n");\r
+        } else { \r
+            WAIT_UNTIL_DEVICE_READY(!= 0xFF,"cx2070x: Timed out waiting for cx2070x to be ready after loader downloaded!\n");\r
+               }\r
+\r
+        //Download the CTL\r
+        pRomData    = (struct CX_CODEC_ROM_DATA *) ( (char*)pRom + FromBigEndiaULONG(pRom->CtlAddr ));\r
+        pRomDataEnd = (struct CX_CODEC_ROM_DATA *) ((char*)pRomData +FromBigEndiaULONG(pRom->CtlLen));\r
+\r
+        for( ;pRomData!=pRomDataEnd;)\r
+        {\r
+            CurAddr = FromBigEndiaULONG(pRomData->Address);\r
+            pData       = &pRomData->data[0];\r
+            cbDataLen   = FromBigEndiaULONG(pRomData->Length) ;\r
+            BIF(CxWriteMemory(CurAddr,cbDataLen -sizeof(unsigned long)/*subtracts the address bytes*/ , pData, MEM_TYPE_RAM ));\r
+            // The next RoMData position = current romData position + cbDataLen + sizeof( data len bytes)\r
+            pRomData  =   (struct CX_CODEC_ROM_DATA *)((char*) pRomData + cbDataLen + sizeof(unsigned long));  \r
+\r
+            curProgress +=  cbDataLen ;\r
+            ShowProgress(curProgress,false, I2C_OK,TotalLen);\r
+        }\r
+\r
+        pRomData    = (struct CX_CODEC_ROM_DATA *) ( (char*)pRom + FromBigEndiaULONG(pRom->SpxAddr ));\r
+        pRomDataEnd = (struct CX_CODEC_ROM_DATA *) ((char*)pRomData +FromBigEndiaULONG(pRom->SpxLen));\r
+\r
+        for( ;pRomData!=pRomDataEnd;)\r
+        {\r
+            CurAddr = FromBigEndiaULONG(pRomData->Address);\r
+            pData       = &pRomData->data[0];\r
+            cbDataLen   = FromBigEndiaULONG(pRomData->Length) ;\r
+            BIF(CxWriteMemory(CurAddr,cbDataLen -sizeof(unsigned long)/*subtracts the address bytes*/ , pData, MEM_TYPE_SPX ));\r
+            // The next RoMData position = current romData position + cbDataLen + sizeof( data len bytes)\r
+            pRomData  =   (struct CX_CODEC_ROM_DATA *)((char*) pRomData + cbDataLen + sizeof(unsigned long));  \r
+\r
+            curProgress +=  cbDataLen ;\r
+            ShowProgress(curProgress,false, I2C_OK,TotalLen);\r
+        }\r
+\r
+        if(ErrNo != 0) break;\r
+\r
+        ShowProgress(TotalLen,false, I2C_OK,TotalLen);\r
+\r
+        //\r
+        // Reset\r
+        //\r
+        if(bIsRomVersion)\r
+        {\r
+            WriteReg(0x1000,0x00);\r
+         //   msleep(400); //delay 400 ms\r
+        }\r
+        else\r
+        {\r
+            WriteReg(0x400,0x40);\r
+            msleep(400); //delay 400 ms\r
+        }\r
+       \r
+       WAIT_UNTIL_DEVICE_READY(== 0x01,"cx2070x: Timed out waiting for cx2070x to be ready after firmware downloaded!\n");\r
+\r
+        //check if XPS code is working or not.\r
+\r
+        WriteReg(0x117d,0x01);\r
+        for (timeout=0;timeout<dev_ready_time_out;timeout++) \r
+        {                                                    \r
+            Ready = ReadReg(0x117d);                         \r
+            if (Ready == 0x00) break;                            \r
+            msleep(1);                                      \r
+        };                                                   \r
+        if( timeout == dev_ready_time_out)                   \r
+        {                                                    \r
+            LOG((DBG_ERROR "cx2070x: DSP lockup! download firmware failed!")); \r
+            ErrNo = -ERRNO_DEVICE_DSP_LOCKUP;          \r
+            break;                                           \r
+        } \r
+\r
+        fwVer = CxGetFirmwareVersion();\r
+        if(bIsRomVersion)\r
+        {\r
+            fwPatchVer = CxGetFirmwarePatchVersion();\r
+            printk(KERN_INFO "cx2070x: firmware download successfully! FW: %u,%u,%u, FW Patch: %u,%u,%u\n",\r
+                (unsigned char)(fwVer>>16),  \r
+                (unsigned char)(fwVer>>8),  \r
+                (unsigned char)fwVer,\r
+                (unsigned char)(fwPatchVer>>16),  \r
+                (unsigned char)(fwPatchVer>>8),  \r
+                (unsigned char)fwPatchVer);\r
+        }\r
+        else\r
+        {\r
+             printk(KERN_INFO "cx2070x: firmware download successfully! FW: %u,%u,%u\n",\r
+                (unsigned char)(fwVer>>16),  \r
+                (unsigned char)(fwVer>>8),  \r
+                (unsigned char)fwVer);\r
+        }\r
+\r
+    }while(0);\r
+\r
+    return ErrNo;\r
+}\r
+\r
+int ApplyDSPChanges(const unsigned char *const pRom)\r
+{\r
+    int ErrNo = ERRNO_NOERR;\r
+    struct CX_CODEC_ROM* pNewRom ;\r
+    struct CX_CODEC_ROM_APPENDED *pRomAppended;\r
+    struct CX_CODEC_ROM_APPENDED_INFO *pInfo;\r
+    struct CX_CODEC_APPENDED_DATA    *pData;\r
+    struct CX_CODEC_APPENDED_DATA    *pDataEnd;\r
+    unsigned short                    wRegAddr;\r
+    unsigned char                     NewC;\r
+\r
+#define DESC_LEN   (16)\r
+    char szJira[DESC_LEN+1];\r
+    char szDate[DESC_LEN+1];\r
+\r
+    pNewRom = (struct CX_CODEC_ROM*) pRom;\r
+\r
+    // check if firmware contains DSP tuning data.\r
+    if( (FromBigEndiaULONG(pNewRom->SpxLen) + FromBigEndiaULONG(pNewRom->SpxAddr)) != FromBigEndiaULONG(pNewRom->FileSize) ) \r
+    {\r
+      // has DSP Tuning data.\r
+\r
+        pRomAppended = (struct CX_CODEC_ROM_APPENDED*)((char*)pNewRom + FromBigEndiaULONG(pNewRom->SpxAddr) + FromBigEndiaULONG(pNewRom->SpxLen));\r
+        pInfo = (struct CX_CODEC_ROM_APPENDED_INFO*) ((char*)pNewRom + FromBigEndiaULONG(pRomAppended ->TuningAddr) + \r
+            FromBigEndiaULONG(pRomAppended ->TuningLen));\r
+\r
+        strncpy(szJira,pInfo->sJIRAID,DESC_LEN);\r
+        strncpy(szDate,pInfo->sTime,DESC_LEN);\r
+        szJira[DESC_LEN]=0;\r
+        szDate[DESC_LEN-1]=0; //remove the last lettle $.\r
+        printk(KERN_INFO "Applying the DSP tuning changes..Jira: %s Date: %s\n"\r
+                                                       ,szJira,szDate);\r
+\r
+        pData     = pRomAppended->data; \r
+        pDataEnd  = (struct CX_CODEC_APPENDED_DATA*)((char*)pData + FromBigEndiaULONG(pRomAppended->TuningLen));\r
+        for(;pData != pDataEnd; pData++)\r
+        {\r
+            wRegAddr = pData->Address[0];\r
+            wRegAddr <<=8;\r
+            wRegAddr |= pData->Address[1];\r
+            WriteReg(wRegAddr,pData->data);\r
+            //printk(KERN_INFO "0X%04x=0x%02x\n",wRegAddr,pData->data);\r
+        }\r
+        // re-set NewC.\r
+        NewC = ReadReg(0x117d); \r
+        WriteReg(0x117d,NewC|1);\r
+    }\r
+    \r
+    return ErrNo;\r
+}\r
+\r
diff --git a/sound/soc/codecs/cxpump.h b/sound/soc/codecs/cxpump.h
new file mode 100644 (file)
index 0000000..825b070
--- /dev/null
@@ -0,0 +1,206 @@
+/****************************************************************************************\r
+*****************************************************************************************\r
+***                                                                                   ***\r
+***                                 Copyright (c) 2011                                ***\r
+***                                                                                   ***\r
+***                                Conexant Systems, Inc.                             ***\r
+***                                                                                   ***\r
+***                                 All Rights Reserved                               ***\r
+***                                                                                   ***\r
+***                                    CONFIDENTIAL                                   ***\r
+***                                                                                   ***\r
+***               NO DISSEMINATION OR USE WITHOUT PRIOR WRITTEN PERMISSION            ***\r
+***                                                                                   ***\r
+*****************************************************************************************\r
+**\r
+**  File Name:\r
+**      pump.c\r
+**\r
+**  Abstract:\r
+**      This code is to download the firmware to CX20709 device via I2C bus. \r
+**      \r
+**\r
+**  Product Name:\r
+**      Conexant Channel CX20709\r
+**\r
+**  Remark:\r
+**      \r
+**\r
+** \r
+********************************************************************************\r
+**  Revision History\r
+**      Date        Description                                 Author\r
+**      01/21/11    Created.                                    Simon Ho\r
+**      01/24/11    Speed up the firmware download by sending   Simon Ho\r
+**                  I2C data continually without  addressing    \r
+********************************************************************************\r
+*****************************************************************************************/\r
+#ifdef __cplusplus\r
+extern "C"{\r
+#endif \r
+\r
+\r
+typedef int (*fun_I2cWriteThenRead)(  void * pCallbackContext,\r
+                                      unsigned char ChipAddr, \r
+                                      unsigned long cbBuf,\r
+                                      unsigned char* pBuf,\r
+                                      unsigned long cbReadBuf, \r
+                                      unsigned char*pReadBuf);\r
+\r
+typedef int (*fun_I2cWrite)(  void * pCallbackContext,\r
+                              unsigned char ChipAddr,\r
+                              unsigned long cbBuf, \r
+                              unsigned char* pBuf);\r
+\r
+/*\r
+ * Set the I2cWrite callback function.\r
+ * \r
+ * PARAMETERS\r
+ *  \r
+ *    pCallbackContext [in] - A pointer to a caller-defined structure of data items\r
+ *                            to be passed as the context parameter of the callback\r
+ *                            routine each time it is called. \r
+ *\r
+ *    I2cWritePtr      [in] - A pointer to a i2cwirte callback routine, which is to \r
+ *                            write I2C data. The callback routine must conform to \r
+ *                            the following prototype:\r
+ * \r
+ *                        int (*fun_I2cWrite)(  \r
+ *                                void * pCallbackContext,\r
+ *                                unsigned char ChipAddr,\r
+ *                                unsigned long cbBuf, \r
+ *                                unsigned char* pBuf\r
+ *                             );\r
+ *\r
+ *                        The callback routine parameters are as follows:\r
+ *\r
+ *                        pCallbackContext [in] - A pointer to a caller-supplied \r
+ *                                                context area as specified in the\r
+ *                                                CallbackContext parameter of \r
+ *                                                SetupI2cWriteCallback. \r
+ *                        ChipAddr         [in] - The i2c chip address.\r
+ *                        cbBuf            [in] - The size of the input buffer, in bytes.\r
+ *                        pBuf             [in] - A pointer to the input buffer that contains \r
+ *                                                the data required to perform the operation.\r
+ *\r
+ *\r
+ *    cbMaxWriteBufSize [in] - Specify the maximux transfer size for a I2c continue \r
+ *                            writing with 'STOP'. This is limited in I2C bus Master\r
+ *                            device. The size can not less then 3 since Channel \r
+ *                            requires 2 address bytes plus a data byte.\r
+ *                              \r
+ *\r
+ *\r
+ * RETURN\r
+ *      None\r
+ *\r
+ */\r
+void SetupI2cWriteCallback( void * pCallbackContext,\r
+                            fun_I2cWrite         I2cWritePtr,\r
+                            unsigned long        cbMaxWriteBufSize);\r
+\r
+\r
+/*\r
+ * Set the SetupI2cWriteThenRead callback function.\r
+ * \r
+ * PARAMETERS\r
+ *  \r
+ *    pCallbackContext    [in] - A pointer to a caller-defined structure of data items\r
+ *                               to be passed as the context parameter of the callback\r
+ *                               routine each time it is called. \r
+ *\r
+ *    I2cWriteThenReadPtr [in] - A pointer to a i2cwirte callback routine, which is to \r
+ *                               write I2C data. The callback routine must conform to \r
+ *                               the following prototype:\r
+ *\r
+ *                        int (*fun_I2cWriteThenRead)(  \r
+ *                                void * pCallbackContext,\r
+ *                                unsigned char ChipAddr,\r
+ *                                unsigned long cbBuf, \r
+ *                                unsigned char* pBuf\r
+ *                             );\r
+ *\r
+ *                        The callback routine parameters are as follows:\r
+ *\r
+ *                         pCallbackContext [in] - A pointer to a caller-supplied \r
+ *                                                 context area as specified in the\r
+ *                                                 CallbackContext parameter of \r
+ *                                                 SetupI2cWriteCallback. \r
+ *                         ChipAddr         [in] - The i2c chip address.\r
+ *                         cbBuf            [in] - The size of the input buffer, in bytes.\r
+ *                         pBuf             [in] - A pointer to the input buffer that contains \r
+ *                                                 the data required to perform the operation.\r
+ *\r
+ * RETURN\r
+ *  \r
+ *    If the operation completes successfully, the return value is ERRNO_NOERR.\r
+ *    Otherwise, return ERRON_* error code. \r
+ *\r
+ */\r
+void SetupI2cWriteThenReadCallback( void * pCallbackContext,\r
+                fun_I2cWriteThenRead I2cWriteThenReadPtr);\r
+\r
+\r
+void SetupMemoryBuffer(void * pAllocedMemoryBuffer);\r
+\r
+\r
+/*\r
+ * Download Firmware to Channel.\r
+ * \r
+ * PARAMETERS\r
+ *  \r
+ *    pRomData            [in] - A pointer fo the input buffer that contains rom data.\r
+ *\r
+ * RETURN\r
+ *  \r
+ *    If the operation completes successfully, the return value is ERRNO_NOERR.\r
+ *    Otherwise, return ERRON_* error code. \r
+ * \r
+ * REMARKS\r
+ *  \r
+ *    You need to set up both I2cWrite and I2cWriteThenRead callback function by calling \r
+ *    SetupI2cWriteCallback and SetupI2cWriteThenReadCallback before you call this function.\r
+ */\r
+int DownloadFW(const unsigned char *const pRomData);\r
+\r
+/*\r
+ * Apply the extra DSP changes from FW file.\r
+ * \r
+ * PARAMETERS\r
+ *  \r
+ *    pRomData            [in] - A pointer fo the input buffer that contains rom data.\r
+ *\r
+ * RETURN\r
+ *  \r
+ *    If the operation completes successfully, the return value is ERRNO_NOERR.\r
+ *    Otherwise, return ERRON_* error code. \r
+ * \r
+ * REMARKS\r
+ *  \r
+ *    You need to set up both I2C/SPI Write and I2C/SPI WriteThenRead callback function \r
+ *    by calling SetupI2cSpiWriteCallback and SetupI2cSpiWriteThenReadCallback before you call \r
+ *    this function.\r
+ */\r
+int ApplyDSPChanges(const unsigned char *const pRom);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif \r
+\r
+\r
+/*Error codes*/\r
+#define ERRNO_NOERR                 0\r
+#define ERRNO_SRC_FILE_NOT_EXIST    101\r
+#define ERRNO_WRITE_FILE_FAILED     102\r
+#define ERRNO_INVALID_DATA          103\r
+#define ERRNO_CHECKSUM_FAILED       104\r
+#define ERRNO_FAILED                105\r
+#define ERRNO_INVALID_PARAMETER     106\r
+#define ERRNO_NOMEM                 107\r
+#define ERRNO_I2CFUN_NOT_SET        108\r
+#define ERRNO_UPDATE_MEMORY_FAILED  109\r
+#define ERRNO_DEVICE_NOT_RESET      110\r
+#define ERRNO_DEVICE_OUT_OF_CONTROL 111\r
+#define ERRNO_DEVICE_DSP_LOCKUP     112\r
+\r
+\r
index 64ef61cc20b7cf902f493c3ea00005f15ed9bb03..2966744847bfcd23d4346f88e2c9896fe6da7bf5 100755 (executable)
@@ -136,7 +136,15 @@ config SND_RK29_SOC_RT5512
        select SND_SOC_RT5512
        select SND_RK29_SOC_I2S
        help
-               Say Y if you want to add support for SoC audio on the ODROID.
+         Say Y if you want to add support for SoC audio on the rockchip.
+
+config SND_RK29_SOC_CX2070X
+       tristate "SoC I2S Audio support for rockchip - CX2070X"
+       depends on SND_RK29_SOC
+       select SND_SOC_CX2070X
+       select SND_RK29_SOC_I2S
+       help
+         Say Y if you want to add support for SoC audio on the rockchip.
 
 config SND_RK29_SOC_RT5621
        tristate "SoC I2S Audio support for rockchip - rt5621"
index 892ca7143ef5b8bf0755e0f11870cad22efa80b4..88fec2ee7f835d61b6c1382ea5e2980bd67a21d1 100755 (executable)
@@ -37,6 +37,7 @@ snd-soc-rk3026-objs := rk_rk3026.o
 snd-soc-hdmi-i2s-objs := rk_hdmi_i2s.o
 snd-soc-hdmi-spdif-objs := rk_hdmi_spdif.o
 snd-soc-rt5512-objs := rk29_rt5512.o
+snd-soc-cx2070x-objs := rk29_cx2070x.o
 
 obj-$(CONFIG_SND_RK29_SOC_WM8994) += snd-soc-wm8994.o
 obj-$(CONFIG_SND_RK29_SOC_WM8988) += snd-soc-wm8988.o
@@ -63,3 +64,4 @@ obj-$(CONFIG_SND_RK_SOC_RK2928) += snd-soc-rk2928.o
 obj-$(CONFIG_SND_RK29_SOC_ES8323) += snd-soc-es8323.o
 obj-$(CONFIG_SND_RK_SOC_RK3026) += snd-soc-rk3026.o
 obj-$(CONFIG_SND_RK29_SOC_RT5512) += snd-soc-rt5512.o
+obj-$(CONFIG_SND_RK29_SOC_CX2070X) += snd-soc-cx2070x.o
diff --git a/sound/soc/rk29/rk29_cx2070x.c b/sound/soc/rk29/rk29_cx2070x.c
new file mode 100644 (file)
index 0000000..44013ac
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ *  rk29_cx2070x.c
+ *
+ *  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 <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <sound/jack.h>
+#include <linux/delay.h>    
+#include "rk29_pcm.h"
+#include "rk29_i2s.h"
+#if 1
+#define        DBG(x...)       printk(KERN_INFO x)
+#else
+#define        DBG(x...)
+#endif
+
+#include "../codecs/cx2070x.h"
+
+static struct platform_device *rk29_snd_device;
+
+
+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;
+    //unsigned int pll_div;
+    int ret;
+
+        DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
+        
+        /* 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; 
+
+        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;
+        case 96000:
+        case 192000:   
+                pll_out = 12288000*2;
+                break;         
+        case 88200:
+        case 176400:   
+                pll_out = 11289600*2;
+                break;         
+        default:
+                DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+                return -EINVAL;
+                break;
+        }
+#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, 64-1);//bclk = 2*32*lrck; 2*32fs
+       switch(params_rate(params)) {
+        case 176400:           
+               case 192000:
+                       snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 1);  
+        DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
+               __FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));                   
+                       break;
+               default:
+                       snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);  
+        DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
+               __FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));                   
+                       break;
+       }
+
+    /*Set the system clk for codec*/
+       ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
+       if (ret < 0)
+       {
+               DBG("rk29_hw_params_rt5631:failed to set the sysclk for codec side\n"); 
+               return ret;
+       }        
+#endif 
+
+#if 0
+    switch (params_rate(params))
+       {
+               case 8000:
+                       pll_div = 12;
+                       break;
+               case 16000:
+                       pll_div = 6;
+                       break;
+               case 32000:
+                       pll_div = 3;
+                       break;
+               case 48000:
+                       pll_div = 2;
+                       break;
+               case 96000:
+                       pll_div = 1;
+                       break;
+               case 11025:
+                       pll_div = 8;
+                       break;
+               case 22050:
+                       pll_div = 4;
+                       break;
+               case 44100:
+                       pll_div = 2;
+                       break;
+               case 88200:
+                       pll_div = 1;
+                       break;
+               default:
+                       printk("Not yet supported!\n");
+                       return -EINVAL;
+       }
+       ret = snd_soc_dai_set_clkdiv(codec_dai, cx2070x_CLK_DIV_ID, pll_div*4);
+       if (ret < 0)
+               return ret;     
+#endif
+
+#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+       //snd_soc_dai_set_pll(codec_dai,0,pll_out, 22579200);
+       snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);                                                
+#endif       
+       return 0;
+}
+
+//---------------------------------------------------------------------------------
+/*
+ * cx2070x DAI operations.
+ */
+static struct snd_soc_ops rk29_ops = {
+       .hw_params = rk29_hw_params,
+};
+
+static const struct snd_soc_dapm_widget cx2070x_dapm_widgets[] = {
+       // Input
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
+       //SND_SOC_DAPM_LINE("Headset Jack", NULL),
+       SND_SOC_DAPM_INPUT("BT IN"),
+       // Output
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("ALineOut", NULL),
+       SND_SOC_DAPM_OUTPUT("BT OUT"),
+       
+};
+
+static const struct snd_soc_dapm_route cx2070x_audio_map[] = {
+       // Input
+       {"MIC IN", NULL,"Mic Jack"},
+    {"PCM IN", NULL, "BT IN"},
+       // Output
+       {"Ext Spk", NULL, "SPK OUT"},
+       {"Headphone Jack", NULL, "HP OUT"},
+       {"ALineOut", NULL, "LINE OUT"},
+       {"BT OUT", NULL, "PCM OUT"},
+};
+
+static int cx2070x_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_codec *codec = rtd->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       //struct cx2070x_codec_chip *chip = snd_soc_codec_get_drvdata(codec);
+       //int err = 0;
+    printk(">>>>>>>>>>%s",__FUNCTION__);
+       snd_soc_dapm_new_controls(dapm, cx2070x_dapm_widgets,
+                               ARRAY_SIZE(cx2070x_dapm_widgets));
+
+       snd_soc_dapm_add_routes(dapm, cx2070x_audio_map,
+                               ARRAY_SIZE(cx2070x_audio_map));
+#if FOR_MID
+    snd_soc_dapm_disable_pin(dapm, "Mic Jack");
+       snd_soc_dapm_disable_pin(dapm, "BT IN");
+       snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+       snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+    snd_soc_dapm_disable_pin(dapm, "ALineOut");
+    snd_soc_dapm_disable_pin(dapm, "BT OUT");
+#endif
+
+       snd_soc_dapm_sync(dapm);
+       return 0;
+}
+
+static struct snd_soc_dai_link rk29_dai[] = {
+       { /* Primary DAI i/f */
+               .name = "CX2070X AIF1",
+               .stream_name = "CX2070X PCM",
+               .cpu_dai_name = "rk29_i2s.1",
+               .codec_dai_name = "cx2070x-hifi",
+               .platform_name = "rockchip-audio",
+               .codec_name = "cx2070x.0-0014",
+               .init = cx2070x_init,
+               .ops = &rk29_ops,
+       },
+};
+
+static struct snd_soc_card snd_soc_card_rk29 = {
+       .name = "RK29_CX2070X",
+       .dai_link = rk29_dai,
+
+       /* If you want to use sec_fifo device,
+        * changes the num_link = 2 or ARRAY_SIZE(snd_soc_card_rk29). */
+       .num_links = ARRAY_SIZE(rk29_dai),
+};
+
+static int __init audio_card_init(void)
+{
+       int ret;
+       rk29_snd_device = platform_device_alloc("soc-audio", -1);
+       if (!rk29_snd_device)
+               return -ENOMEM;
+
+       platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
+
+       ret = platform_device_add(rk29_snd_device);
+    printk(">>>>>>>>>>%s ret = %d",__FUNCTION__, ret);
+       if (ret)
+               platform_device_put(rk29_snd_device);
+
+       return ret;
+}
+module_init(audio_card_init);
+
+static void __exit audio_card_exit(void)
+{
+       platform_device_unregister(rk29_snd_device);
+}
+module_exit(audio_card_exit);
+
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
+MODULE_AUTHOR("showy.zhang <showy.zhang@rock-chips.com>");
+MODULE_LICENSE("GPL");