📄 colibri.cpp
字号:
/*+++ *******************************************************************\
*
* Copyright and Disclaimer:
*
* ---------------------------------------------------------------
* This software is provided "AS IS" without warranty of any kind,
* either expressed or implied, including but not limited to the
* implied warranties of noninfringement, merchantability and/or
* fitness for a particular purpose.
* ---------------------------------------------------------------
*
* Copyright (c) 2008 Conexant Systems, Inc.
* All rights reserved.
*
\******************************************************************* ---*/
#include "colibri.h"
#include "miscfuncs.h"
#include "debug.h"
Colibri::Colibri(DriverI2C* p_i2c, void* p_DIF):
_p_i2c(p_i2c)
{
KeInitializeMutex(&_mutex, 0);
_p_DIF = (DirectIF *)p_DIF;
}
Colibri::~Colibri()
{
}
VOID Colibri::lock()
{
KeWaitForSingleObject(&_mutex, Executive, KernelMode, FALSE, NULL );
}
/////////////////////////////////////////////////////////////////////////////////////////
VOID Colibri::unlock()
{
KeReleaseMutex(&_mutex, FALSE);
}
VOID Colibri::initialize()
{
initSuperBlock();
initChannels();
}
VOID Colibri::SetupAFEforLowIF()
{
RegMaskWrite(8, ADC_STATUS2_CH3, 0, 0, 1); // clear the stab flag latch
RegMaskWrite(8, ADC_PWRDN_CLAMP_CH2, 4, 6, 0x7); //pwr down ch2
// config colibri to lo-if mode
// FIXME: ntf_mode = 2'b00 by default. But set 0x1 would reduce the diff IF input by half,
// for low-if agc defect
RegMaskWrite(8, ADC_NTF_PRECLMP_EN_CH3, 0, 1, 0x0); // ntf_mode = 2'b0
RegMaskWrite(8, ADC_INPUT_CH3, 1, 2, 0x1); // input_mode = 2'b1
RegMaskWrite(8, ADC_FB_FRCRST_CH3, 2, 2, 0x1); // fb_mode = 1'b1
RegMaskWrite(8, ADC_DCSERVO_DEM_CH3, 0, 1, 0x3); // clk_inv = dem_off = 1'b1
RegMaskWrite(8, ADC_CTRL_DAC1_CH3, 2, 2, 0x1); // ctrl_dac1 = 1'b1
RegMaskWrite(8, ADC_CTRL_DAC23_CH3 , 0, 2, 0x6); // ctrl_dac2 = 3'b6
RegMaskWrite(8, ADC_CTRL_DAC23_CH3, 4, 6, 0x4); // ctrl_dac3 = 3'b4
RegMaskWrite(8, ADC_PWRDN_CLAMP_CH3, 5, 5, 0x1); // pd_buffer = 1'b1
}
VOID Colibri::SetupAFEforBaseband()
{
BYTE c_value = 0;
readByte(ADC_PWRDN_CLAMP_CH2, &c_value);
c_value &= (~(0x50));
writeByte(ADC_PWRDN_CLAMP_CH2, c_value);
}
VOID Colibri::SetupAFEforHiIF()
{
//todo:ask Alsor for Hi-IF settings
}
VOID Colibri::initializeAudioInputTunerTv()
{
RegMaskWrite(8, ADC_INPUT_CH1, 4, 5, 0x3);
RegMaskWrite(8, ADC_INPUT_CH3, 4, 5, 0x1);
RegMaskWrite(8, ADC_PWRDN_CLAMP_CH2, 4, 6, 0x7); //pwr down ch2
}
NTSTATUS Colibri::RegMaskWrite(BYTE size, WORD register_address,BYTE bit_start,BYTE bit_end, DWORD value)
{
if (bit_start>(size-1) || bit_end>(size-1))
{
return STATUS_UNSUCCESSFUL;
}
CHAR tmp[4] = {0,};
NTSTATUS status = STATUS_SUCCESS;
if (size==8)
{
status = readByte(register_address, (PBYTE)tmp);
}
else
{
status = readDword(register_address, (PDWORD)tmp);
}
if (!NT_SUCCESS(status))
{
return status;
}
DWORD mask = 1<<bit_end;
for (int i=bit_end; i>bit_start&&i>0; i--)
{
mask = mask + (1<<(i-1));
}
value <<= bit_start;
if (size==8)
{
(*(PBYTE)tmp) = (*(PBYTE)tmp) & ((BYTE)~mask);
(*(PBYTE)tmp) = (*(PBYTE)tmp) | ((BYTE)value);
status = writeByte(register_address, (*(PBYTE)tmp));
}
else
{
(*(PDWORD)tmp) = (*(PDWORD)tmp) & ((DWORD)~mask);
(*(PDWORD)tmp) = (*(PDWORD)tmp) | ((DWORD)value);
status = writeDword(register_address, (*(PDWORD)tmp));
}
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::readByte(WORD register_address, PBYTE p_value)
{
lock();
NTSTATUS status = readByteNoLock(register_address, p_value);
unlock();
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::writeByte(WORD register_address, BYTE value)
{
lock();
NTSTATUS status = writeByteNoLock(register_address, value);
unlock();
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::readByteNoLock(WORD register_address, PBYTE p_value)
{
BYTE addr[2] = {0,0};
addr[0] = (BYTE) register_address;
addr[1] = (register_address >> 8) & 0xff;
BOOLEAN status = _p_i2c->read(
Colibri_DEVICE_ADDRESS>>1,
2,
&addr[0],
1,
p_value);
if (status==TRUE)
{
return STATUS_SUCCESS;
}
else
{
return STATUS_UNSUCCESSFUL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::writeByteNoLock(WORD register_address, BYTE value)
{
BYTE buffer[2];
buffer[0] = (register_address) & 0xff;
buffer[1] = (register_address>>8) & 0xff;
BOOLEAN status = _p_i2c->write(
Colibri_DEVICE_ADDRESS>>1,
2,
buffer,
1,
&value);
if (status==TRUE)
{
return STATUS_SUCCESS;
}
else
{
return STATUS_UNSUCCESSFUL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS Colibri::writeDword(WORD register_address, DWORD value)
{
BYTE buffer[2];
BYTE v[4];
buffer[0] = (BYTE) (register_address );
buffer[1] = (BYTE) (register_address>>8);
v[0] = (BYTE) (value);
v[1] = (BYTE) (value >> 8);
v[2] = (BYTE) (value >> 16);
v[3] = (BYTE) (value >> 24);
lock();
BOOLEAN status = _p_i2c->write(
Colibri_DEVICE_ADDRESS>>1,
2,
buffer,
4,
v);
unlock();
if (status==TRUE)
{
return STATUS_SUCCESS;
}
else
{
return STATUS_UNSUCCESSFUL;
}
}
NTSTATUS Colibri::readDword(WORD register_address, PDWORD p_value)
{
BYTE addr[2] = {0,0};
addr[0] = (BYTE) register_address ;
addr[1] = (register_address>> 8 )& 0xff;
lock();
BOOLEAN status = _p_i2c->read(
Colibri_DEVICE_ADDRESS>>1,
2,
&addr[0],
4,
(PBYTE)p_value);
unlock();
if (status==TRUE)
{
return STATUS_SUCCESS;
}
else
{
return STATUS_UNSUCCESSFUL;
}
}
/*
we have 3 channel
channel 1 ----- pin 1 to pin4(in reg is 1-4)
channel 2 ----- pin 5 to pin8(in reg is 5-8)
channel 3 ----- pin 9 to pin 12(in reg is 9-11)
*/
VOID Colibri::setInputMux(DWORD input_mux)
{
BYTE ch1_setting = (BYTE)input_mux;
BYTE ch2_setting = (BYTE)(input_mux >> 8);
BYTE ch3_setting = (BYTE)(input_mux >> 16);
WORD ch1 = 0;
WORD ch2 = 0;
WORD ch3 = 0;
BYTE value = 0;
if(ch1_setting != 0)
{
readByte(ADC_INPUT_CH1, &value);
value &= (!INPUT_SEL_MASK);
value |= (ch1_setting-1)<<4;
writeByte(ADC_INPUT_CH1, value);
}
if(ch2_setting != 0)
{
readByte(ADC_INPUT_CH2, &value);
value &= (!INPUT_SEL_MASK);
value |= (ch2_setting-1)<<4;
writeByte(ADC_INPUT_CH2, value);
}
//For ch3_setting, the value to put in the register is 7 less than the input number
if(ch3_setting != 0)
{
readByte(ADC_INPUT_CH3, &value);
value &= (!INPUT_SEL_MASK);
value |= (ch3_setting-1)<<4;
writeByte(ADC_INPUT_CH3, value);
}
}
// Function name : Colibri::static_setColibriForLowIF
// Description : Sets up colibri for Low IF mode, BW center Freq = 12.5MHz
// channel 3 differential mode.
// Return type : void
// Argument : void *p_Colibri
// Argument : DWORD if_freq
// Argument : BOOL spectral_invert
// Argument : ULONG mode
void Colibri::static_setColibriForLowIF(void *p_Colibri, DWORD if_freq, BOOL spectral_invert, ULONG mode)
{
ASSERT(p_Colibri);
DirectIF * p_DIF;
DWORD colibri_carrier_offset = 0;
Colibri * pColibri = (Colibri *)p_Colibri;
if(pColibri)
{
p_DIF = pColibri->getDIF();
//Set colibri for low IF
pColibri->SetMode(Colibri::AFE_MODE_LOW_IF);//SetupAFEforLowIF();
// Set C2HH for low IF operation.
p_DIF->ConfigureC2HHforLowIF(mode);
// Get colibri offsets.
colibri_carrier_offset = pColibri->GetColibriCarrierOffset(mode);
// Set the band Pass filter for DIF
p_DIF->setDIFbandpass( (if_freq+colibri_carrier_offset) , spectral_invert, mode);
}
}
// Function name : Colibri::GetColibriCarrierOffset
// Description : Return the frequency shift that the IF gets after
// passing though colibri. For NTSC the IF changes from 5.35 to 10.18
// or 10.6(video carrier center freq)
// Return type : DWORD
DWORD Colibri::GetColibriCarrierOffset(ULONG mode)
{
DWORD colibri_carrier_offset = 0;
if(mode == KSPROPERTY_TUNER_MODE_FM_RADIO)
{
colibri_carrier_offset = 1100000;
}
else
{
//get offset for KSPROPERTY_TUNER_MODE_TV
DWORD video_standard = KS_AnalogVideo_NTSC_M;
video_standard = _p_DIF->getStandard();
switch(video_standard)
{
case KS_AnalogVideo_PAL_B:
case KS_AnalogVideo_PAL_G:
colibri_carrier_offset = 2700000; //2.70MHz
break;
case KS_AnalogVideo_PAL_D:
case KS_AnalogVideo_PAL_I:
case KS_AnalogVideo_SECAM_L:
case KS_AnalogVideo_SECAM_L1:
colibri_carrier_offset = 2100000; //2.70MHz
break;
default:
case KS_AnalogVideo_NTSC_M:
case KS_AnalogVideo_NTSC_M_J:
colibri_carrier_offset = 4832000; //4.83MHz
break;
}
}
return colibri_carrier_offset;
}
VOID Colibri::initSuperBlock()
{
// super block initialize
writeByte( SUP_BLK_TUNE1, 0x42); // 0x00
writeByte( SUP_BLK_TUNE2, 0x12); // 0x01
writeByte( SUP_BLK_PLL2, 0x0f); // 0x05
// enable pll
writeByte( SUP_BLK_PWRDN, 0x18); // 0x08
// start tuning filter
writeByte( SUP_BLK_TUNE3, 0x40); // 0x02
sleep(5);
// exit tuning
writeByte( SUP_BLK_TUNE3, 0x00); // 0x02
}
VOID Colibri::initChannels()
{
// power up all 3 channels, clear pd_buffer
writeByte( ADC_PWRDN_CLAMP_CH1, 0x00); // 0x23
writeByte( ADC_PWRDN_CLAMP_CH2, 0x00);
writeByte( ADC_PWRDN_CLAMP_CH3, 0x00);
// Enable quantizer calibration
writeByte( ADC_COM_QUANT, 0x02); // 0x0B
// channel initialize
// force modulator (fb) reset
writeByte( ADC_FB_FRCRST_CH1, 0x17); // 0x27
writeByte( ADC_FB_FRCRST_CH2, 0x17);
writeByte( ADC_FB_FRCRST_CH3, 0x17);
// start quantilizer calibration
writeByte( ADC_CAL_ATEST_CH1, 0x10); // 0x22
writeByte( ADC_CAL_ATEST_CH2, 0x10);
writeByte( ADC_CAL_ATEST_CH3, 0x10);
sleep(5);
// exit modulator (fb) reset
writeByte( ADC_FB_FRCRST_CH1, 0x07); // 0x27
writeByte( ADC_FB_FRCRST_CH2, 0x07);
writeByte( ADC_FB_FRCRST_CH3, 0x07);
// enable the pre_clamp in each channel for single-ended input
writeByte( ADC_NTF_PRECLMP_EN_CH1, 0xf0); // 0x29
writeByte( ADC_NTF_PRECLMP_EN_CH2, 0xf0);
writeByte( ADC_NTF_PRECLMP_EN_CH3, 0xf0);
// use diode instead of resistor, so set term_en to 0, res_en to 0
RegMaskWrite(8, ADC_QGAIN_RES_TRM_CH1, 3, 7, 0x00); // 0x2A
RegMaskWrite(8, ADC_QGAIN_RES_TRM_CH2, 3, 7, 0x00);
RegMaskWrite(8, ADC_QGAIN_RES_TRM_CH3, 3, 7, 0x00);
//dynamic element matching off
writeByte( ADC_DCSERVO_DEM_CH1, 0x03); // 0x26
writeByte( ADC_DCSERVO_DEM_CH2, 0x03);
writeByte( ADC_DCSERVO_DEM_CH3, 0x03);
}
VOID Colibri::powerUp()
{
//todo:finsih this
initialize();
}
VOID Colibri::powerDown()
{
//todo:finsih this
}
VOID Colibri::SetMode(AFE_MODE mode)
{
switch(mode)
{
case AFE_MODE_LOW_IF:
SetupAFEforLowIF();
break;
case
AFE_MODE_BASEBAND:
SetupAFEforBaseband();
break;
case
AFE_MODE_HI_IF:
SetupAFEforHiIF();
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -