CX20701 USB Codec: add CX20701 support in RK3188_tb_sdk

This commit is contained in:
zhangjun
2013-09-17 15:14:22 +08:00
parent db38a404c2
commit fc5293086d
13 changed files with 4312 additions and 1 deletions

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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

View File

@@ -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 <20> 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 <20> 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 <20> 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

2041
sound/soc/codecs/cx2070x.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -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

266
sound/soc/codecs/cxdebug.c Normal file
View File

@@ -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");

View File

@@ -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

978
sound/soc/codecs/cxpump.c Normal file
View File

@@ -0,0 +1,978 @@
/*
* 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.
*
* This code is to download the firmware to CX2070x device.
*
*************************************************************************
* Modified Date: 01/24/11
* File Version: 1.0.0.1
*************************************************************************
*/
#if defined(_MSC_VER)
// microsoft windows environment.
#define __BYTE_ORDER __LITTLE_ENDIAN
#define __LITTLE_ENDIAN 1234
#include <stdlib.h> // For _MAX_PATH definition
#include <stdio.h>
#include <string.h>
#define msleep(_x_)
int printk(const char *s, ...);
#define KERN_ERR "<3>"
#elif defined(__KERNEL__)
// linux kernel environment.
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#else
//
// linux user mode environment.
//
#include <stdlib.h> // For _MAX_PATH definition
#include <stdio.h>
#endif
#include "cxpump.h"
#if defined( __BIG_ENDIAN) && !defined(__BYTE_ORDER)
#define __BYTE_ORDER __BIG_ENDIAN
#elif defined( __LITTLE_ENDIAN ) && !defined(__BYTE_ORDER)
#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
#ifndef __BYTE_ORDER
#error __BYTE_ORDER is undefined.
#endif
#define ENABLE_I2C_BURST_MODE
#if defined(_MSC_VER)
#pragma warning(disable:4127 4706 4101) // conditional experssion is constant
typedef enum I2C_STATE{I2C_OK,I2C_ERR,I2C_RETRY} ;
void ShowProgress(int curPos,bool bForceRedraw, I2C_STATE eState, const int MaxPos);
void InitShowProgress(const int MaxPos);
#elif defined(__KERNEL__)
//linux kernel mode
#define ShowProgress(curPos,bForceRedraw,eState, axPos)
#define InitShowProgress(MaxPos)
#else
//linux user mode
#define InitShowProgress(MaxPos)
#define ShowProgress(curPos,bForceRedraw,eState, axPos)
#endif
#ifndef NULL
#define NULL 0
#endif //#ifndef NULL
#define S_DESC "Cnxt Channel Firmware" /*Specify the string that will show on head of rom file*/
#define S_ROM_FILE_NAME "cx2070x.fw" /*Specify the file name of rom file*/
#define CHIP_ADDR 0x14 /*Specify the i2c chip address*/
#define MEMORY_UPDATE_TIMEOUT 300
#define MAX_ROM_SIZE (1024*1024)
//#define DBG_ERROR "ERROR : "
#define DBG_ERROR KERN_ERR
#define LOG( _msg_ ) printk _msg_
//#define LOG( _msg_ ) ;
typedef struct CX_CODEC_ROM_DATA
{
#ifdef USE_TYPE_DEFINE
unsigned long Type;
#endif //#ifdef USE_TYPE_DEFINE
unsigned long Length;
unsigned long Address;
unsigned char data[1];
}CX_CODEC_ROM_DATA;
#define ROM_DATA_TYPE_S37 0xAA55CC01 // S37 format.
#define ROM_DATA_TYPE_CNXT 0xAA55CC04 // Conexant SPI format.
#define ROM_DATA_SEPARATED_LINE 0x23232323 //()()()()
typedef struct CX_CODEC_ROM{
char sDesc[24];
char cOpenBracket;
char sVersion[5];
char cCloseBracket;
char cEOF;
unsigned long FileSize;
unsigned long LoaderAddr;
unsigned long LoaderLen;
unsigned long CtlAddr;
unsigned long CtlLen;
unsigned long SpxAddr;
unsigned long SpxLen;
struct CX_CODEC_ROM_DATA Data[1];
}CX_CODEC_ROM;
typedef struct CX_CODEC_APPENDED_DATA
{
unsigned char Address[2]; // The address of data.
unsigned char padding; // The actual firmware data.
unsigned char data; // The actual firmware data.
}CX_CODEC_APPENDED_DATA;
typedef struct CX_CODEC_ROM_APPENDED{
unsigned long TuningAddr;
unsigned long TuningLen;
CX_CODEC_APPENDED_DATA data[1]; // following by Jira id and time.
}CX_CODEC_ROM_APPENDED;
typedef struct CX_CODEC_ROM_APPENDED_INFO{
char sJIRAID[16];
char sTime[16];
}CX_CODEC_ROM_APPENDED_INFO;
// To convert two digital ASCII into one BYTE.
unsigned char ASCII_2_BYTE( char ah, char al) ;
#define BUF_SIZE 0x1000
#define BIBF(_x_) if(!(_x_)) break;
#define BIF(_x_) if((ErrNo=(_x_)) !=0) break;
#ifndef BIBF
#define BIBF( _x_ ) if(!(_x_)) break;
#endif
enum {
MEM_TYPE_RAM = 1 /* CTL*/,
MEM_TYPE_SPX = 2,
MEM_TYPE_EEPROM = 3,
MEM_TYPE_CPX =0x04,
MEM_TYPE_EEPROM_RESET = 0x8003, //reset after writing.
};
fun_I2cWriteThenRead g_I2cWriteThenReadPtr = NULL;
fun_I2cWrite g_I2cWritePtr = NULL;
unsigned char * g_AllocatedBuffer = NULL;
unsigned char * g_Buffer = NULL;
unsigned long g_cbMaxWriteBufSize = 0;
void * g_pContextI2cWrite = NULL;
void * g_pContextI2cWriteThenRead = NULL;
/*
* The SetupI2cWriteCallback sets the I2cWrite callback function.
*
* PARAMETERS
*
* pCallbackContext [in] - A pointer to a caller-defined structure of data items
* to be passed as the context parameter of the callback
* routine each time it is called.
*
* I2cWritePtr [in] - A pointer to a i2cwirte callback routine, which is to
* write I2C data. The callback routine must conform to
* the following prototype:
*
* int (*fun_I2cWrite)(
* void * pCallbackContext,
* unsigned char ChipAddr,
* unsigned long cbBuf,
* unsigned char* pBuf
* );
*
* The callback routine parameters are as follows:
*
* pCallbackContext [in] - A pointer to a caller-supplied
* context area as specified in the
* CallbackContext parameter of
* SetupI2cWriteCallback.
* ChipAddr [in] - The i2c chip address.
* cbBuf [in] - The size of the input buffer, in bytes.
* pBuf [in] - A pointer to the input buffer that contains
* the data required to perform the operation.
*
*
* cbMaxWriteBuf [in] - Specify the maximux transfer size for a I2c continue
* writing with 'STOP'. This is limited in I2C bus Master
* device. The size can not less then 3 since Channel
* requires 2 address bytes plus a data byte.
*
*
*
* RETURN
*
* None
*
*/
void SetupI2cWriteCallback( void * pCallbackContext,
fun_I2cWrite I2cWritePtr,
unsigned long cbMaxWriteBufSize)
{
g_pContextI2cWrite = pCallbackContext;
g_I2cWritePtr = I2cWritePtr;
g_cbMaxWriteBufSize = cbMaxWriteBufSize;
}
/*
* The SetupI2cWriteThenReadCallback sets the SetupI2cWriteThenRead callback function.
*
* PARAMETERS
*
* pCallbackContext [in] - A pointer to a caller-defined structure of data items
* to be passed as the context parameter of the callback
* routine each time it is called.
*
* I2cWriteThenReadPtr [in] - A pointer to a i2cwirte callback routine, which is to
* write I2C data. The callback routine must conform to
* the following prototype:
*
* int (*fun_I2cWriteThenRead)(
* void * pCallbackContext,
* unsigned char ChipAddr,
* unsigned long cbBuf,
* unsigned char* pBuf
* );
*
* The callback routine parameters are as follows:
*
* pCallbackContext [in] - A pointer to a caller-supplied
* context area as specified in the
* CallbackContext parameter of
* SetupI2cWriteCallback.
* ChipAddr [in] - The i2c chip address.
* cbBuf [in] - The size of the input buffer, in bytes.
* pBuf [in] - A pointer to the input buffer that contains
* the data required to perform the operation.
*
* RETURN
* None
*
*/
void SetupI2cWriteThenReadCallback( void * pCallbackContext,
fun_I2cWriteThenRead I2cWriteThenReadPtr)
{
g_pContextI2cWriteThenRead = pCallbackContext;
g_I2cWriteThenReadPtr = I2cWriteThenReadPtr;
}
void SetupMemoryBuffer(void * pAllocedMemoryBuffer)
{
g_AllocatedBuffer = (unsigned char*)pAllocedMemoryBuffer;
g_Buffer = g_AllocatedBuffer +2;
}
/*
* Convert a 4-byte number from a ByteOrder into another ByteOrder.
*/
unsigned long ByteOrderSwapULONG(unsigned long i)
{
return((i&0xff)<<24)+((i&0xff00)<<8)+((i&0xff0000)>>8)+((i>>24)&0xff);
}
/*
* Convert a 2-byte number from a ByteOrder into another ByteOrder.
*/
unsigned short ByteOrderSwapWORD(unsigned short i)
{
return ((i>>8)&0xff)+((i << 8)&0xff00);
}
/*
* Convert a 4-byte number from generic byte order into Big Endia
*/
unsigned long ToBigEndiaULONG(unsigned long i)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
return ByteOrderSwapULONG(i);
#else
return i;
#endif
}
/*
* Convert a 2-byte number from generic byte order into Big Endia
*/
unsigned short ToBigEndiaWORD(unsigned short i)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
return ByteOrderSwapWORD(i);
#else
return i;
#endif
}
/*
* Convert a 4-byte number from Big Endia into generic byte order.
*/
unsigned long FromBigEndiaULONG(unsigned long i)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
return ByteOrderSwapULONG(i);
#else
return i;
#endif
}
/*
* Convert a 2-byte number from Big Endia into generic byte order.
*/
unsigned short FromBigEndiaWORD(unsigned short i)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
return ByteOrderSwapWORD(i);
#else
return i;
#endif
}
/*
* To convert two digital ASCII into one BYTE.
*/
unsigned char ASCII_2_BYTE( char ah, char al)
{
unsigned char ret = '\0';
int i =2;
for(;i>0;i--)
{
if( 'a' <= ah && 'f' >= ah)
{
ret += ah - 'a'+10;
}
else if( 'A' <= ah && 'F' >= ah)
{
ret += ah -'A'+10;
}
else if( '0' <= ah && '9' >= ah)
{
ret += ah - '0';
}
else
{
LOG((DBG_ERROR "Invalid txt data.\n"));
// ErrNo = ERRNO_INVALID_DATA;
break;
}
ah =al;
if(i==2)
ret = (unsigned short)ret << 4;
}
return ret;
}
/*
* Read a byte from the specified register address.
*
* PARAMETERS
*
* RegAddr [in] - Specifies the register address.
*
* RETURN
*
* Returns the byte that is read from the specified register address.
*
*/
unsigned char ReadReg(unsigned short RegAddr)
{
unsigned char RegData;
if(!g_I2cWriteThenReadPtr)
{
LOG((DBG_ERROR "i2C function is not set.\n"));
return 0;
}
RegAddr = ToBigEndiaWORD(RegAddr);
g_I2cWriteThenReadPtr(g_pContextI2cWriteThenRead,CHIP_ADDR,
2,(unsigned char*) &RegAddr,1,&RegData);
return RegData;
}
/*
* Write a byte from the specified register address.
*
* PARAMETERS
*
* RegAddr [in] - Specifies the register address.
*
* RETURN
*
* Returns the byte that is read from the specified register address.
*
* REMARK
*
* The g_I2cWriteThenReadPtr must be set before calling this function.
*/
int WriteReg(unsigned short RegAddr, unsigned char RegData)
{
unsigned char WrBuf[3];
if(!g_I2cWritePtr)
{
LOG((DBG_ERROR "i2C function is not set.\n"));
return -ERRNO_I2CFUN_NOT_SET;
}
*((unsigned short*) WrBuf) = ToBigEndiaWORD(RegAddr);
WrBuf[2] = RegData;
g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR,sizeof(WrBuf),WrBuf);
return ERRNO_NOERR;
}
/*
* Writes a number of bytes from a buffer to Channel via I2C bus.
*
* PARAMETERS
*
* NumOfBytes [in] - Specifies the number of bytes to be written
* to the memory address.
* pData [in] - Pointer to a buffer from an array of I2C data
* are to be written.
*
* RETURN
*
* If the operation completes successfully, the return value is ERRNO_NOERR.
* Otherwise, return ERRON_* error code.
*/
int ChannelI2cBulkWrite( unsigned long NumOfBytes, unsigned char *pData)
{
int ErrNo = ERRNO_NOERR;
unsigned short CurAddr;
//unsigned char *pDataEnd = pData + NumOfBytes;
unsigned char *pCurData = pData;
unsigned short *pCurAddrByte = NULL;
unsigned long BytesToProcess = 0;
unsigned short backup = 0;
const unsigned long cbAddressBytes = 2;
const unsigned long cbMaxDataLen = g_cbMaxWriteBufSize-cbAddressBytes;
if(!g_I2cWritePtr )
{
LOG((DBG_ERROR "i2C function is not set.\n"));
return -ERRNO_I2CFUN_NOT_SET;
}
//assert(NumOfBytes < 3);
CurAddr = FromBigEndiaWORD( *((unsigned short*)pData));
//skip first 2 bytes data (address).
NumOfBytes -= cbAddressBytes;
pCurData += cbAddressBytes;
for(;NumOfBytes;)
{
BytesToProcess = NumOfBytes > cbMaxDataLen? cbMaxDataLen : NumOfBytes;
NumOfBytes-= BytesToProcess;
// save the pervious 2 bytes for later use.
pCurAddrByte = (unsigned short*) (pCurData -cbAddressBytes);
backup = *pCurAddrByte;
*pCurAddrByte= ToBigEndiaWORD(CurAddr);
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, BytesToProcess + cbAddressBytes,(unsigned char*)pCurAddrByte));
//restore the data
*pCurAddrByte = backup;
pCurData += BytesToProcess;
CurAddr += (unsigned short)BytesToProcess;
}
return ErrNo;
}
/*
* Writes a number of bytes from a buffer to the specified memory address.
*
* PARAMETERS
*
* dwAddr [in] - Specifies the memory address.
* NumOfBytes [in] - Specifies the number of bytes to be written
* to the memory address.
* pData [in] - Pointer to a buffer from an struct of
* CX_CODEC_ROM_DATA is to be written.
* MemType [in] - Specifies the requested memory type, the value must be from
* the following table.
*
* MEM_TYPE_RAM = 1
* MEM_TYPE_SPX = 2
* MEM_TYPE_EEPROM = 3
*
* RETURN
*
* If the operation completes successfully, the return value is ERRNO_NOERR.
* Otherwise, return ERRON_* error code.
*/
int CxWriteMemory(unsigned long dwAddr, unsigned long NumOfBytes, unsigned char * pData, int MemType )
{
int ErrNo = ERRNO_NOERR;
unsigned char Address[4];
unsigned char WrData[8];
unsigned char offset = 0;
const unsigned long MAX_BUF_LEN = 0x100;
unsigned char cr = 0;
int bNeedToContinue = 0;
int i=0;
const unsigned long cbAddressBytes = 2;
unsigned short * pAddressByte;
unsigned char *pEndData = pData + NumOfBytes;
unsigned short RegMemMapAddr = ToBigEndiaWORD(0x300);
unsigned long BytesToProcess = 0;
while(NumOfBytes)
{
BytesToProcess = NumOfBytes <= MAX_BUF_LEN ? NumOfBytes : MAX_BUF_LEN;
NumOfBytes -= BytesToProcess;
pEndData = pData + BytesToProcess;
*((unsigned long*)&Address) = ToBigEndiaULONG(dwAddr);
// dwAddr += offset;
offset = 0;
if( !bNeedToContinue )
{
#ifdef ENABLE_I2C_BURST_MODE
//
// Update the memory target address and buffer length.
//
WrData[0] = 0x02; //update target address Low 0x02FC
WrData[1] = 0xFC;
WrData[2] = Address[3];
WrData[3] = Address[2];
WrData[4] = Address[1];
WrData[5] = (unsigned char)BytesToProcess -1 ; // X bytes - 1
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 6 , WrData));
#else
//
// Update the memory target address and buffer length.
//
WrData[0] = 0x02; //update target address Low 0x02FC
WrData[1] = 0xFC;
WrData[2] = Address[3];
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));
WrData[0] = 0x02; //update target address Middle 0x02FD
WrData[1] = 0xFD;
WrData[2] = Address[2];
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));
WrData[0] = 0x02; //update target address High 0x02FE
WrData[1] = 0xFE;
WrData[2] = Address[1];
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));
WrData[0] = 0x02; //update Buffer Length. 0x02FF
WrData[1] = 0xFF;
WrData[2] = (unsigned char)BytesToProcess -1 ; // X bytes - 1
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));
#endif
}
//
// Update buffer.
//
#ifdef ENABLE_I2C_BURST_MODE
pAddressByte = (unsigned short*) (pData - cbAddressBytes);
memcpy(g_Buffer, pAddressByte, BytesToProcess+cbAddressBytes);
*((unsigned short*)g_Buffer) = RegMemMapAddr;
ChannelI2cBulkWrite(BytesToProcess+cbAddressBytes, (unsigned char*)g_Buffer);
pData = pEndData;
#else
for(offset=0;pData != pEndData;offset++,pData++)
{
WrData[0] = 0x03; //update Buffer [0x0300 - 0x03ff]
WrData[1] = (unsigned char) offset;
WrData[2] = *pData;
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));
}
#endif
//
// Commit the changes and start to transfer buffer to memory.
//
if( MemType == MEM_TYPE_RAM)
{
cr = 0x81;
}
else if( MemType == MEM_TYPE_EEPROM)
{
cr = 0x83;
}
else if( MemType == MEM_TYPE_SPX)
{
cr = 0x85;
if( bNeedToContinue )
{
cr |= 0x08;
}
}
WrData[0] = 0x04; // UpdateCtl [0x400]
WrData[1] = 0x00;
WrData[2] = cr; // start to transfer
BIBF(g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR, 3 , WrData));
for(i = 0;i<MEMORY_UPDATE_TIMEOUT;i++)
{
// loop until the writing is done.
WrData[0] = ReadReg(0x0400);
if(!( WrData[0] & 0x80 ))
{
//done
break;
}
else
{
//pending
if(MemType== MEM_TYPE_EEPROM)
{
//it needs more time for updating eeprom.
msleep(5); // need more waiting
}
else
{
udelay(1);
}
continue;
}
}
if( i == MEMORY_UPDATE_TIMEOUT)
{
//writing failed.
LOG( (DBG_ERROR "memory update timeout.\n"));
ErrNo = -ERRNO_UPDATE_MEMORY_FAILED;
break;
}
if ( i >= 1)
{
printk( KERN_ERR "write pending loop =%d\n", i);
}
bNeedToContinue = 1;
}while(0);
return ErrNo ;
}
#define WAIT_UNTIL_DEVICE_READY(_x_,_msg_) \
for (timeout=0;timeout<dev_ready_time_out;timeout++) \
{ \
Ready = ReadReg(0x1000); \
if (Ready _x_) break; \
msleep(10); \
}; \
if( timeout == dev_ready_time_out) \
{ \
printk(KERN_ERR _msg_); \
ErrNo = -ERRNO_DEVICE_OUT_OF_CONTROL; \
break; \
}
unsigned int CxGetFirmwarePatchVersion(void)
{
unsigned int FwPatchVersion = 0;
int ErrNo;
if( NULL == g_I2cWriteThenReadPtr||
NULL == g_I2cWritePtr)
{
ErrNo = -ERRNO_I2CFUN_NOT_SET;
LOG( (DBG_ERROR "i2C function is not set.\n"));
return 0;
}
FwPatchVersion = ReadReg(0x1584);
FwPatchVersion <<= 8;
FwPatchVersion |= ReadReg(0x1585);
FwPatchVersion <<= 8;
FwPatchVersion |= ReadReg(0x1586);
return FwPatchVersion;
}
unsigned int CxGetFirmwareVersion(void)
{
unsigned int FwVersion = 0;
int ErrNo;
if( NULL == g_I2cWriteThenReadPtr||
NULL == g_I2cWritePtr)
{
ErrNo = -ERRNO_I2CFUN_NOT_SET;
LOG( (DBG_ERROR "i2C function is not set.\n"));
return 0;
}
FwVersion = ReadReg(0x1002);
FwVersion <<= 8;
FwVersion |= ReadReg(0x1001);
FwVersion <<= 8;
FwVersion |= ReadReg(0x1006);
return FwVersion;
}
// return number, 0= failed. 1 = successful.
int DownloadFW(const unsigned char * const pRomBin)
{
int ErrNo = ERRNO_NOERR;
struct CX_CODEC_ROM *pRom = (struct CX_CODEC_ROM *)pRomBin;
struct CX_CODEC_ROM_DATA *pRomData;
struct CX_CODEC_ROM_DATA *pRomDataEnd;
unsigned char *pData;
unsigned char *pDataEnd;
unsigned long CurAddr = 0;
unsigned long cbDataLen = 0;
unsigned char Ready;
unsigned long curProgress = 0;
unsigned long TotalLen = 0;
unsigned long i = 0;
const unsigned long dev_ready_time_out = 100;
int bIsRomVersion = 0;
const char CHAN_PATH[]="CNXT CHANNEL PATCH";
unsigned long timeout;
unsigned long fwVer;
unsigned long fwPatchVer;
do{
if(pRom == NULL ||g_Buffer == NULL)
{
ErrNo = -ERRNO_INVALID_PARAMETER;
LOG( (DBG_ERROR "Invalid parameter.\n"));
break;
}
if( NULL == g_I2cWriteThenReadPtr||
NULL == g_I2cWritePtr)
{
ErrNo = -ERRNO_I2CFUN_NOT_SET;
LOG( (DBG_ERROR "i2C function is not set.\n"));
break;
}
//check if codec is ROM version
if (0 == memcmp(CHAN_PATH,pRom->sDesc,sizeof(CHAN_PATH)-1)) {
printk(KERN_INFO "[CNXT] sDesc = %s", pRom->sDesc);
bIsRomVersion = 1;
}
if (bIsRomVersion) {
WAIT_UNTIL_DEVICE_READY(== 0X01,"cx2070x: Timed out waiting for codecto be ready!\n");
} else {
//Check if there is a FIRMWARE present. the Channel should get
// a clear reset signal before we download firmware to it.
if( (ReadReg(0x009) & 0x04) == 0) {
LOG((DBG_ERROR "cx2070x: did not get a clear reset..!"));
ErrNo = -ERRNO_DEVICE_NOT_RESET;
break;
}
}
TotalLen = FromBigEndiaULONG(pRom->LoaderLen) + FromBigEndiaULONG(pRom->CtlLen) + FromBigEndiaULONG(pRom->SpxLen);
// InitShowProgress(TotalLen);
//Download the loader.
pRomData = (struct CX_CODEC_ROM_DATA *) ( (char*)pRom + FromBigEndiaULONG(pRom->LoaderAddr));
pRomDataEnd = (struct CX_CODEC_ROM_DATA *) ((char*)pRomData +FromBigEndiaULONG(pRom->LoaderLen));
for( ;pRomData!=pRomDataEnd;)
{
#ifdef ENABLE_I2C_BURST_MODE
pData = &pRomData->data[0];
pDataEnd= pData + FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned long);
memcpy(g_Buffer, pData-2, FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned short));
BIF(ChannelI2cBulkWrite( FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned short), g_Buffer));
curProgress += FromBigEndiaULONG(pRomData->Length) ;
ShowProgress(curProgress,false, I2C_OK,TotalLen);
pRomData = (struct CX_CODEC_ROM_DATA *)pDataEnd;
#else
CurAddr = FromBigEndiaULONG(pRomData->Address);
pData = &pRomData->data[0];
pDataEnd= pData + FromBigEndiaULONG(pRomData->Length) - sizeof(unsigned long);
for( ;pData!=pDataEnd;pData++)
{
*((unsigned short*)writeBuf) = ToBigEndiaWORD((unsigned short)CurAddr);
writeBuf[2]= *pData;
g_I2cWritePtr(g_pContextI2cWrite,CHIP_ADDR,3, writeBuf);
CurAddr++;
}
pRomData = (struct CX_CODEC_ROM_DATA *)pData;
#endif
}
//* check if the device is ready.
if (bIsRomVersion) {
WAIT_UNTIL_DEVICE_READY(== 0X01,"cx2070x: Timed out waiting for cx2070x to be ready after loader downloaded!\n");
} else {
WAIT_UNTIL_DEVICE_READY(!= 0xFF,"cx2070x: Timed out waiting for cx2070x to be ready after loader downloaded!\n");
}
//Download the CTL
pRomData = (struct CX_CODEC_ROM_DATA *) ( (char*)pRom + FromBigEndiaULONG(pRom->CtlAddr ));
pRomDataEnd = (struct CX_CODEC_ROM_DATA *) ((char*)pRomData +FromBigEndiaULONG(pRom->CtlLen));
for( ;pRomData!=pRomDataEnd;)
{
CurAddr = FromBigEndiaULONG(pRomData->Address);
pData = &pRomData->data[0];
cbDataLen = FromBigEndiaULONG(pRomData->Length) ;
BIF(CxWriteMemory(CurAddr,cbDataLen -sizeof(unsigned long)/*subtracts the address bytes*/ , pData, MEM_TYPE_RAM ));
// The next RoMData position = current romData position + cbDataLen + sizeof( data len bytes)
pRomData = (struct CX_CODEC_ROM_DATA *)((char*) pRomData + cbDataLen + sizeof(unsigned long));
curProgress += cbDataLen ;
ShowProgress(curProgress,false, I2C_OK,TotalLen);
}
pRomData = (struct CX_CODEC_ROM_DATA *) ( (char*)pRom + FromBigEndiaULONG(pRom->SpxAddr ));
pRomDataEnd = (struct CX_CODEC_ROM_DATA *) ((char*)pRomData +FromBigEndiaULONG(pRom->SpxLen));
for( ;pRomData!=pRomDataEnd;)
{
CurAddr = FromBigEndiaULONG(pRomData->Address);
pData = &pRomData->data[0];
cbDataLen = FromBigEndiaULONG(pRomData->Length) ;
BIF(CxWriteMemory(CurAddr,cbDataLen -sizeof(unsigned long)/*subtracts the address bytes*/ , pData, MEM_TYPE_SPX ));
// The next RoMData position = current romData position + cbDataLen + sizeof( data len bytes)
pRomData = (struct CX_CODEC_ROM_DATA *)((char*) pRomData + cbDataLen + sizeof(unsigned long));
curProgress += cbDataLen ;
ShowProgress(curProgress,false, I2C_OK,TotalLen);
}
if(ErrNo != 0) break;
ShowProgress(TotalLen,false, I2C_OK,TotalLen);
//
// Reset
//
if(bIsRomVersion)
{
WriteReg(0x1000,0x00);
// msleep(400); //delay 400 ms
}
else
{
WriteReg(0x400,0x40);
msleep(400); //delay 400 ms
}
WAIT_UNTIL_DEVICE_READY(== 0x01,"cx2070x: Timed out waiting for cx2070x to be ready after firmware downloaded!\n");
//check if XPS code is working or not.
WriteReg(0x117d,0x01);
for (timeout=0;timeout<dev_ready_time_out;timeout++)
{
Ready = ReadReg(0x117d);
if (Ready == 0x00) break;
msleep(1);
};
if( timeout == dev_ready_time_out)
{
LOG((DBG_ERROR "cx2070x: DSP lockup! download firmware failed!"));
ErrNo = -ERRNO_DEVICE_DSP_LOCKUP;
break;
}
fwVer = CxGetFirmwareVersion();
if(bIsRomVersion)
{
fwPatchVer = CxGetFirmwarePatchVersion();
printk(KERN_INFO "cx2070x: firmware download successfully! FW: %u,%u,%u, FW Patch: %u,%u,%u\n",
(unsigned char)(fwVer>>16),
(unsigned char)(fwVer>>8),
(unsigned char)fwVer,
(unsigned char)(fwPatchVer>>16),
(unsigned char)(fwPatchVer>>8),
(unsigned char)fwPatchVer);
}
else
{
printk(KERN_INFO "cx2070x: firmware download successfully! FW: %u,%u,%u\n",
(unsigned char)(fwVer>>16),
(unsigned char)(fwVer>>8),
(unsigned char)fwVer);
}
}while(0);
return ErrNo;
}
int ApplyDSPChanges(const unsigned char *const pRom)
{
int ErrNo = ERRNO_NOERR;
struct CX_CODEC_ROM* pNewRom ;
struct CX_CODEC_ROM_APPENDED *pRomAppended;
struct CX_CODEC_ROM_APPENDED_INFO *pInfo;
struct CX_CODEC_APPENDED_DATA *pData;
struct CX_CODEC_APPENDED_DATA *pDataEnd;
unsigned short wRegAddr;
unsigned char NewC;
#define DESC_LEN (16)
char szJira[DESC_LEN+1];
char szDate[DESC_LEN+1];
pNewRom = (struct CX_CODEC_ROM*) pRom;
// check if firmware contains DSP tuning data.
if( (FromBigEndiaULONG(pNewRom->SpxLen) + FromBigEndiaULONG(pNewRom->SpxAddr)) != FromBigEndiaULONG(pNewRom->FileSize) )
{
// has DSP Tuning data.
pRomAppended = (struct CX_CODEC_ROM_APPENDED*)((char*)pNewRom + FromBigEndiaULONG(pNewRom->SpxAddr) + FromBigEndiaULONG(pNewRom->SpxLen));
pInfo = (struct CX_CODEC_ROM_APPENDED_INFO*) ((char*)pNewRom + FromBigEndiaULONG(pRomAppended ->TuningAddr) +
FromBigEndiaULONG(pRomAppended ->TuningLen));
strncpy(szJira,pInfo->sJIRAID,DESC_LEN);
strncpy(szDate,pInfo->sTime,DESC_LEN);
szJira[DESC_LEN]=0;
szDate[DESC_LEN-1]=0; //remove the last lettle $.
printk(KERN_INFO "Applying the DSP tuning changes..Jira: %s Date: %s\n"
,szJira,szDate);
pData = pRomAppended->data;
pDataEnd = (struct CX_CODEC_APPENDED_DATA*)((char*)pData + FromBigEndiaULONG(pRomAppended->TuningLen));
for(;pData != pDataEnd; pData++)
{
wRegAddr = pData->Address[0];
wRegAddr <<=8;
wRegAddr |= pData->Address[1];
WriteReg(wRegAddr,pData->data);
//printk(KERN_INFO "0X%04x=0x%02x\n",wRegAddr,pData->data);
}
// re-set NewC.
NewC = ReadReg(0x117d);
WriteReg(0x117d,NewC|1);
}
return ErrNo;
}

206
sound/soc/codecs/cxpump.h Normal file
View File

@@ -0,0 +1,206 @@
/****************************************************************************************
*****************************************************************************************
*** ***
*** Copyright (c) 2011 ***
*** ***
*** Conexant Systems, Inc. ***
*** ***
*** All Rights Reserved ***
*** ***
*** CONFIDENTIAL ***
*** ***
*** NO DISSEMINATION OR USE WITHOUT PRIOR WRITTEN PERMISSION ***
*** ***
*****************************************************************************************
**
** File Name:
** pump.c
**
** Abstract:
** This code is to download the firmware to CX20709 device via I2C bus.
**
**
** Product Name:
** Conexant Channel CX20709
**
** Remark:
**
**
**
********************************************************************************
** Revision History
** Date Description Author
** 01/21/11 Created. Simon Ho
** 01/24/11 Speed up the firmware download by sending Simon Ho
** I2C data continually without addressing
********************************************************************************
*****************************************************************************************/
#ifdef __cplusplus
extern "C"{
#endif
typedef int (*fun_I2cWriteThenRead)( void * pCallbackContext,
unsigned char ChipAddr,
unsigned long cbBuf,
unsigned char* pBuf,
unsigned long cbReadBuf,
unsigned char*pReadBuf);
typedef int (*fun_I2cWrite)( void * pCallbackContext,
unsigned char ChipAddr,
unsigned long cbBuf,
unsigned char* pBuf);
/*
* Set the I2cWrite callback function.
*
* PARAMETERS
*
* pCallbackContext [in] - A pointer to a caller-defined structure of data items
* to be passed as the context parameter of the callback
* routine each time it is called.
*
* I2cWritePtr [in] - A pointer to a i2cwirte callback routine, which is to
* write I2C data. The callback routine must conform to
* the following prototype:
*
* int (*fun_I2cWrite)(
* void * pCallbackContext,
* unsigned char ChipAddr,
* unsigned long cbBuf,
* unsigned char* pBuf
* );
*
* The callback routine parameters are as follows:
*
* pCallbackContext [in] - A pointer to a caller-supplied
* context area as specified in the
* CallbackContext parameter of
* SetupI2cWriteCallback.
* ChipAddr [in] - The i2c chip address.
* cbBuf [in] - The size of the input buffer, in bytes.
* pBuf [in] - A pointer to the input buffer that contains
* the data required to perform the operation.
*
*
* cbMaxWriteBufSize [in] - Specify the maximux transfer size for a I2c continue
* writing with 'STOP'. This is limited in I2C bus Master
* device. The size can not less then 3 since Channel
* requires 2 address bytes plus a data byte.
*
*
*
* RETURN
* None
*
*/
void SetupI2cWriteCallback( void * pCallbackContext,
fun_I2cWrite I2cWritePtr,
unsigned long cbMaxWriteBufSize);
/*
* Set the SetupI2cWriteThenRead callback function.
*
* PARAMETERS
*
* pCallbackContext [in] - A pointer to a caller-defined structure of data items
* to be passed as the context parameter of the callback
* routine each time it is called.
*
* I2cWriteThenReadPtr [in] - A pointer to a i2cwirte callback routine, which is to
* write I2C data. The callback routine must conform to
* the following prototype:
*
* int (*fun_I2cWriteThenRead)(
* void * pCallbackContext,
* unsigned char ChipAddr,
* unsigned long cbBuf,
* unsigned char* pBuf
* );
*
* The callback routine parameters are as follows:
*
* pCallbackContext [in] - A pointer to a caller-supplied
* context area as specified in the
* CallbackContext parameter of
* SetupI2cWriteCallback.
* ChipAddr [in] - The i2c chip address.
* cbBuf [in] - The size of the input buffer, in bytes.
* pBuf [in] - A pointer to the input buffer that contains
* the data required to perform the operation.
*
* RETURN
*
* If the operation completes successfully, the return value is ERRNO_NOERR.
* Otherwise, return ERRON_* error code.
*
*/
void SetupI2cWriteThenReadCallback( void * pCallbackContext,
fun_I2cWriteThenRead I2cWriteThenReadPtr);
void SetupMemoryBuffer(void * pAllocedMemoryBuffer);
/*
* Download Firmware to Channel.
*
* PARAMETERS
*
* pRomData [in] - A pointer fo the input buffer that contains rom data.
*
* RETURN
*
* If the operation completes successfully, the return value is ERRNO_NOERR.
* Otherwise, return ERRON_* error code.
*
* REMARKS
*
* You need to set up both I2cWrite and I2cWriteThenRead callback function by calling
* SetupI2cWriteCallback and SetupI2cWriteThenReadCallback before you call this function.
*/
int DownloadFW(const unsigned char *const pRomData);
/*
* Apply the extra DSP changes from FW file.
*
* PARAMETERS
*
* pRomData [in] - A pointer fo the input buffer that contains rom data.
*
* RETURN
*
* If the operation completes successfully, the return value is ERRNO_NOERR.
* Otherwise, return ERRON_* error code.
*
* REMARKS
*
* You need to set up both I2C/SPI Write and I2C/SPI WriteThenRead callback function
* by calling SetupI2cSpiWriteCallback and SetupI2cSpiWriteThenReadCallback before you call
* this function.
*/
int ApplyDSPChanges(const unsigned char *const pRom);
#ifdef __cplusplus
}
#endif
/*Error codes*/
#define ERRNO_NOERR 0
#define ERRNO_SRC_FILE_NOT_EXIST 101
#define ERRNO_WRITE_FILE_FAILED 102
#define ERRNO_INVALID_DATA 103
#define ERRNO_CHECKSUM_FAILED 104
#define ERRNO_FAILED 105
#define ERRNO_INVALID_PARAMETER 106
#define ERRNO_NOMEM 107
#define ERRNO_I2CFUN_NOT_SET 108
#define ERRNO_UPDATE_MEMORY_FAILED 109
#define ERRNO_DEVICE_NOT_RESET 110
#define ERRNO_DEVICE_OUT_OF_CONTROL 111
#define ERRNO_DEVICE_DSP_LOCKUP 112

View File

@@ -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"

View File

@@ -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

View File

@@ -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");