mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
CX20701 USB Codec: add CX20701 support in RK3188_tb_sdk
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
411
sound/soc/codecs/cx2070x-i2c.h
Normal file
411
sound/soc/codecs/cx2070x-i2c.h
Normal 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
2041
sound/soc/codecs/cx2070x.c
Normal file
File diff suppressed because it is too large
Load Diff
69
sound/soc/codecs/cx2070x.h
Normal file
69
sound/soc/codecs/cx2070x.h
Normal 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
266
sound/soc/codecs/cxdebug.c
Normal 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");
|
||||
|
||||
46
sound/soc/codecs/cxdebug.h
Normal file
46
sound/soc/codecs/cxdebug.h
Normal 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
978
sound/soc/codecs/cxpump.c
Normal 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
206
sound/soc/codecs/cxpump.h
Normal 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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
272
sound/soc/rk29/rk29_cx2070x.c
Normal file
272
sound/soc/rk29/rk29_cx2070x.c
Normal 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");
|
||||
Reference in New Issue
Block a user