From 230930e97557ae77c517098112ba56a73a56ca1f Mon Sep 17 00:00:00 2001 From: Steve Markgraf Date: Mon, 4 Nov 2013 21:50:02 +0100 Subject: [PATCH] use new driver for R8XX tuners Signed-off-by: Steve Markgraf --- include/tuner_r820t.h | 196 --- include/tuner_r82xx.h | 116 ++ src/CMakeLists.txt | 4 +- src/Makefile.am | 2 +- src/librtlsdr.c | 61 +- src/tuner_r820t.c | 3050 ----------------------------------------- src/tuner_r82xx.c | 1252 +++++++++++++++++ 7 files changed, 1415 insertions(+), 3266 deletions(-) delete mode 100644 include/tuner_r820t.h create mode 100644 include/tuner_r82xx.h delete mode 100644 src/tuner_r820t.c create mode 100644 src/tuner_r82xx.c diff --git a/include/tuner_r820t.h b/include/tuner_r820t.h deleted file mode 100644 index f9bd4cf..0000000 --- a/include/tuner_r820t.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef _R820T_TUNER_H -#define _R820T_TUNER_H - -#define R820T_I2C_ADDR 0x34 -#define R820T_CHECK_ADDR 0x00 -#define R820T_CHECK_VAL 0x69 - -#define R820T_IF_FREQ 3570000 - -//*************************************************************** -//* INCLUDES.H -//*************************************************************** -#define VERSION "R820T_v1.49_ASTRO" -#define VER_NUM 49 - -#define USE_16M_XTAL FALSE -#define R828_Xtal 28800 - -#define USE_DIPLEXER FALSE -#define TUNER_CLK_OUT TRUE - -#ifndef _UINT_X_ -#define _UINT_X_ 1 -typedef unsigned char UINT8; -typedef unsigned short UINT16; -typedef unsigned int UINT32; -#endif - -#define TRUE 1 -#define FALSE 0 - -#define FUNCTION_SUCCESS 0 -#define FUNCTION_ERROR -1 - -typedef enum _R828_ErrCode -{ - RT_Success, - RT_Fail -}R828_ErrCode; - -typedef enum _Rafael_Chip_Type //Don't modify chip list -{ - R828 = 0, - R828D, - R828S, - R820T, - R820C, - R620D, - R620S -}Rafael_Chip_Type; -//----------------------------------------------------------// -// R828 Parameter // -//----------------------------------------------------------// - -extern UINT8 R828_ADDRESS; - -#define DIP_FREQ 320000 -#define IMR_TRIAL 9 -#define VCO_pwr_ref 0x02 - -extern UINT32 R828_IF_khz; -extern UINT32 R828_CAL_LO_khz; -extern UINT8 R828_IMR_point_num; -extern UINT8 R828_IMR_done_flag; -extern UINT8 Rafael_Chip; - -typedef enum _R828_Standard_Type //Don't remove standand list!! -{ - NTSC_MN = 0, - PAL_I, - PAL_DK, - PAL_B_7M, //no use - PAL_BGH_8M, //for PAL B/G, PAL G/H - SECAM_L, - SECAM_L1_INV, //for SECAM L' - SECAM_L1, //no use - ATV_SIZE, - DVB_T_6M = ATV_SIZE, - DVB_T_7M, - DVB_T_7M_2, - DVB_T_8M, - DVB_T2_6M, - DVB_T2_7M, - DVB_T2_7M_2, - DVB_T2_8M, - DVB_T2_1_7M, - DVB_T2_10M, - DVB_C_8M, - DVB_C_6M, - ISDB_T, - DTMB, - R828_ATSC, - FM, - STD_SIZE -}R828_Standard_Type; - -extern UINT8 R828_Fil_Cal_flag[STD_SIZE]; - -typedef enum _R828_SetFreq_Type -{ - FAST_MODE = TRUE, - NORMAL_MODE = FALSE -}R828_SetFreq_Type; - -typedef enum _R828_LoopThrough_Type -{ - LOOP_THROUGH = TRUE, - SIGLE_IN = FALSE -}R828_LoopThrough_Type; - - -typedef enum _R828_InputMode_Type -{ - AIR_IN = 0, - CABLE_IN_1, - CABLE_IN_2 -}R828_InputMode_Type; - -typedef enum _R828_IfAgc_Type -{ - IF_AGC1 = 0, - IF_AGC2 -}R828_IfAgc_Type; - -typedef enum _R828_GPIO_Type -{ - HI_SIG = TRUE, - LO_SIG = FALSE -}R828_GPIO_Type; - -typedef struct _R828_Set_Info -{ - UINT32 RF_Hz; - UINT32 RF_KHz; - R828_Standard_Type R828_Standard; - R828_LoopThrough_Type RT_Input; - R828_InputMode_Type RT_InputMode; - R828_IfAgc_Type R828_IfAgc_Select; -}R828_Set_Info; - -typedef struct _R828_RF_Gain_Info -{ - UINT8 RF_gain1; - UINT8 RF_gain2; - UINT8 RF_gain_comb; -}R828_RF_Gain_Info; - -typedef enum _R828_RF_Gain_TYPE -{ - RF_AUTO = 0, - RF_MANUAL -}R828_RF_Gain_TYPE; - -typedef struct _R828_I2C_LEN_TYPE -{ - UINT8 RegAddr; - UINT8 Data[50]; - UINT8 Len; -}R828_I2C_LEN_TYPE; - -typedef struct _R828_I2C_TYPE -{ - UINT8 RegAddr; - UINT8 Data; -}R828_I2C_TYPE; -//----------------------------------------------------------// -// R828 Function // -//----------------------------------------------------------// -R828_ErrCode R828_Init(void *pTuner); -R828_ErrCode R828_Standby(void *pTuner, R828_LoopThrough_Type R828_LoopSwitch); -R828_ErrCode R828_GPIO(void *pTuner, R828_GPIO_Type R828_GPIO_Conrl); -R828_ErrCode R828_SetStandard(void *pTuner, R828_Standard_Type RT_Standard); -R828_ErrCode R828_SetFrequency(void *pTuner, R828_Set_Info R828_INFO, R828_SetFreq_Type R828_SetFreqMode); -R828_ErrCode R828_GetRfGain(void *pTuner, R828_RF_Gain_Info *pR828_rf_gain); -R828_ErrCode R828_SetRfGain(void *pTuner, int gain); -R828_ErrCode R828_RfGainMode(void *pTuner, int manual); - -int -r820t_SetRfFreqHz( - void *pTuner, - unsigned long RfFreqHz - ); - -int -r820t_SetStandardMode( - void *pTuner, - int StandardMode - ); - -int -r820t_SetStandby( - void *pTuner, - int LoopThroughType - ); - -#endif /* _R820T_TUNER_H */ diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h new file mode 100644 index 0000000..2295574 --- /dev/null +++ b/include/tuner_r82xx.h @@ -0,0 +1,116 @@ +/* + * Rafael Micro R820T/R828D driver + * + * Copyright (C) 2013 Mauro Carvalho Chehab + * Copyright (C) 2013 Steve Markgraf + * + * This driver is a heavily modified version of the driver found in the + * Linux kernel: + * http://git.linuxtv.org/linux-2.6.git/history/HEAD:/drivers/media/tuners/r820t.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. + * + * This program 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 program. If not, see . + */ + +#ifndef R82XX_H +#define R82XX_H + +#define R820T_I2C_ADDR 0x34 +#define R820T_CHECK_ADDR 0x00 +#define R820T_CHECK_VAL 0x69 + +#define R82XX_IF_FREQ 3570000 + +#define REG_SHADOW_START 5 +#define NUM_REGS 30 +#define NUM_IMR 5 +#define IMR_TRIAL 9 + +#define VER_NUM 49 + +enum r82xx_chip { + CHIP_R820T, + CHIP_R620D, + CHIP_R828D, + CHIP_R828, + CHIP_R828S, + CHIP_R820C, +}; + +enum r82xx_tuner_type { + TUNER_RADIO = 1, + TUNER_ANALOG_TV, + TUNER_DIGITAL_TV +}; + +enum r82xx_xtal_cap_value { + XTAL_LOW_CAP_30P = 0, + XTAL_LOW_CAP_20P, + XTAL_LOW_CAP_10P, + XTAL_LOW_CAP_0P, + XTAL_HIGH_CAP_0P +}; + +struct r82xx_config { + uint8_t i2c_addr; + uint32_t xtal; + enum r82xx_chip rafael_chip; + unsigned int max_i2c_msg_len; + int use_diplexer; + int use_predetect; +}; + +struct r82xx_priv { + struct r82xx_config *cfg; + + uint8_t regs[NUM_REGS]; + uint8_t buf[NUM_REGS + 1]; + enum r82xx_xtal_cap_value xtal_cap_sel; + uint16_t pll; /* kHz */ + uint32_t int_freq; + uint8_t fil_cal_code; + int has_lock; + int init_done; + + /* Store current mode */ + uint32_t delsys; + enum r82xx_tuner_type type; + + uint32_t bw; /* in MHz */ + + void *rtl_dev; +}; + +struct r82xx_freq_range { + uint32_t freq; + uint8_t open_d; + uint8_t rf_mux_ploy; + uint8_t tf_c; + uint8_t xtal_cap20p; + uint8_t xtal_cap10p; + uint8_t xtal_cap0p; +}; + +enum r82xx_delivery_system { + SYS_UNDEFINED, + SYS_DVBT, + SYS_DVBT2, + SYS_ISDBT, +}; + +int r82xx_standby(struct r82xx_priv *priv); +int r82xx_init(struct r82xx_priv *priv); +int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq); +int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain); + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 38ac947..ffaf435 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,7 +26,7 @@ add_library(rtlsdr_shared SHARED tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c - tuner_r820t.c + tuner_r82xx.c ) target_link_libraries(rtlsdr_shared @@ -44,7 +44,7 @@ add_library(rtlsdr_static STATIC tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c - tuner_r820t.c + tuner_r82xx.c ) if(WIN32) diff --git a/src/Makefile.am b/src/Makefile.am index 91cb010..8b27660 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ AM_CFLAGS = ${CFLAGS} -fPIC ${SYMBOL_VISIBILITY} lib_LTLIBRARIES = librtlsdr.la -librtlsdr_la_SOURCES = librtlsdr.c tuner_e4k.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c tuner_r820t.c +librtlsdr_la_SOURCES = librtlsdr.c tuner_e4k.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c tuner_r82xx.c librtlsdr_la_LDFLAGS = -version-info $(LIBVERSION) bin_PROGRAMS = rtl_sdr rtl_tcp rtl_test rtl_fm rtl_eeprom rtl_adsb rtl_power diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 9ccff1e..a0026fd 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -1,6 +1,6 @@ /* * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver - * Copyright (C) 2012 by Steve Markgraf + * Copyright (C) 2012-2013 by Steve Markgraf * Copyright (C) 2012 by Dimitri Stolnikov * * This program is free software: you can redistribute it and/or modify @@ -47,7 +47,7 @@ #include "tuner_fc0012.h" #include "tuner_fc0013.h" #include "tuner_fc2580.h" -#include "tuner_r820t.h" +#include "tuner_r82xx.h" typedef struct rtlsdr_tuner_iface { /* tuner interface */ @@ -89,6 +89,9 @@ struct rtlsdr_dev { int corr; /* ppm */ int gain; /* tenth dB */ struct e4k_state e4k_s; + struct r82xx_config r82xx_c; + struct r82xx_priv r82xx_p; + /* status */ int dev_lost; int driver_active; unsigned int xfer_errors; @@ -179,16 +182,38 @@ int fc2580_set_gain(void *dev, int gain) { return 0; } int fc2580_set_gain_mode(void *dev, int manual) { return 0; } int r820t_init(void *dev) { - int r = R828_Init(dev); - r820t_SetStandardMode(dev, DVB_T_6M); - return r; -} -int r820t_exit(void *dev) { return r820t_SetStandby(dev, 0); } -int r820t_set_freq(void *dev, uint32_t freq) { return r820t_SetRfFreqHz(dev, freq); } -int r820t_set_bw(void *dev, int bw) { return 0; } -int r820t_set_gain(void *dev, int gain) { return R828_SetRfGain(dev, gain); } -int r820t_set_gain_mode(void *dev, int manual) { return R828_RfGainMode(dev, manual); } + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + devt->r82xx_p.rtl_dev = dev; + devt->r82xx_c.i2c_addr = R820T_I2C_ADDR; + rtlsdr_get_xtal_freq(devt, NULL, &devt->r82xx_c.xtal); + + devt->r82xx_c.rafael_chip = CHIP_R820T; + devt->r82xx_c.max_i2c_msg_len = 2; + devt->r82xx_c.use_diplexer = 0; + devt->r82xx_c.use_predetect = 0; + devt->r82xx_p.cfg = &devt->r82xx_c; + + return r82xx_init(&devt->r82xx_p); +} +int r820t_exit(void *dev) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_standby(&devt->r82xx_p); +} + +int r820t_set_freq(void *dev, uint32_t freq) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_set_freq(&devt->r82xx_p, freq); +} +int r820t_set_bw(void *dev, int bw) { return 0; } +int r820t_set_gain(void *dev, int gain) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_set_gain(&devt->r82xx_p, 1, gain); +} +int r820t_set_gain_mode(void *dev, int manual) { + rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; + return r82xx_set_gain(&devt->r82xx_p, manual, 0); +} /* definition order must match enum rtlsdr_tuner */ static rtlsdr_tuner_iface_t tuners[] = { { @@ -652,8 +677,9 @@ int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq, uint32_t tuner_fr else dev->tun_xtal = tuner_freq; - /* read corrected clock value into e4k structure */ - if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc)) + /* read corrected clock value into e4k and r82xx structure */ + if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc) || + rtlsdr_get_xtal_freq(dev, NULL, &dev->r82xx_c.xtal)) return -3; /* update xtal-dependent settings */ @@ -829,8 +855,9 @@ int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm) r |= rtlsdr_set_sample_freq_correction(dev, ppm); - /* read corrected clock value into e4k structure */ - if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc)) + /* read corrected clock value into e4k and r82xx structure */ + if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc) || + rtlsdr_get_xtal_freq(dev, NULL, &dev->r82xx_c.xtal)) return -3; if (dev->freq) /* retune to apply new correction value */ @@ -1077,7 +1104,7 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on) } if (dev->tuner_type == RTLSDR_TUNER_R820T) { - r |= rtlsdr_set_if_freq(dev, R820T_IF_FREQ); + r |= rtlsdr_set_if_freq(dev, R82XX_IF_FREQ); /* enable spectrum inversion */ r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1); @@ -1418,7 +1445,7 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) /* the R820T uses 3.57 MHz IF for the DVB-T 6 MHz mode, and * 4.57 MHz for the 8 MHz mode */ - rtlsdr_set_if_freq(dev, R820T_IF_FREQ); + rtlsdr_set_if_freq(dev, R82XX_IF_FREQ); /* enable spectrum inversion */ rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1); diff --git a/src/tuner_r820t.c b/src/tuner_r820t.c deleted file mode 100644 index 5f241df..0000000 --- a/src/tuner_r820t.c +++ /dev/null @@ -1,3050 +0,0 @@ -/* - * R820T tuner driver, taken from Realteks RTL2832U Linux Kernel Driver - * - * This driver is a mess, and should be cleaned up/rewritten. - * - */ - -#include -#include - -#include "rtlsdr_i2c.h" -#include "tuner_r820t.h" - -int r820t_SetRfFreqHz(void *pTuner, unsigned long RfFreqHz) -{ - R828_Set_Info R828Info; - -// if(pExtra->IsStandardModeSet==NO) -// goto error_status_set_tuner_rf_frequency; - -// R828Info.R828_Standard = (R828_Standard_Type)pExtra->StandardMode; - R828Info.R828_Standard = (R828_Standard_Type)DVB_T_6M; - R828Info.RF_Hz = (UINT32)(RfFreqHz); - R828Info.RF_KHz = (UINT32)(RfFreqHz/1000); - - if(R828_SetFrequency(pTuner, R828Info, NORMAL_MODE) != RT_Success) - return FUNCTION_ERROR; - - return FUNCTION_SUCCESS; -} - -int r820t_SetStandardMode(void *pTuner, int StandardMode) -{ - if(R828_SetStandard(pTuner, (R828_Standard_Type)StandardMode) != RT_Success) - return FUNCTION_ERROR; - - return FUNCTION_SUCCESS; -} - -int r820t_SetStandby(void *pTuner, int LoopThroughType) -{ - - if(R828_Standby(pTuner, (R828_LoopThrough_Type)LoopThroughType) != RT_Success) - return FUNCTION_ERROR; - - return FUNCTION_SUCCESS; -} - -// The following context is implemented for R820T source code. - -/* just reverses the bits of a byte */ -int -r820t_Convert(int InvertNum) -{ - int ReturnNum; - int AddNum; - int BitNum; - int CountNum; - - ReturnNum = 0; - AddNum = 0x80; - BitNum = 0x01; - - for(CountNum = 0;CountNum < 8;CountNum ++) - { - if(BitNum & InvertNum) - ReturnNum += AddNum; - - AddNum /= 2; - BitNum *= 2; - } - - return ReturnNum; -} - -R828_ErrCode -I2C_Write_Len(void *pTuner, R828_I2C_LEN_TYPE *I2C_Info) -{ - unsigned char DeviceAddr; - - unsigned int i, j; - - unsigned char RegStartAddr; - unsigned char *pWritingBytes; - unsigned long ByteNum; - - unsigned char WritingBuffer[128]; - unsigned long WritingByteNum, WritingByteNumMax, WritingByteNumRem; - unsigned char RegWritingAddr; - - // Get regiser start address, writing bytes, and byte number. - RegStartAddr = I2C_Info->RegAddr; - pWritingBytes = I2C_Info->Data; - ByteNum = (unsigned long)I2C_Info->Len; - - // Calculate maximum writing byte number. -// WritingByteNumMax = pBaseInterface->I2cWritingByteNumMax - LEN_1_BYTE; - WritingByteNumMax = 2 - 1; //9 orig - - // Set tuner register bytes with writing bytes. - // Note: Set tuner register bytes considering maximum writing byte number. - for(i = 0; i < ByteNum; i += WritingByteNumMax) - { - // Set register writing address. - RegWritingAddr = RegStartAddr + i; - - // Calculate remainder writing byte number. - WritingByteNumRem = ByteNum - i; - - // Determine writing byte number. - WritingByteNum = (WritingByteNumRem > WritingByteNumMax) ? WritingByteNumMax : WritingByteNumRem; - - // Set writing buffer. - // Note: The I2C format of tuner register byte setting is as follows: - // start_bit + (DeviceAddr | writing_bit) + RegWritingAddr + writing_bytes (WritingByteNum bytes) + - // stop_bit - WritingBuffer[0] = RegWritingAddr; - - for(j = 0; j < WritingByteNum; j++) - WritingBuffer[j+1] = pWritingBytes[i + j]; - - // Set tuner register bytes with writing buffer. -// if(pI2cBridge->ForwardI2cWritingCmd(pI2cBridge, DeviceAddr, WritingBuffer, WritingByteNum + LEN_1_BYTE) != -// FUNCTION_SUCCESS) -// goto error_status_set_tuner_registers; - - if (rtlsdr_i2c_write_fn(pTuner, R820T_I2C_ADDR, WritingBuffer, WritingByteNum + 1) < 0) - return RT_Fail; - } - - return RT_Success; -} - -R828_ErrCode -I2C_Read_Len(void *pTuner, R828_I2C_LEN_TYPE *I2C_Info) -{ - uint8_t DeviceAddr; - - unsigned int i; - - uint8_t RegStartAddr; - uint8_t ReadingBytes[128]; - unsigned long ByteNum; - - // Get regiser start address, writing bytes, and byte number. - RegStartAddr = 0x00; - ByteNum = (unsigned long)I2C_Info->Len; - - // Set tuner register reading address. - // Note: The I2C format of tuner register reading address setting is as follows: - // start_bit + (DeviceAddr | writing_bit) + RegReadingAddr + stop_bit -// if(pI2cBridge->ForwardI2cWritingCmd(pI2cBridge, DeviceAddr, &RegStartAddr, LEN_1_BYTE) != FUNCTION_SUCCESS) -// goto error_status_set_tuner_register_reading_address; - - if (rtlsdr_i2c_write_fn(pTuner, R820T_I2C_ADDR, &RegStartAddr, 1) < 0) - return RT_Fail; - - // Get tuner register bytes. - // Note: The I2C format of tuner register byte getting is as follows: - // start_bit + (DeviceAddr | reading_bit) + reading_bytes (ReadingByteNum bytes) + stop_bit -// if(pI2cBridge->ForwardI2cReadingCmd(pI2cBridge, DeviceAddr, ReadingBytes, ByteNum) != FUNCTION_SUCCESS) -// goto error_status_get_tuner_registers; - - if (rtlsdr_i2c_read_fn(pTuner, R820T_I2C_ADDR, ReadingBytes, ByteNum) < 0) - return RT_Fail; - - for(i = 0; iData[i] = (UINT8)r820t_Convert(ReadingBytes[i]); - } - - - return RT_Success; - - -error_status_get_tuner_registers: -error_status_set_tuner_register_reading_address: - - return RT_Fail; -} - -R828_ErrCode -I2C_Write(void *pTuner, R828_I2C_TYPE *I2C_Info) -{ - uint8_t WritingBuffer[2]; - - // Set writing bytes. - // Note: The I2C format of tuner register byte setting is as follows: - // start_bit + (DeviceAddr | writing_bit) + addr + data + stop_bit - WritingBuffer[0] = I2C_Info->RegAddr; - WritingBuffer[1] = I2C_Info->Data; - - // Set tuner register bytes with writing buffer. -// if(pI2cBridge->ForwardI2cWritingCmd(pI2cBridge, DeviceAddr, WritingBuffer, LEN_2_BYTE) != FUNCTION_SUCCESS) -// goto error_status_set_tuner_registers; - -// printf("called %s: %02x -> %02x\n", __FUNCTION__, WritingBuffer[0], WritingBuffer[1]); - - if (rtlsdr_i2c_write_fn(pTuner, R820T_I2C_ADDR, WritingBuffer, 2) < 0) - return RT_Fail; - - return RT_Success; -} - -void -R828_Delay_MS( - void *pTuner, - unsigned long WaitTimeMs - ) -{ - /* simply don't wait for now */ - return; -} - -//----------------------------------------------------- -// -// Filename: R820T.c -// -// This file is R820T tuner driver -// Copyright 2011 by Rafaelmicro., Inc. -// -//----------------------------------------------------- - - -//#include "stdafx.h" -//#include "R828.h" -//#include "..\I2C_Sys.h" - - -#if(TUNER_CLK_OUT==TRUE) //enable tuner clk output for share Xtal application -UINT8 R828_iniArry[27] = {0x83, 0x32, 0x75, 0xC0, 0x40, 0xD6, 0x6C, 0xF5, 0x63, - /* 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D */ - - 0x75, 0x68, 0x6C, 0x83, 0x80, 0x00, 0x0F, 0x00, 0xC0,//xtal_check - /* 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 */ - - 0x30, 0x48, 0xCC, 0x60, 0x00, 0x54, 0xAE, 0x4A, 0xC0}; - /* 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F */ -#else -UINT8 R828_iniArry[27] = {0x83, 0x32, 0x75, 0xC0, 0x40, 0xD6, 0x6C, 0xF5, 0x63, - /* 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D */ - - 0x75, 0x78, 0x6C, 0x83, 0x80, 0x00, 0x0F, 0x00, 0xC0,//xtal_check - /* 0x0E 0x0F 0x10 0x11 0x12 0x13 0x14 0x15 0x16 */ - - 0x30, 0x48, 0xCC, 0x60, 0x00, 0x54, 0xAE, 0x4A, 0xC0}; - /* 0x17 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F */ -#endif - -UINT8 R828_ADDRESS=0x34; -UINT8 Rafael_Chip = R820T; -//----------------------------------------------------------// -// Internal Structs // -//----------------------------------------------------------// -typedef struct _R828_SectType -{ - UINT8 Phase_Y; - UINT8 Gain_X; - UINT16 Value; -}R828_SectType; - -typedef enum _BW_Type -{ - BW_6M = 0, - BW_7M, - BW_8M, - BW_1_7M, - BW_10M, - BW_200K -}BW_Type; - -typedef struct _Sys_Info_Type -{ - UINT16 IF_KHz; - BW_Type BW; - UINT32 FILT_CAL_LO; - UINT8 FILT_GAIN; - UINT8 IMG_R; - UINT8 FILT_Q; - UINT8 HP_COR; - UINT8 EXT_ENABLE; - UINT8 LOOP_THROUGH; - UINT8 LT_ATT; - UINT8 FLT_EXT_WIDEST; - UINT8 POLYFIL_CUR; -}Sys_Info_Type; - -typedef struct _Freq_Info_Type -{ - UINT8 OPEN_D; - UINT8 RF_MUX_PLOY; - UINT8 TF_C; - UINT8 XTAL_CAP20P; - UINT8 XTAL_CAP10P; - UINT8 XTAL_CAP0P; - UINT8 IMR_MEM; -}Freq_Info_Type; - -typedef struct _SysFreq_Info_Type -{ - UINT8 LNA_TOP; - UINT8 LNA_VTH_L; - UINT8 MIXER_TOP; - UINT8 MIXER_VTH_L; - UINT8 AIR_CABLE1_IN; - UINT8 CABLE2_IN; - UINT8 PRE_DECT; - UINT8 LNA_DISCHARGE; - UINT8 CP_CUR; - UINT8 DIV_BUF_CUR; - UINT8 FILTER_CUR; -}SysFreq_Info_Type; - -//----------------------------------------------------------// -// Internal Parameters // -//----------------------------------------------------------// -enum XTAL_CAP_VALUE -{ - XTAL_LOW_CAP_30P = 0, - XTAL_LOW_CAP_20P, - XTAL_LOW_CAP_10P, - XTAL_LOW_CAP_0P, - XTAL_HIGH_CAP_0P -}; -UINT8 R828_Arry[27]; -R828_SectType IMR_Data[5] = { - {0, 0, 0}, - {0, 0, 0}, - {0, 0, 0}, - {0, 0, 0}, - {0, 0, 0} - };//Please keep this array data for standby mode. -R828_I2C_TYPE R828_I2C; -R828_I2C_LEN_TYPE R828_I2C_Len; - -UINT32 R828_IF_khz; -UINT32 R828_CAL_LO_khz; -UINT8 R828_IMR_point_num; -UINT8 R828_IMR_done_flag = FALSE; -UINT8 R828_Fil_Cal_flag[STD_SIZE]; -static UINT8 R828_Fil_Cal_code[STD_SIZE]; - -static UINT8 Xtal_cap_sel = XTAL_LOW_CAP_0P; -static UINT8 Xtal_cap_sel_tmp = XTAL_LOW_CAP_0P; -//----------------------------------------------------------// -// Internal static struct // -//----------------------------------------------------------// -static SysFreq_Info_Type SysFreq_Info1; -static Sys_Info_Type Sys_Info1; -//static Freq_Info_Type R828_Freq_Info; -static Freq_Info_Type Freq_Info1; -//----------------------------------------------------------// -// Internal Functions // -//----------------------------------------------------------// -R828_ErrCode R828_Xtal_Check(void *pTuner); -R828_ErrCode R828_InitReg(void *pTuner); -R828_ErrCode R828_IMR_Prepare(void *pTuner); -R828_ErrCode R828_IMR(void *pTuner, UINT8 IMR_MEM, int IM_Flag); -R828_ErrCode R828_PLL(void *pTuner, UINT32 LO_Freq, R828_Standard_Type R828_Standard); -R828_ErrCode R828_MUX(void *pTuner, UINT32 RF_KHz); -R828_ErrCode R828_IQ(void *pTuner, R828_SectType* IQ_Pont); -R828_ErrCode R828_IQ_Tree(void *pTuner, UINT8 FixPot, UINT8 FlucPot, UINT8 PotReg, R828_SectType* CompareTree); -R828_ErrCode R828_CompreCor(R828_SectType* CorArry); -R828_ErrCode R828_CompreStep(void *pTuner, R828_SectType* StepArry, UINT8 Pace); -R828_ErrCode R828_Muti_Read(void *pTuner, UINT8 IMR_Reg, UINT16* IMR_Result_Data); -R828_ErrCode R828_Section(void *pTuner, R828_SectType* SectionArry); -R828_ErrCode R828_F_IMR(void *pTuner, R828_SectType* IQ_Pont); -R828_ErrCode R828_IMR_Cross(void *pTuner, R828_SectType* IQ_Pont, UINT8* X_Direct); - -Sys_Info_Type R828_Sys_Sel(R828_Standard_Type R828_Standard); -Freq_Info_Type R828_Freq_Sel(UINT32 RF_freq); -SysFreq_Info_Type R828_SysFreq_Sel(R828_Standard_Type R828_Standard,UINT32 RF_freq); - -R828_ErrCode R828_Filt_Cal(void *pTuner, UINT32 Cal_Freq,BW_Type R828_BW); -//R828_ErrCode R828_SetFrequency(void *pTuner, R828_Set_Info R828_INFO, R828_SetFreq_Type R828_SetFreqMode); - -Sys_Info_Type R828_Sys_Sel(R828_Standard_Type R828_Standard) -{ - Sys_Info_Type R828_Sys_Info; - - switch (R828_Standard) - { - - case DVB_T_6M: - case DVB_T2_6M: - R828_Sys_Info.IF_KHz=3570; - R828_Sys_Info.BW=BW_6M; - R828_Sys_Info.FILT_CAL_LO=56000; //52000->56000 - R828_Sys_Info.FILT_GAIN=0x10; //+3dB, 6MHz on - R828_Sys_Info.IMG_R=0x00; //image negative - R828_Sys_Info.FILT_Q=0x10; //R10[4]:low Q(1'b1) - R828_Sys_Info.HP_COR=0x6B; // 1.7M disable, +2cap, 1.0MHz - R828_Sys_Info.EXT_ENABLE=0x60; //R30[6]=1 ext enable; R30[5]:1 ext at LNA max-1 - R828_Sys_Info.LOOP_THROUGH=0x00; //R5[7], LT ON - R828_Sys_Info.LT_ATT=0x00; //R31[7], LT ATT enable - R828_Sys_Info.FLT_EXT_WIDEST=0x00;//R15[7]: FLT_EXT_WIDE OFF - R828_Sys_Info.POLYFIL_CUR=0x60; //R25[6:5]:Min - break; - - case DVB_T_7M: - case DVB_T2_7M: - R828_Sys_Info.IF_KHz=4070; - R828_Sys_Info.BW=BW_7M; - R828_Sys_Info.FILT_CAL_LO=60000; - R828_Sys_Info.FILT_GAIN=0x10; //+3dB, 6MHz on - R828_Sys_Info.IMG_R=0x00; //image negative - R828_Sys_Info.FILT_Q=0x10; //R10[4]:low Q(1'b1) - R828_Sys_Info.HP_COR=0x2B; // 1.7M disable, +1cap, 1.0MHz - R828_Sys_Info.EXT_ENABLE=0x60; //R30[6]=1 ext enable; R30[5]:1 ext at LNA max-1 - R828_Sys_Info.LOOP_THROUGH=0x00; //R5[7], LT ON - R828_Sys_Info.LT_ATT=0x00; //R31[7], LT ATT enable - R828_Sys_Info.FLT_EXT_WIDEST=0x00;//R15[7]: FLT_EXT_WIDE OFF - R828_Sys_Info.POLYFIL_CUR=0x60; //R25[6:5]:Min - break; - - case DVB_T_7M_2: - case DVB_T2_7M_2: - R828_Sys_Info.IF_KHz=4570; - R828_Sys_Info.BW=BW_7M; - R828_Sys_Info.FILT_CAL_LO=63000; - R828_Sys_Info.FILT_GAIN=0x10; //+3dB, 6MHz on - R828_Sys_Info.IMG_R=0x00; //image negative - R828_Sys_Info.FILT_Q=0x10; //R10[4]:low Q(1'b1) - R828_Sys_Info.HP_COR=0x2A; // 1.7M disable, +1cap, 1.25MHz - R828_Sys_Info.EXT_ENABLE=0x60; //R30[6]=1 ext enable; R30[5]:1 ext at LNA max-1 - R828_Sys_Info.LOOP_THROUGH=0x00; //R5[7], LT ON - R828_Sys_Info.LT_ATT=0x00; //R31[7], LT ATT enable - R828_Sys_Info.FLT_EXT_WIDEST=0x00;//R15[7]: FLT_EXT_WIDE OFF - R828_Sys_Info.POLYFIL_CUR=0x60; //R25[6:5]:Min - break; - - case DVB_T_8M: - case DVB_T2_8M: - R828_Sys_Info.IF_KHz=4570; - R828_Sys_Info.BW=BW_8M; - R828_Sys_Info.FILT_CAL_LO=68500; - R828_Sys_Info.FILT_GAIN=0x10; //+3dB, 6MHz on - R828_Sys_Info.IMG_R=0x00; //image negative - R828_Sys_Info.FILT_Q=0x10; //R10[4]:low Q(1'b1) - R828_Sys_Info.HP_COR=0x0B; // 1.7M disable, +0cap, 1.0MHz - R828_Sys_Info.EXT_ENABLE=0x60; //R30[6]=1 ext enable; R30[5]:1 ext at LNA max-1 - R828_Sys_Info.LOOP_THROUGH=0x00; //R5[7], LT ON - R828_Sys_Info.LT_ATT=0x00; //R31[7], LT ATT enable - R828_Sys_Info.FLT_EXT_WIDEST=0x00;//R15[7]: FLT_EXT_WIDE OFF - R828_Sys_Info.POLYFIL_CUR=0x60; //R25[6:5]:Min - break; - - case ISDB_T: - R828_Sys_Info.IF_KHz=4063; - R828_Sys_Info.BW=BW_6M; - R828_Sys_Info.FILT_CAL_LO=59000; - R828_Sys_Info.FILT_GAIN=0x10; //+3dB, 6MHz on - R828_Sys_Info.IMG_R=0x00; //image negative - R828_Sys_Info.FILT_Q=0x10; //R10[4]:low Q(1'b1) - R828_Sys_Info.HP_COR=0x6A; // 1.7M disable, +2cap, 1.25MHz - R828_Sys_Info.EXT_ENABLE=0x40; //R30[6], ext enable; R30[5]:0 ext at LNA max - R828_Sys_Info.LOOP_THROUGH=0x00; //R5[7], LT ON - R828_Sys_Info.LT_ATT=0x00; //R31[7], LT ATT enable - R828_Sys_Info.FLT_EXT_WIDEST=0x00;//R15[7]: FLT_EXT_WIDE OFF - R828_Sys_Info.POLYFIL_CUR=0x60; //R25[6:5]:Min - break; - - default: //DVB_T_8M - R828_Sys_Info.IF_KHz=4570; - R828_Sys_Info.BW=BW_8M; - R828_Sys_Info.FILT_CAL_LO=68500; - R828_Sys_Info.FILT_GAIN=0x10; //+3dB, 6MHz on - R828_Sys_Info.IMG_R=0x00; //image negative - R828_Sys_Info.FILT_Q=0x10; //R10[4]:low Q(1'b1) - R828_Sys_Info.HP_COR=0x0D; // 1.7M disable, +0cap, 0.7MHz - R828_Sys_Info.EXT_ENABLE=0x60; //R30[6]=1 ext enable; R30[5]:1 ext at LNA max-1 - R828_Sys_Info.LOOP_THROUGH=0x00; //R5[7], LT ON - R828_Sys_Info.LT_ATT=0x00; //R31[7], LT ATT enable - R828_Sys_Info.FLT_EXT_WIDEST=0x00;//R15[7]: FLT_EXT_WIDE OFF - R828_Sys_Info.POLYFIL_CUR=0x60; //R25[6:5]:Min - break; - - } - - return R828_Sys_Info; -} - -Freq_Info_Type R828_Freq_Sel(UINT32 LO_freq) -{ - Freq_Info_Type R828_Freq_Info; - - if(LO_freq<50000) - { - R828_Freq_Info.OPEN_D=0x08; // low - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0xDF; //R27[7:0] band2,band0 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - - else if(LO_freq>=50000 && LO_freq<55000) - { - R828_Freq_Info.OPEN_D=0x08; // low - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0xBE; //R27[7:0] band4,band1 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=55000 && LO_freq<60000) - { - R828_Freq_Info.OPEN_D=0x08; // low - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x8B; //R27[7:0] band7,band4 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=60000 && LO_freq<65000) - { - R828_Freq_Info.OPEN_D=0x08; // low - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x7B; //R27[7:0] band8,band4 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=65000 && LO_freq<70000) - { - R828_Freq_Info.OPEN_D=0x08; // low - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x69; //R27[7:0] band9,band6 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=70000 && LO_freq<75000) - { - R828_Freq_Info.OPEN_D=0x08; // low - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x58; //R27[7:0] band10,band7 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=75000 && LO_freq<80000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x44; //R27[7:0] band11,band11 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=80000 && LO_freq<90000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x44; //R27[7:0] band11,band11 - R828_Freq_Info.XTAL_CAP20P=0x02; //R16[1:0] 20pF (10) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=90000 && LO_freq<100000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x34; //R27[7:0] band12,band11 - R828_Freq_Info.XTAL_CAP20P=0x01; //R16[1:0] 10pF (01) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=100000 && LO_freq<110000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x34; //R27[7:0] band12,band11 - R828_Freq_Info.XTAL_CAP20P=0x01; //R16[1:0] 10pF (01) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 0; - } - else if( LO_freq>=110000 && LO_freq<120000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x24; //R27[7:0] band13,band11 - R828_Freq_Info.XTAL_CAP20P=0x01; //R16[1:0] 10pF (01) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 1; - } - else if( LO_freq>=120000 && LO_freq<140000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x24; //R27[7:0] band13,band11 - R828_Freq_Info.XTAL_CAP20P=0x01; //R16[1:0] 10pF (01) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 1; - } - else if( LO_freq>=140000 && LO_freq<180000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x14; //R27[7:0] band14,band11 - R828_Freq_Info.XTAL_CAP20P=0x01; //R16[1:0] 10pF (01) - R828_Freq_Info.XTAL_CAP10P=0x01; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 1; - } - else if( LO_freq>=180000 && LO_freq<220000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x13; //R27[7:0] band14,band12 - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 1; - } - else if( LO_freq>=220000 && LO_freq<250000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x13; //R27[7:0] band14,band12 - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 2; - } - else if( LO_freq>=250000 && LO_freq<280000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x11; //R27[7:0] highest,highest - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 2; - } - else if( LO_freq>=280000 && LO_freq<310000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x02; //R26[7:6]=0 (LPF) R26[1:0]=2 (low) - R828_Freq_Info.TF_C=0x00; //R27[7:0] highest,highest - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 2; - } - else if( LO_freq>=310000 && LO_freq<450000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x41; //R26[7:6]=1 (bypass) R26[1:0]=1 (middle) - R828_Freq_Info.TF_C=0x00; //R27[7:0] highest,highest - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 2; - } - else if( LO_freq>=450000 && LO_freq<588000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x41; //R26[7:6]=1 (bypass) R26[1:0]=1 (middle) - R828_Freq_Info.TF_C=0x00; //R27[7:0] highest,highest - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 3; - } - else if( LO_freq>=588000 && LO_freq<650000) - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x40; //R26[7:6]=1 (bypass) R26[1:0]=0 (highest) - R828_Freq_Info.TF_C=0x00; //R27[7:0] highest,highest - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 3; - } - else - { - R828_Freq_Info.OPEN_D=0x00; // high - R828_Freq_Info.RF_MUX_PLOY = 0x40; //R26[7:6]=1 (bypass) R26[1:0]=0 (highest) - R828_Freq_Info.TF_C=0x00; //R27[7:0] highest,highest - R828_Freq_Info.XTAL_CAP20P=0x00; //R16[1:0] 0pF (00) - R828_Freq_Info.XTAL_CAP10P=0x00; - R828_Freq_Info.XTAL_CAP0P=0x00; - R828_Freq_Info.IMR_MEM = 4; - } - - return R828_Freq_Info; -} - -SysFreq_Info_Type R828_SysFreq_Sel(R828_Standard_Type R828_Standard,UINT32 RF_freq) -{ - SysFreq_Info_Type R828_SysFreq_Info; - - switch(R828_Standard) - { - - case DVB_T_6M: - case DVB_T_7M: - case DVB_T_7M_2: - case DVB_T_8M: - if( (RF_freq==506000) || (RF_freq==666000) || (RF_freq==818000) ) - { - R828_SysFreq_Info.MIXER_TOP=0x14; // MIXER TOP:14 , TOP-1, low-discharge - R828_SysFreq_Info.LNA_TOP=0xE5; // Detect BW 3, LNA TOP:4, PreDet Top:2 - R828_SysFreq_Info.CP_CUR=0x28; //101, 0.2 - R828_SysFreq_Info.DIV_BUF_CUR=0x20; // 10, 200u - } - else - { - R828_SysFreq_Info.MIXER_TOP=0x24; // MIXER TOP:13 , TOP-1, low-discharge - R828_SysFreq_Info.LNA_TOP=0xE5; // Detect BW 3, LNA TOP:4, PreDet Top:2 - R828_SysFreq_Info.CP_CUR=0x38; // 111, auto - R828_SysFreq_Info.DIV_BUF_CUR=0x30; // 11, 150u - } - R828_SysFreq_Info.LNA_VTH_L=0x53; // LNA VTH 0.84 , VTL 0.64 - R828_SysFreq_Info.MIXER_VTH_L=0x75; // MIXER VTH 1.04, VTL 0.84 - R828_SysFreq_Info.AIR_CABLE1_IN=0x00; - R828_SysFreq_Info.CABLE2_IN=0x00; - R828_SysFreq_Info.PRE_DECT=0x40; - R828_SysFreq_Info.LNA_DISCHARGE=14; - R828_SysFreq_Info.FILTER_CUR=0x40; // 10, low - break; - - - case DVB_T2_6M: - case DVB_T2_7M: - case DVB_T2_7M_2: - case DVB_T2_8M: - R828_SysFreq_Info.MIXER_TOP=0x24; // MIXER TOP:13 , TOP-1, low-discharge - R828_SysFreq_Info.LNA_TOP=0xE5; // Detect BW 3, LNA TOP:4, PreDet Top:2 - R828_SysFreq_Info.LNA_VTH_L=0x53; // LNA VTH 0.84 , VTL 0.64 - R828_SysFreq_Info.MIXER_VTH_L=0x75; // MIXER VTH 1.04, VTL 0.84 - R828_SysFreq_Info.AIR_CABLE1_IN=0x00; - R828_SysFreq_Info.CABLE2_IN=0x00; - R828_SysFreq_Info.PRE_DECT=0x40; - R828_SysFreq_Info.LNA_DISCHARGE=14; - R828_SysFreq_Info.CP_CUR=0x38; // 111, auto - R828_SysFreq_Info.DIV_BUF_CUR=0x30; // 11, 150u - R828_SysFreq_Info.FILTER_CUR=0x40; // 10, low - break; - - case ISDB_T: - R828_SysFreq_Info.MIXER_TOP=0x24; // MIXER TOP:13 , TOP-1, low-discharge - R828_SysFreq_Info.LNA_TOP=0xE5; // Detect BW 3, LNA TOP:4, PreDet Top:2 - R828_SysFreq_Info.LNA_VTH_L=0x75; // LNA VTH 1.04 , VTL 0.84 - R828_SysFreq_Info.MIXER_VTH_L=0x75; // MIXER VTH 1.04, VTL 0.84 - R828_SysFreq_Info.AIR_CABLE1_IN=0x00; - R828_SysFreq_Info.CABLE2_IN=0x00; - R828_SysFreq_Info.PRE_DECT=0x40; - R828_SysFreq_Info.LNA_DISCHARGE=14; - R828_SysFreq_Info.CP_CUR=0x38; // 111, auto - R828_SysFreq_Info.DIV_BUF_CUR=0x30; // 11, 150u - R828_SysFreq_Info.FILTER_CUR=0x40; // 10, low - break; - - default: //DVB-T 8M - R828_SysFreq_Info.MIXER_TOP=0x24; // MIXER TOP:13 , TOP-1, low-discharge - R828_SysFreq_Info.LNA_TOP=0xE5; // Detect BW 3, LNA TOP:4, PreDet Top:2 - R828_SysFreq_Info.LNA_VTH_L=0x53; // LNA VTH 0.84 , VTL 0.64 - R828_SysFreq_Info.MIXER_VTH_L=0x75; // MIXER VTH 1.04, VTL 0.84 - R828_SysFreq_Info.AIR_CABLE1_IN=0x00; - R828_SysFreq_Info.CABLE2_IN=0x00; - R828_SysFreq_Info.PRE_DECT=0x40; - R828_SysFreq_Info.LNA_DISCHARGE=14; - R828_SysFreq_Info.CP_CUR=0x38; // 111, auto - R828_SysFreq_Info.DIV_BUF_CUR=0x30; // 11, 150u - R828_SysFreq_Info.FILTER_CUR=0x40; // 10, low - break; - - } //end switch - -//DTV use Diplexer -#if(USE_DIPLEXER==TRUE) -if ((Rafael_Chip==R820C) || (Rafael_Chip==R820T) || (Rafael_Chip==R828S)) -{ - // Air-in (>=DIP_FREQ) & cable-1(= DIP_FREQ) - { - R828_SysFreq_Info.AIR_CABLE1_IN = 0x00; //air in, cable-1 off - R828_SysFreq_Info.CABLE2_IN = 0x00; //cable-2 off - } - else - { - R828_SysFreq_Info.AIR_CABLE1_IN = 0x60; //cable-1 in, air off - R828_SysFreq_Info.CABLE2_IN = 0x00; //cable-2 off - } -} -#endif - return R828_SysFreq_Info; - - } - -R828_ErrCode R828_Xtal_Check(void *pTuner) -{ - UINT8 ArrayNum; - - ArrayNum = 27; - for(ArrayNum=0;ArrayNum<27;ArrayNum++) - { - R828_Arry[ArrayNum] = R828_iniArry[ArrayNum]; - } - - //cap 30pF & Drive Low - R828_I2C.RegAddr = 0x10; - R828_Arry[11] = (R828_Arry[11] & 0xF4) | 0x0B ; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //set pll autotune = 128kHz - R828_I2C.RegAddr = 0x1A; - R828_Arry[21] = R828_Arry[21] & 0xF3; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //set manual initial reg = 111111; - R828_I2C.RegAddr = 0x13; - R828_Arry[14] = (R828_Arry[14] & 0x80) | 0x7F; - R828_I2C.Data = R828_Arry[14]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //set auto - R828_I2C.RegAddr = 0x13; - R828_Arry[14] = (R828_Arry[14] & 0xBF); - R828_I2C.Data = R828_Arry[14]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Delay_MS(pTuner, 5); - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 3; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - // if 30pF unlock, set to cap 20pF -#if (USE_16M_XTAL==TRUE) - //VCO=2360MHz for 16M Xtal. VCO band 26 - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) > 29) || ((R828_I2C_Len.Data[2] & 0x3F) < 23)) -#else - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) == 0x3F)) -#endif - { - //cap 20pF - R828_I2C.RegAddr = 0x10; - R828_Arry[11] = (R828_Arry[11] & 0xFC) | 0x02; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Delay_MS(pTuner, 5); - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 3; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - // if 20pF unlock, set to cap 10pF -#if (USE_16M_XTAL==TRUE) - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) > 29) || ((R828_I2C_Len.Data[2] & 0x3F) < 23)) -#else - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) == 0x3F)) -#endif - { - //cap 10pF - R828_I2C.RegAddr = 0x10; - R828_Arry[11] = (R828_Arry[11] & 0xFC) | 0x01; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Delay_MS(pTuner, 5); - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 3; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - // if 10pF unlock, set to cap 0pF -#if (USE_16M_XTAL==TRUE) - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) > 29) || ((R828_I2C_Len.Data[2] & 0x3F) < 23)) -#else - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) == 0x3F)) -#endif - { - //cap 0pF - R828_I2C.RegAddr = 0x10; - R828_Arry[11] = (R828_Arry[11] & 0xFC) | 0x00; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Delay_MS(pTuner, 5); - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 3; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - // if unlock, set to high drive -#if (USE_16M_XTAL==TRUE) - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) > 29) || ((R828_I2C_Len.Data[2] & 0x3F) < 23)) -#else - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) == 0x3F)) -#endif - { - //X'tal drive high - R828_I2C.RegAddr = 0x10; - R828_Arry[11] = (R828_Arry[11] & 0xF7) ; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //R828_Delay_MS(15); - R828_Delay_MS(pTuner, 20); - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 3; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - -#if (USE_16M_XTAL==TRUE) - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) > 29) || ((R828_I2C_Len.Data[2] & 0x3F) < 23)) -#else - if(((R828_I2C_Len.Data[2] & 0x40) == 0x00) || ((R828_I2C_Len.Data[2] & 0x3F) == 0x3F)) -#endif - { - return RT_Fail; - } - else //0p+high drive lock - { - Xtal_cap_sel_tmp = XTAL_HIGH_CAP_0P; - } - } - else //0p lock - { - Xtal_cap_sel_tmp = XTAL_LOW_CAP_0P; - } - } - else //10p lock - { - Xtal_cap_sel_tmp = XTAL_LOW_CAP_10P; - } - } - else //20p lock - { - Xtal_cap_sel_tmp = XTAL_LOW_CAP_20P; - } - } - else // 30p lock - { - Xtal_cap_sel_tmp = XTAL_LOW_CAP_30P; - } - - return RT_Success; -} -R828_ErrCode R828_Init(void *pTuner) -{ -// R820T_EXTRA_MODULE *pExtra; - UINT8 i; - - // Get tuner extra module. -// pExtra = &(pTuner->Extra.R820t); - - //write initial reg - //if(R828_InitReg(pTuner) != RT_Success) - // return RT_Fail; - - if(R828_IMR_done_flag==FALSE) - { - - //write initial reg -// if(R828_InitReg(pTuner) != RT_Success) -// return RT_Fail; - - //Do Xtal check - if((Rafael_Chip==R820T) || (Rafael_Chip==R828S) || (Rafael_Chip==R820C)) - { - Xtal_cap_sel = XTAL_HIGH_CAP_0P; - } - else - { - if(R828_Xtal_Check(pTuner) != RT_Success) //1st - return RT_Fail; - - Xtal_cap_sel = Xtal_cap_sel_tmp; - - if(R828_Xtal_Check(pTuner) != RT_Success) //2nd - return RT_Fail; - - if(Xtal_cap_sel_tmp > Xtal_cap_sel) - { - Xtal_cap_sel = Xtal_cap_sel_tmp; - } - - if(R828_Xtal_Check(pTuner) != RT_Success) //3rd - return RT_Fail; - - if(Xtal_cap_sel_tmp > Xtal_cap_sel) - { - Xtal_cap_sel = Xtal_cap_sel_tmp; - } - - } - - //reset filter cal. - for (i=0; i24000) - RingRef = R828_Xtal /2; - else - RingRef = R828_Xtal; - - for(n=0;n<16;n++) - { - if((16+n)* 8 * RingRef >= 3100000) - { - n_ring=n; - break; - } - - if(n==15) //n_ring not found - { - //return RT_Fail; - n_ring=n; - } - - } - - R828_Arry[19] &= 0xF0; //set ring[3:0] - R828_Arry[19] |= n_ring; - RingVCO = (16+n_ring)* 8 * RingRef; - R828_Arry[19]&=0xDF; //clear ring_se23 - R828_Arry[20]&=0xFC; //clear ring_seldiv - R828_Arry[26]&=0xFC; //clear ring_att - - switch(IMR_MEM) - { - case 0: - RingFreq = RingVCO/48; - R828_Arry[19]|=0x20; // ring_se23 = 1 - R828_Arry[20]|=0x03; // ring_seldiv = 3 - R828_Arry[26]|=0x02; // ring_att 10 - break; - case 1: - RingFreq = RingVCO/16; - R828_Arry[19]|=0x00; // ring_se23 = 0 - R828_Arry[20]|=0x02; // ring_seldiv = 2 - R828_Arry[26]|=0x00; // pw_ring 00 - break; - case 2: - RingFreq = RingVCO/8; - R828_Arry[19]|=0x00; // ring_se23 = 0 - R828_Arry[20]|=0x01; // ring_seldiv = 1 - R828_Arry[26]|=0x03; // pw_ring 11 - break; - case 3: - RingFreq = RingVCO/6; - R828_Arry[19]|=0x20; // ring_se23 = 1 - R828_Arry[20]|=0x00; // ring_seldiv = 0 - R828_Arry[26]|=0x03; // pw_ring 11 - break; - case 4: - RingFreq = RingVCO/4; - R828_Arry[19]|=0x00; // ring_se23 = 0 - R828_Arry[20]|=0x00; // ring_seldiv = 0 - R828_Arry[26]|=0x01; // pw_ring 01 - break; - default: - RingFreq = RingVCO/4; - R828_Arry[19]|=0x00; // ring_se23 = 0 - R828_Arry[20]|=0x00; // ring_seldiv = 0 - R828_Arry[26]|=0x01; // pw_ring 01 - break; - } - - - //write pw_ring,n_ring,ringdiv2 to I2C - - //------------n_ring,ring_se23----------// - R828_I2C.RegAddr = 0x18; - R828_I2C.Data = R828_Arry[19]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - //------------ring_sediv----------------// - R828_I2C.RegAddr = 0x19; - R828_I2C.Data = R828_Arry[20]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - //------------pw_ring-------------------// - R828_I2C.RegAddr = 0x1f; - R828_I2C.Data = R828_Arry[26]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Must do before PLL() - if(R828_MUX(pTuner, RingFreq - 5300) != RT_Success) //MUX input freq ~ RF_in Freq - return RT_Fail; - - if(R828_PLL(pTuner, (RingFreq - 5300) * 1000, STD_SIZE) != RT_Success) //set pll freq = ring freq - 6M - return RT_Fail; - - if(IM_Flag == TRUE) - { - if(R828_IQ(pTuner, &IMR_POINT) != RT_Success) - return RT_Fail; - } - else - { - IMR_POINT.Gain_X = IMR_Data[3].Gain_X; - IMR_POINT.Phase_Y = IMR_Data[3].Phase_Y; - IMR_POINT.Value = IMR_Data[3].Value; - if(R828_F_IMR(pTuner, &IMR_POINT) != RT_Success) - return RT_Fail; - } - - //Save IMR Value - switch(IMR_MEM) - { - case 0: - IMR_Data[0].Gain_X = IMR_POINT.Gain_X; - IMR_Data[0].Phase_Y = IMR_POINT.Phase_Y; - IMR_Data[0].Value = IMR_POINT.Value; - break; - case 1: - IMR_Data[1].Gain_X = IMR_POINT.Gain_X; - IMR_Data[1].Phase_Y = IMR_POINT.Phase_Y; - IMR_Data[1].Value = IMR_POINT.Value; - break; - case 2: - IMR_Data[2].Gain_X = IMR_POINT.Gain_X; - IMR_Data[2].Phase_Y = IMR_POINT.Phase_Y; - IMR_Data[2].Value = IMR_POINT.Value; - break; - case 3: - IMR_Data[3].Gain_X = IMR_POINT.Gain_X; - IMR_Data[3].Phase_Y = IMR_POINT.Phase_Y; - IMR_Data[3].Value = IMR_POINT.Value; - break; - case 4: - IMR_Data[4].Gain_X = IMR_POINT.Gain_X; - IMR_Data[4].Phase_Y = IMR_POINT.Phase_Y; - IMR_Data[4].Value = IMR_POINT.Value; - break; - default: - IMR_Data[4].Gain_X = IMR_POINT.Gain_X; - IMR_Data[4].Phase_Y = IMR_POINT.Phase_Y; - IMR_Data[4].Value = IMR_POINT.Value; - break; - } - return RT_Success; -} - -R828_ErrCode R828_PLL(void *pTuner, UINT32 LO_Freq, R828_Standard_Type R828_Standard) -{ - -// R820T_EXTRA_MODULE *pExtra; - - UINT8 MixDiv; - UINT8 DivBuf; - UINT8 Ni; - UINT8 Si; - UINT8 DivNum; - UINT8 Nint; - UINT32 VCO_Min_kHz; - UINT32 VCO_Max_kHz; - uint64_t VCO_Freq; - UINT32 PLL_Ref; //Max 24000 (kHz) - UINT32 VCO_Fra; //VCO contribution by SDM (kHz) - UINT16 Nsdm; - UINT16 SDM; - UINT16 SDM16to9; - UINT16 SDM8to1; - //UINT8 Judge = 0; - UINT8 VCO_fine_tune; - - MixDiv = 2; - DivBuf = 0; - Ni = 0; - Si = 0; - DivNum = 0; - Nint = 0; - VCO_Min_kHz = 1770000; - VCO_Max_kHz = VCO_Min_kHz*2; - VCO_Freq = 0; - PLL_Ref = 0; //Max 24000 (kHz) - VCO_Fra = 0; //VCO contribution by SDM (kHz) - Nsdm = 2; - SDM = 0; - SDM16to9 = 0; - SDM8to1 = 0; - //UINT8 Judge = 0; - VCO_fine_tune = 0; - -#if 0 - if ((Rafael_Chip==R620D) || (Rafael_Chip==R828D) || (Rafael_Chip==R828)) //X'tal can't not exceed 20MHz for ATV - { - if(R828_Standard <= SECAM_L1) //ref set refdiv2, reffreq = Xtal/2 on ATV application - { - R828_Arry[11] |= 0x10; //b4=1 - PLL_Ref = R828_Xtal /2; - } - else //DTV, FilCal, IMR - { - R828_Arry[11] &= 0xEF; - PLL_Ref = R828_Xtal; - } - } - else - { - if(R828_Xtal > 24000) - { - R828_Arry[11] |= 0x10; //b4=1 - PLL_Ref = R828_Xtal /2; - } - else - { - R828_Arry[11] &= 0xEF; - PLL_Ref = R828_Xtal; - } - } -#endif - //FIXME hack - R828_Arry[11] &= 0xEF; - PLL_Ref = rtlsdr_get_tuner_clock(pTuner); - - R828_I2C.RegAddr = 0x10; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //set pll autotune = 128kHz - R828_I2C.RegAddr = 0x1A; - R828_Arry[21] = R828_Arry[21] & 0xF3; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Set VCO current = 100 - R828_I2C.RegAddr = 0x12; - R828_Arry[13] = (R828_Arry[13] & 0x1F) | 0x80; - R828_I2C.Data = R828_Arry[13]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Divider - while(MixDiv <= 64) - { - if((((LO_Freq/1000) * MixDiv) >= VCO_Min_kHz) && (((LO_Freq/1000) * MixDiv) < VCO_Max_kHz)) - { - DivBuf = MixDiv; - while(DivBuf > 2) - { - DivBuf = DivBuf >> 1; - DivNum ++; - } - break; - } - MixDiv = MixDiv << 1; - } - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 5; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - VCO_fine_tune = (R828_I2C_Len.Data[4] & 0x30)>>4; - - if(VCO_fine_tune > VCO_pwr_ref) - DivNum = DivNum - 1; - else if(VCO_fine_tune < VCO_pwr_ref) - DivNum = DivNum + 1; - - R828_I2C.RegAddr = 0x10; - R828_Arry[11] &= 0x1F; - R828_Arry[11] |= (DivNum << 5); - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - VCO_Freq = (uint64_t)(LO_Freq * (uint64_t)MixDiv); - Nint = (UINT8) (VCO_Freq / 2 / PLL_Ref); - VCO_Fra = (UINT16) ((VCO_Freq - 2 * PLL_Ref * Nint) / 1000); - - //FIXME hack - PLL_Ref /= 1000; - -// printf("VCO_Freq = %lu, Nint= %u, VCO_Fra= %lu, LO_Freq= %u, MixDiv= %u\n", VCO_Freq, Nint, VCO_Fra, LO_Freq, MixDiv); - - //boundary spur prevention - if (VCO_Fra < PLL_Ref/64) //2*PLL_Ref/128 - VCO_Fra = 0; - else if (VCO_Fra > PLL_Ref*127/64) //2*PLL_Ref*127/128 - { - VCO_Fra = 0; - Nint ++; - } - else if((VCO_Fra > PLL_Ref*127/128) && (VCO_Fra < PLL_Ref)) //> 2*PLL_Ref*127/256, < 2*PLL_Ref*128/256 - VCO_Fra = PLL_Ref*127/128; // VCO_Fra = 2*PLL_Ref*127/256 - else if((VCO_Fra > PLL_Ref) && (VCO_Fra < PLL_Ref*129/128)) //> 2*PLL_Ref*128/256, < 2*PLL_Ref*129/256 - VCO_Fra = PLL_Ref*129/128; // VCO_Fra = 2*PLL_Ref*129/256 - else - VCO_Fra = VCO_Fra; - - if (Nint > 63) { - fprintf(stderr, "[R820T] No valid PLL values for %u Hz!\n", LO_Freq); - return RT_Fail; - } - - //N & S - Ni = (Nint - 13) / 4; - Si = Nint - 4 *Ni - 13; - R828_I2C.RegAddr = 0x14; - R828_Arry[15] = 0x00; - R828_Arry[15] |= (Ni + (Si << 6)); - R828_I2C.Data = R828_Arry[15]; - - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //pw_sdm - R828_I2C.RegAddr = 0x12; - R828_Arry[13] &= 0xF7; - if(VCO_Fra == 0) - R828_Arry[13] |= 0x08; - R828_I2C.Data = R828_Arry[13]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //SDM calculator - while(VCO_Fra > 1) - { - if (VCO_Fra > (2*PLL_Ref / Nsdm)) - { - SDM = SDM + 32768 / (Nsdm/2); - VCO_Fra = VCO_Fra - 2*PLL_Ref / Nsdm; - if (Nsdm >= 0x8000) - break; - } - Nsdm = Nsdm << 1; - } - - SDM16to9 = SDM >> 8; - SDM8to1 = SDM - (SDM16to9 << 8); - - R828_I2C.RegAddr = 0x16; - R828_Arry[17] = (UINT8) SDM16to9; - R828_I2C.Data = R828_Arry[17]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - R828_I2C.RegAddr = 0x15; - R828_Arry[16] = (UINT8) SDM8to1; - R828_I2C.Data = R828_Arry[16]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - -// R828_Delay_MS(10); - - if ((Rafael_Chip==R620D) || (Rafael_Chip==R828D) || (Rafael_Chip==R828)) - { - if(R828_Standard <= SECAM_L1) - R828_Delay_MS(pTuner, 20); - else - R828_Delay_MS(pTuner, 10); - } - else - { - R828_Delay_MS(pTuner, 10); - } - - //check PLL lock status - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 3; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - if( (R828_I2C_Len.Data[2] & 0x40) == 0x00 ) - { - fprintf(stderr, "[R820T] PLL not locked for %u Hz!\n", LO_Freq); - R828_I2C.RegAddr = 0x12; - R828_Arry[13] = (R828_Arry[13] & 0x1F) | 0x60; //increase VCO current - R828_I2C.Data = R828_Arry[13]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Fail; - } - - //set pll autotune = 8kHz - R828_I2C.RegAddr = 0x1A; - R828_Arry[21] = R828_Arry[21] | 0x08; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Success; -} - -R828_ErrCode R828_MUX(void *pTuner, UINT32 RF_KHz) -{ - UINT8 RT_Reg08; - UINT8 RT_Reg09; - - RT_Reg08 = 0; - RT_Reg09 = 0; - - //Freq_Info_Type Freq_Info1; - Freq_Info1 = R828_Freq_Sel(RF_KHz); - - // Open Drain - R828_I2C.RegAddr = 0x17; - R828_Arry[18] = (R828_Arry[18] & 0xF7) | Freq_Info1.OPEN_D; - R828_I2C.Data = R828_Arry[18]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // RF_MUX,Polymux - R828_I2C.RegAddr = 0x1A; - R828_Arry[21] = (R828_Arry[21] & 0x3C) | Freq_Info1.RF_MUX_PLOY; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // TF BAND - R828_I2C.RegAddr = 0x1B; - R828_Arry[22] &= 0x00; - R828_Arry[22] |= Freq_Info1.TF_C; - R828_I2C.Data = R828_Arry[22]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // XTAL CAP & Drive - R828_I2C.RegAddr = 0x10; - R828_Arry[11] &= 0xF4; - switch(Xtal_cap_sel) - { - case XTAL_LOW_CAP_30P: - case XTAL_LOW_CAP_20P: - R828_Arry[11] = R828_Arry[11] | Freq_Info1.XTAL_CAP20P | 0x08; - break; - - case XTAL_LOW_CAP_10P: - R828_Arry[11] = R828_Arry[11] | Freq_Info1.XTAL_CAP10P | 0x08; - break; - - case XTAL_LOW_CAP_0P: - R828_Arry[11] = R828_Arry[11] | Freq_Info1.XTAL_CAP0P | 0x08; - break; - - case XTAL_HIGH_CAP_0P: - R828_Arry[11] = R828_Arry[11] | Freq_Info1.XTAL_CAP0P | 0x00; - break; - - default: - R828_Arry[11] = R828_Arry[11] | Freq_Info1.XTAL_CAP0P | 0x08; - break; - } - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Set_IMR - if(R828_IMR_done_flag == TRUE) - { - RT_Reg08 = IMR_Data[Freq_Info1.IMR_MEM].Gain_X & 0x3F; - RT_Reg09 = IMR_Data[Freq_Info1.IMR_MEM].Phase_Y & 0x3F; - } - else - { - RT_Reg08 = 0; - RT_Reg09 = 0; - } - - R828_I2C.RegAddr = 0x08; - R828_Arry[3] = R828_iniArry[3] & 0xC0; - R828_Arry[3] = R828_Arry[3] | RT_Reg08; - R828_I2C.Data = R828_Arry[3]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x09; - R828_Arry[4] = R828_iniArry[4] & 0xC0; - R828_Arry[4] = R828_Arry[4] | RT_Reg09; - R828_I2C.Data =R828_Arry[4] ; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Success; -} - -R828_ErrCode R828_IQ(void *pTuner, R828_SectType* IQ_Pont) -{ - R828_SectType Compare_IQ[3]; -// R828_SectType CompareTemp; -// UINT8 IQ_Count = 0; - UINT8 VGA_Count; - UINT16 VGA_Read; - UINT8 X_Direction; // 1:X, 0:Y - - VGA_Count = 0; - VGA_Read = 0; - - // increase VGA power to let image significant - for(VGA_Count = 12;VGA_Count < 16;VGA_Count ++) - { - R828_I2C.RegAddr = 0x0C; - R828_I2C.Data = (R828_Arry[7] & 0xF0) + VGA_Count; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Delay_MS(pTuner, 10); // - - if(R828_Muti_Read(pTuner, 0x01, &VGA_Read) != RT_Success) - return RT_Fail; - - if(VGA_Read > 40*4) - break; - } - - //initial 0x08, 0x09 - //Compare_IQ[0].Gain_X = 0x40; //should be 0xC0 in R828, Jason - //Compare_IQ[0].Phase_Y = 0x40; //should be 0x40 in R828 - Compare_IQ[0].Gain_X = R828_iniArry[3] & 0xC0; // Jason modified, clear b[5], b[4:0] - Compare_IQ[0].Phase_Y = R828_iniArry[4] & 0xC0; // - - //while(IQ_Count < 3) - //{ - // Determine X or Y - if(R828_IMR_Cross(pTuner, &Compare_IQ[0], &X_Direction) != RT_Success) - return RT_Fail; - - //if(X_Direction==1) - //{ - // if(R828_IQ_Tree(Compare_IQ[0].Phase_Y, Compare_IQ[0].Gain_X, 0x09, &Compare_IQ[0]) != RT_Success) //X - // return RT_Fail; - //} - //else - //{ - // if(R828_IQ_Tree(Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) //Y - // return RT_Fail; - //} - - /* - //--- X direction ---// - //X: 3 points - if(R828_IQ_Tree(Compare_IQ[0].Phase_Y, Compare_IQ[0].Gain_X, 0x09, &Compare_IQ[0]) != RT_Success) // - return RT_Fail; - - //compare and find min of 3 points. determine I/Q direction - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - //increase step to find min value of this direction - if(R828_CompreStep(&Compare_IQ[0], 0x08) != RT_Success) - return RT_Fail; - */ - - if(X_Direction==1) - { - //compare and find min of 3 points. determine I/Q direction - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - //increase step to find min value of this direction - if(R828_CompreStep(pTuner, &Compare_IQ[0], 0x08) != RT_Success) //X - return RT_Fail; - } - else - { - //compare and find min of 3 points. determine I/Q direction - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - //increase step to find min value of this direction - if(R828_CompreStep(pTuner, &Compare_IQ[0], 0x09) != RT_Success) //Y - return RT_Fail; - } - /* - //--- Y direction ---// - //Y: 3 points - if(R828_IQ_Tree(Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) // - return RT_Fail; - - //compare and find min of 3 points. determine I/Q direction - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - //increase step to find min value of this direction - if(R828_CompreStep(&Compare_IQ[0], 0x09) != RT_Success) - return RT_Fail; - */ - - //Another direction - if(X_Direction==1) - { - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) //Y - return RT_Fail; - - //compare and find min of 3 points. determine I/Q direction - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - //increase step to find min value of this direction - if(R828_CompreStep(pTuner, &Compare_IQ[0], 0x09) != RT_Success) //Y - return RT_Fail; - } - else - { - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Phase_Y, Compare_IQ[0].Gain_X, 0x09, &Compare_IQ[0]) != RT_Success) //X - return RT_Fail; - - //compare and find min of 3 points. determine I/Q direction - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - //increase step to find min value of this direction - if(R828_CompreStep(pTuner, &Compare_IQ[0], 0x08) != RT_Success) //X - return RT_Fail; - } - //CompareTemp = Compare_IQ[0]; - - //--- Check 3 points again---// - if(X_Direction==1) - { - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Phase_Y, Compare_IQ[0].Gain_X, 0x09, &Compare_IQ[0]) != RT_Success) //X - return RT_Fail; - } - else - { - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) //Y - return RT_Fail; - } - - //if(R828_IQ_Tree(Compare_IQ[0].Phase_Y, Compare_IQ[0].Gain_X, 0x09, &Compare_IQ[0]) != RT_Success) // - // return RT_Fail; - - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - //if((CompareTemp.Gain_X == Compare_IQ[0].Gain_X) && (CompareTemp.Phase_Y == Compare_IQ[0].Phase_Y))//Ben Check - // break; - - //IQ_Count ++; - //} - //if(IQ_Count == 3) - // return RT_Fail; - - //Section-4 Check - /* - CompareTemp = Compare_IQ[0]; - for(IQ_Count = 0;IQ_Count < 5;IQ_Count ++) - { - if(R828_Section(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - if((CompareTemp.Gain_X == Compare_IQ[0].Gain_X) && (CompareTemp.Phase_Y == Compare_IQ[0].Phase_Y)) - break; - } - */ - - //Section-9 check - //if(R828_F_IMR(&Compare_IQ[0]) != RT_Success) - if(R828_Section(pTuner, &Compare_IQ[0]) != RT_Success) - return RT_Fail; - - *IQ_Pont = Compare_IQ[0]; - - //reset gain/phase control setting - R828_I2C.RegAddr = 0x08; - R828_I2C.Data = R828_iniArry[3] & 0xC0; //Jason - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x09; - R828_I2C.Data = R828_iniArry[4] & 0xC0; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Success; -} - -//-------------------------------------------------------------------------------------------- -// Purpose: record IMC results by input gain/phase location -// then adjust gain or phase positive 1 step and negtive 1 step, both record results -// input: FixPot: phase or gain -// FlucPot phase or gain -// PotReg: 0x08 or 0x09 -// CompareTree: 3 IMR trace and results -// output: TREU or FALSE -//-------------------------------------------------------------------------------------------- -R828_ErrCode R828_IQ_Tree(void *pTuner, UINT8 FixPot, UINT8 FlucPot, UINT8 PotReg, R828_SectType* CompareTree) -{ - UINT8 TreeCount; - UINT8 TreeTimes; - UINT8 TempPot; - UINT8 PntReg; - - TreeCount = 0; - TreeTimes = 3; - TempPot = 0; - PntReg = 0; - - if(PotReg == 0x08) - PntReg = 0x09; //phase control - else - PntReg = 0x08; //gain control - - for(TreeCount = 0;TreeCount < TreeTimes;TreeCount ++) - { - R828_I2C.RegAddr = PotReg; - R828_I2C.Data = FixPot; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = PntReg; - R828_I2C.Data = FlucPot; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - if(R828_Muti_Read(pTuner, 0x01, &CompareTree[TreeCount].Value) != RT_Success) - return RT_Fail; - - if(PotReg == 0x08) - { - CompareTree[TreeCount].Gain_X = FixPot; - CompareTree[TreeCount].Phase_Y = FlucPot; - } - else - { - CompareTree[TreeCount].Phase_Y = FixPot; - CompareTree[TreeCount].Gain_X = FlucPot; - } - - if(TreeCount == 0) //try right-side point - FlucPot ++; - else if(TreeCount == 1) //try left-side point - { - if((FlucPot & 0x1F) < 0x02) //if absolute location is 1, change I/Q direction - { - TempPot = 2 - (FlucPot & 0x1F); - if(FlucPot & 0x20) //b[5]:I/Q selection. 0:Q-path, 1:I-path - { - FlucPot &= 0xC0; - FlucPot |= TempPot; - } - else - { - FlucPot |= (0x20 | TempPot); - } - } - else - FlucPot -= 2; - } - } - - return RT_Success; -} - -//-----------------------------------------------------------------------------------/ -// Purpose: compare IMC result aray [0][1][2], find min value and store to CorArry[0] -// input: CorArry: three IMR data array -// output: TRUE or FALSE -//-----------------------------------------------------------------------------------/ -R828_ErrCode R828_CompreCor(R828_SectType* CorArry) -{ - UINT8 CompCount; - R828_SectType CorTemp; - - CompCount = 0; - - for(CompCount = 3;CompCount > 0;CompCount --) - { - if(CorArry[0].Value > CorArry[CompCount - 1].Value) //compare IMC result [0][1][2], find min value - { - CorTemp = CorArry[0]; - CorArry[0] = CorArry[CompCount - 1]; - CorArry[CompCount - 1] = CorTemp; - } - } - - return RT_Success; -} - -//-------------------------------------------------------------------------------------// -// Purpose: if (Gain<9 or Phase<9), Gain+1 or Phase+1 and compare with min value -// new < min => update to min and continue -// new > min => Exit -// input: StepArry: three IMR data array -// Pace: gain or phase register -// output: TRUE or FALSE -//-------------------------------------------------------------------------------------// -R828_ErrCode R828_CompreStep(void *pTuner, R828_SectType* StepArry, UINT8 Pace) -{ - //UINT8 StepCount = 0; - R828_SectType StepTemp; - - //min value already saved in StepArry[0] - StepTemp.Phase_Y = StepArry[0].Phase_Y; - StepTemp.Gain_X = StepArry[0].Gain_X; - - while(((StepTemp.Gain_X & 0x1F) < IMR_TRIAL) && ((StepTemp.Phase_Y & 0x1F) < IMR_TRIAL)) //5->10 - { - if(Pace == 0x08) - StepTemp.Gain_X ++; - else - StepTemp.Phase_Y ++; - - R828_I2C.RegAddr = 0x08; - R828_I2C.Data = StepTemp.Gain_X ; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x09; - R828_I2C.Data = StepTemp.Phase_Y; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - if(R828_Muti_Read(pTuner, 0x01, &StepTemp.Value) != RT_Success) - return RT_Fail; - - if(StepTemp.Value <= StepArry[0].Value) - { - StepArry[0].Gain_X = StepTemp.Gain_X; - StepArry[0].Phase_Y = StepTemp.Phase_Y; - StepArry[0].Value = StepTemp.Value; - } - else - { - break; - } - - } //end of while() - - return RT_Success; -} - -//-----------------------------------------------------------------------------------/ -// Purpose: read multiple IMC results for stability -// input: IMR_Reg: IMC result address -// IMR_Result_Data: result -// output: TRUE or FALSE -//-----------------------------------------------------------------------------------/ -R828_ErrCode R828_Muti_Read(void *pTuner, UINT8 IMR_Reg, UINT16* IMR_Result_Data) //jason modified -{ - UINT8 ReadCount; - UINT16 ReadAmount; - UINT8 ReadMax; - UINT8 ReadMin; - UINT8 ReadData; - - ReadCount = 0; - ReadAmount = 0; - ReadMax = 0; - ReadMin = 255; - ReadData = 0; - - R828_Delay_MS(pTuner, 5); - - for(ReadCount = 0;ReadCount < 6;ReadCount ++) - { - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = IMR_Reg + 1; //IMR_Reg = 0x01 - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - ReadData = R828_I2C_Len.Data[1]; - - ReadAmount = ReadAmount + (UINT16)ReadData; - - if(ReadData < ReadMin) - ReadMin = ReadData; - - if(ReadData > ReadMax) - ReadMax = ReadData; - } - *IMR_Result_Data = ReadAmount - (UINT16)ReadMax - (UINT16)ReadMin; - - return RT_Success; -} - -R828_ErrCode R828_Section(void *pTuner, R828_SectType* IQ_Pont) -{ - R828_SectType Compare_IQ[3]; - R828_SectType Compare_Bet[3]; - - //Try X-1 column and save min result to Compare_Bet[0] - if((IQ_Pont->Gain_X & 0x1F) == 0x00) - { - /* - if((IQ_Pont->Gain_X & 0xE0) == 0x40) //bug => only compare b[5], - Compare_IQ[0].Gain_X = 0x61; // Gain=1, I-path //Jason - else - Compare_IQ[0].Gain_X = 0x41; // Gain=1, Q-path - */ - Compare_IQ[0].Gain_X = ((IQ_Pont->Gain_X) & 0xDF) + 1; //Q-path, Gain=1 - } - else - Compare_IQ[0].Gain_X = IQ_Pont->Gain_X - 1; //left point - Compare_IQ[0].Phase_Y = IQ_Pont->Phase_Y; - - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) // y-direction - return RT_Fail; - - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - Compare_Bet[0].Gain_X = Compare_IQ[0].Gain_X; - Compare_Bet[0].Phase_Y = Compare_IQ[0].Phase_Y; - Compare_Bet[0].Value = Compare_IQ[0].Value; - - //Try X column and save min result to Compare_Bet[1] - Compare_IQ[0].Gain_X = IQ_Pont->Gain_X; - Compare_IQ[0].Phase_Y = IQ_Pont->Phase_Y; - - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) - return RT_Fail; - - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - Compare_Bet[1].Gain_X = Compare_IQ[0].Gain_X; - Compare_Bet[1].Phase_Y = Compare_IQ[0].Phase_Y; - Compare_Bet[1].Value = Compare_IQ[0].Value; - - //Try X+1 column and save min result to Compare_Bet[2] - if((IQ_Pont->Gain_X & 0x1F) == 0x00) - Compare_IQ[0].Gain_X = ((IQ_Pont->Gain_X) | 0x20) + 1; //I-path, Gain=1 - else - Compare_IQ[0].Gain_X = IQ_Pont->Gain_X + 1; - Compare_IQ[0].Phase_Y = IQ_Pont->Phase_Y; - - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) - return RT_Fail; - - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - Compare_Bet[2].Gain_X = Compare_IQ[0].Gain_X; - Compare_Bet[2].Phase_Y = Compare_IQ[0].Phase_Y; - Compare_Bet[2].Value = Compare_IQ[0].Value; - - if(R828_CompreCor(&Compare_Bet[0]) != RT_Success) - return RT_Fail; - - *IQ_Pont = Compare_Bet[0]; - - return RT_Success; -} - -R828_ErrCode R828_IMR_Cross(void *pTuner, R828_SectType* IQ_Pont, UINT8* X_Direct) -{ - - R828_SectType Compare_Cross[5]; //(0,0)(0,Q-1)(0,I-1)(Q-1,0)(I-1,0) - R828_SectType Compare_Temp; - UINT8 CrossCount; - UINT8 Reg08; - UINT8 Reg09; - - CrossCount = 0; - Reg08 = R828_iniArry[3] & 0xC0; - Reg09 = R828_iniArry[4] & 0xC0; - - //memset(&Compare_Temp,0, sizeof(R828_SectType)); - Compare_Temp.Gain_X = 0; - Compare_Temp.Phase_Y = 0; - Compare_Temp.Value = 0; - - Compare_Temp.Value = 255; - - for(CrossCount=0; CrossCount<5; CrossCount++) - { - - if(CrossCount==0) - { - Compare_Cross[CrossCount].Gain_X = Reg08; - Compare_Cross[CrossCount].Phase_Y = Reg09; - } - else if(CrossCount==1) - { - Compare_Cross[CrossCount].Gain_X = Reg08; //0 - Compare_Cross[CrossCount].Phase_Y = Reg09 + 1; //Q-1 - } - else if(CrossCount==2) - { - Compare_Cross[CrossCount].Gain_X = Reg08; //0 - Compare_Cross[CrossCount].Phase_Y = (Reg09 | 0x20) + 1; //I-1 - } - else if(CrossCount==3) - { - Compare_Cross[CrossCount].Gain_X = Reg08 + 1; //Q-1 - Compare_Cross[CrossCount].Phase_Y = Reg09; - } - else - { - Compare_Cross[CrossCount].Gain_X = (Reg08 | 0x20) + 1; //I-1 - Compare_Cross[CrossCount].Phase_Y = Reg09; - } - - R828_I2C.RegAddr = 0x08; - R828_I2C.Data = Compare_Cross[CrossCount].Gain_X; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x09; - R828_I2C.Data = Compare_Cross[CrossCount].Phase_Y; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - if(R828_Muti_Read(pTuner, 0x01, &Compare_Cross[CrossCount].Value) != RT_Success) - return RT_Fail; - - if( Compare_Cross[CrossCount].Value < Compare_Temp.Value) - { - Compare_Temp.Value = Compare_Cross[CrossCount].Value; - Compare_Temp.Gain_X = Compare_Cross[CrossCount].Gain_X; - Compare_Temp.Phase_Y = Compare_Cross[CrossCount].Phase_Y; - } - } //end for loop - - - if((Compare_Temp.Phase_Y & 0x1F)==1) //y-direction - { - *X_Direct = (UINT8) 0; - IQ_Pont[0].Gain_X = Compare_Cross[0].Gain_X; - IQ_Pont[0].Phase_Y = Compare_Cross[0].Phase_Y; - IQ_Pont[0].Value = Compare_Cross[0].Value; - - IQ_Pont[1].Gain_X = Compare_Cross[1].Gain_X; - IQ_Pont[1].Phase_Y = Compare_Cross[1].Phase_Y; - IQ_Pont[1].Value = Compare_Cross[1].Value; - - IQ_Pont[2].Gain_X = Compare_Cross[2].Gain_X; - IQ_Pont[2].Phase_Y = Compare_Cross[2].Phase_Y; - IQ_Pont[2].Value = Compare_Cross[2].Value; - } - else //(0,0) or x-direction - { - *X_Direct = (UINT8) 1; - IQ_Pont[0].Gain_X = Compare_Cross[0].Gain_X; - IQ_Pont[0].Phase_Y = Compare_Cross[0].Phase_Y; - IQ_Pont[0].Value = Compare_Cross[0].Value; - - IQ_Pont[1].Gain_X = Compare_Cross[3].Gain_X; - IQ_Pont[1].Phase_Y = Compare_Cross[3].Phase_Y; - IQ_Pont[1].Value = Compare_Cross[3].Value; - - IQ_Pont[2].Gain_X = Compare_Cross[4].Gain_X; - IQ_Pont[2].Phase_Y = Compare_Cross[4].Phase_Y; - IQ_Pont[2].Value = Compare_Cross[4].Value; - } - return RT_Success; -} - -//----------------------------------------------------------------------------------------// -// purpose: search surrounding points from previous point -// try (x-1), (x), (x+1) columns, and find min IMR result point -// input: IQ_Pont: previous point data(IMR Gain, Phase, ADC Result, RefRreq) -// will be updated to final best point -// output: TRUE or FALSE -//----------------------------------------------------------------------------------------// -R828_ErrCode R828_F_IMR(void *pTuner, R828_SectType* IQ_Pont) -{ - R828_SectType Compare_IQ[3]; - R828_SectType Compare_Bet[3]; - UINT8 VGA_Count; - UINT16 VGA_Read; - - VGA_Count = 0; - VGA_Read = 0; - - //VGA - for(VGA_Count = 12;VGA_Count < 16;VGA_Count ++) - { - R828_I2C.RegAddr = 0x0C; - R828_I2C.Data = (R828_Arry[7] & 0xF0) + VGA_Count; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Delay_MS(pTuner, 10); - - if(R828_Muti_Read(pTuner, 0x01, &VGA_Read) != RT_Success) - return RT_Fail; - - if(VGA_Read > 40*4) - break; - } - - //Try X-1 column and save min result to Compare_Bet[0] - if((IQ_Pont->Gain_X & 0x1F) == 0x00) - { - Compare_IQ[0].Gain_X = ((IQ_Pont->Gain_X) & 0xDF) + 1; //Q-path, Gain=1 - } - else - Compare_IQ[0].Gain_X = IQ_Pont->Gain_X - 1; //left point - Compare_IQ[0].Phase_Y = IQ_Pont->Phase_Y; - - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) // y-direction - return RT_Fail; - - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - Compare_Bet[0].Gain_X = Compare_IQ[0].Gain_X; - Compare_Bet[0].Phase_Y = Compare_IQ[0].Phase_Y; - Compare_Bet[0].Value = Compare_IQ[0].Value; - - //Try X column and save min result to Compare_Bet[1] - Compare_IQ[0].Gain_X = IQ_Pont->Gain_X; - Compare_IQ[0].Phase_Y = IQ_Pont->Phase_Y; - - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) - return RT_Fail; - - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - Compare_Bet[1].Gain_X = Compare_IQ[0].Gain_X; - Compare_Bet[1].Phase_Y = Compare_IQ[0].Phase_Y; - Compare_Bet[1].Value = Compare_IQ[0].Value; - - //Try X+1 column and save min result to Compare_Bet[2] - if((IQ_Pont->Gain_X & 0x1F) == 0x00) - Compare_IQ[0].Gain_X = ((IQ_Pont->Gain_X) | 0x20) + 1; //I-path, Gain=1 - else - Compare_IQ[0].Gain_X = IQ_Pont->Gain_X + 1; - Compare_IQ[0].Phase_Y = IQ_Pont->Phase_Y; - - if(R828_IQ_Tree(pTuner, Compare_IQ[0].Gain_X, Compare_IQ[0].Phase_Y, 0x08, &Compare_IQ[0]) != RT_Success) - return RT_Fail; - - if(R828_CompreCor(&Compare_IQ[0]) != RT_Success) - return RT_Fail; - - Compare_Bet[2].Gain_X = Compare_IQ[0].Gain_X; - Compare_Bet[2].Phase_Y = Compare_IQ[0].Phase_Y; - Compare_Bet[2].Value = Compare_IQ[0].Value; - - if(R828_CompreCor(&Compare_Bet[0]) != RT_Success) - return RT_Fail; - - *IQ_Pont = Compare_Bet[0]; - - return RT_Success; -} - -R828_ErrCode R828_GPIO(void *pTuner, R828_GPIO_Type R828_GPIO_Conrl) -{ - if(R828_GPIO_Conrl == HI_SIG) - R828_Arry[10] |= 0x01; - else - R828_Arry[10] &= 0xFE; - - R828_I2C.RegAddr = 0x0F; - R828_I2C.Data = R828_Arry[10]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Success; -} - -R828_ErrCode R828_SetStandard(void *pTuner, R828_Standard_Type RT_Standard) -{ - - // Used Normal Arry to Modify - UINT8 ArrayNum; - - ArrayNum = 27; - for(ArrayNum=0;ArrayNum<27;ArrayNum++) - { - R828_Arry[ArrayNum] = R828_iniArry[ArrayNum]; - } - - - // Record Init Flag & Xtal_check Result - if(R828_IMR_done_flag == TRUE) - R828_Arry[7] = (R828_Arry[7] & 0xF0) | 0x01 | (Xtal_cap_sel<<1); - else - R828_Arry[7] = (R828_Arry[7] & 0xF0) | 0x00; - - R828_I2C.RegAddr = 0x0C; - R828_I2C.Data = R828_Arry[7]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // Record version - R828_I2C.RegAddr = 0x13; - R828_Arry[14] = (R828_Arry[14] & 0xC0) | VER_NUM; - R828_I2C.Data = R828_Arry[14]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - //for LT Gain test - if(RT_Standard > SECAM_L1) - { - R828_I2C.RegAddr = 0x1D; //[5:3] LNA TOP - R828_I2C.Data = (R828_Arry[24] & 0xC7) | 0x00; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //R828_Delay_MS(1); - } - - // Look Up System Dependent Table - Sys_Info1 = R828_Sys_Sel(RT_Standard); - R828_IF_khz = Sys_Info1.IF_KHz; - R828_CAL_LO_khz = Sys_Info1.FILT_CAL_LO; - - // Filter Calibration - if(R828_Fil_Cal_flag[RT_Standard] == FALSE) - { - // do filter calibration - if(R828_Filt_Cal(pTuner, Sys_Info1.FILT_CAL_LO,Sys_Info1.BW) != RT_Success) - return RT_Fail; - - - // read and set filter code - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 5; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - R828_Fil_Cal_code[RT_Standard] = R828_I2C_Len.Data[4] & 0x0F; - - //Filter Cali. Protection - if(R828_Fil_Cal_code[RT_Standard]==0 || R828_Fil_Cal_code[RT_Standard]==15) - { - if(R828_Filt_Cal(pTuner, Sys_Info1.FILT_CAL_LO,Sys_Info1.BW) != RT_Success) - return RT_Fail; - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 5; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - R828_Fil_Cal_code[RT_Standard] = R828_I2C_Len.Data[4] & 0x0F; - - if(R828_Fil_Cal_code[RT_Standard]==15) //narrowest - R828_Fil_Cal_code[RT_Standard] = 0; - - } - R828_Fil_Cal_flag[RT_Standard] = TRUE; - } - - // Set Filter Q - R828_Arry[5] = (R828_Arry[5] & 0xE0) | Sys_Info1.FILT_Q | R828_Fil_Cal_code[RT_Standard]; - R828_I2C.RegAddr = 0x0A; - R828_I2C.Data = R828_Arry[5]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // Set BW, Filter_gain, & HP corner - R828_Arry[6]= (R828_Arry[6] & 0x10) | Sys_Info1.HP_COR; - R828_I2C.RegAddr = 0x0B; - R828_I2C.Data = R828_Arry[6]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // Set Img_R - R828_Arry[2] = (R828_Arry[2] & 0x7F) | Sys_Info1.IMG_R; - R828_I2C.RegAddr = 0x07; - R828_I2C.Data = R828_Arry[2]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - // Set filt_3dB, V6MHz - R828_Arry[1] = (R828_Arry[1] & 0xCF) | Sys_Info1.FILT_GAIN; - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //channel filter extension - R828_Arry[25] = (R828_Arry[25] & 0x9F) | Sys_Info1.EXT_ENABLE; - R828_I2C.RegAddr = 0x1E; - R828_I2C.Data = R828_Arry[25]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - //Loop through - R828_Arry[0] = (R828_Arry[0] & 0x7F) | Sys_Info1.LOOP_THROUGH; - R828_I2C.RegAddr = 0x05; - R828_I2C.Data = R828_Arry[0]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Loop through attenuation - R828_Arry[26] = (R828_Arry[26] & 0x7F) | Sys_Info1.LT_ATT; - R828_I2C.RegAddr = 0x1F; - R828_I2C.Data = R828_Arry[26]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //filter extention widest - R828_Arry[10] = (R828_Arry[10] & 0x7F) | Sys_Info1.FLT_EXT_WIDEST; - R828_I2C.RegAddr = 0x0F; - R828_I2C.Data = R828_Arry[10]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //RF poly filter current - R828_Arry[20] = (R828_Arry[20] & 0x9F) | Sys_Info1.POLYFIL_CUR; - R828_I2C.RegAddr = 0x19; - R828_I2C.Data = R828_Arry[20]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Success; -} - -R828_ErrCode R828_Filt_Cal(void *pTuner, UINT32 Cal_Freq,BW_Type R828_BW) -{ - //set in Sys_sel() - /* - if(R828_BW == BW_8M) - { - //set filt_cap = no cap - R828_I2C.RegAddr = 0x0B; //reg11 - R828_Arry[6] &= 0x9F; //filt_cap = no cap - R828_I2C.Data = R828_Arry[6]; - } - else if(R828_BW == BW_7M) - { - //set filt_cap = +1 cap - R828_I2C.RegAddr = 0x0B; //reg11 - R828_Arry[6] &= 0x9F; //filt_cap = no cap - R828_Arry[6] |= 0x20; //filt_cap = +1 cap - R828_I2C.Data = R828_Arry[6]; - } - else if(R828_BW == BW_6M) - { - //set filt_cap = +2 cap - R828_I2C.RegAddr = 0x0B; //reg11 - R828_Arry[6] &= 0x9F; //filt_cap = no cap - R828_Arry[6] |= 0x60; //filt_cap = +2 cap - R828_I2C.Data = R828_Arry[6]; - } - - - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; -*/ - - // Set filt_cap - R828_I2C.RegAddr = 0x0B; - R828_Arry[6]= (R828_Arry[6] & 0x9F) | (Sys_Info1.HP_COR & 0x60); - R828_I2C.Data = R828_Arry[6]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - //set cali clk =on - R828_I2C.RegAddr = 0x0F; //reg15 - R828_Arry[10] |= 0x04; //calibration clk=on - R828_I2C.Data = R828_Arry[10]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //X'tal cap 0pF for PLL - R828_I2C.RegAddr = 0x10; - R828_Arry[11] = (R828_Arry[11] & 0xFC) | 0x00; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Set PLL Freq = Filter Cali Freq - if(R828_PLL(pTuner, Cal_Freq * 1000, STD_SIZE) != RT_Success) - return RT_Fail; - - //Start Trigger - R828_I2C.RegAddr = 0x0B; //reg11 - R828_Arry[6] |= 0x10; //vstart=1 - R828_I2C.Data = R828_Arry[6]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //delay 0.5ms - R828_Delay_MS(pTuner, 1); - - //Stop Trigger - R828_I2C.RegAddr = 0x0B; - R828_Arry[6] &= 0xEF; //vstart=0 - R828_I2C.Data = R828_Arry[6]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - //set cali clk =off - R828_I2C.RegAddr = 0x0F; //reg15 - R828_Arry[10] &= 0xFB; //calibration clk=off - R828_I2C.Data = R828_Arry[10]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Success; - -} - -R828_ErrCode R828_SetFrequency(void *pTuner, R828_Set_Info R828_INFO, R828_SetFreq_Type R828_SetFreqMode) -{ - UINT32 LO_Hz; - -#if 0 - // Check Input Frequency Range - if((R828_INFO.RF_KHz<40000) || (R828_INFO.RF_KHz>900000)) - { - return RT_Fail; - } -#endif - - if(R828_INFO.R828_Standard==SECAM_L1) - LO_Hz = R828_INFO.RF_Hz - (Sys_Info1.IF_KHz * 1000); - else - LO_Hz = R828_INFO.RF_Hz + (Sys_Info1.IF_KHz * 1000); - - //Set MUX dependent var. Must do before PLL( ) - if(R828_MUX(pTuner, LO_Hz/1000) != RT_Success) - return RT_Fail; - - //Set PLL - if(R828_PLL(pTuner, LO_Hz, R828_INFO.R828_Standard) != RT_Success) - return RT_Fail; - - R828_IMR_point_num = Freq_Info1.IMR_MEM; - - - //Set TOP,VTH,VTL - SysFreq_Info1 = R828_SysFreq_Sel(R828_INFO.R828_Standard, R828_INFO.RF_KHz); - - - // write DectBW, pre_dect_TOP - R828_Arry[24] = (R828_Arry[24] & 0x38) | (SysFreq_Info1.LNA_TOP & 0xC7); - R828_I2C.RegAddr = 0x1D; - R828_I2C.Data = R828_Arry[24]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // write MIXER TOP, TOP+-1 - R828_Arry[23] = (R828_Arry[23] & 0x07) | (SysFreq_Info1.MIXER_TOP & 0xF8); - R828_I2C.RegAddr = 0x1C; - R828_I2C.Data = R828_Arry[23]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - // write LNA VTHL - R828_Arry[8] = (R828_Arry[8] & 0x00) | SysFreq_Info1.LNA_VTH_L; - R828_I2C.RegAddr = 0x0D; - R828_I2C.Data = R828_Arry[8]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // write MIXER VTHL - R828_Arry[9] = (R828_Arry[9] & 0x00) | SysFreq_Info1.MIXER_VTH_L; - R828_I2C.RegAddr = 0x0E; - R828_I2C.Data = R828_Arry[9]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // Cable-1/Air in - R828_I2C.RegAddr = 0x05; - R828_Arry[0] &= 0x9F; - R828_Arry[0] |= SysFreq_Info1.AIR_CABLE1_IN; - R828_I2C.Data = R828_Arry[0]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // Cable-2 in - R828_I2C.RegAddr = 0x06; - R828_Arry[1] &= 0xF7; - R828_Arry[1] |= SysFreq_Info1.CABLE2_IN; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //CP current - R828_I2C.RegAddr = 0x11; - R828_Arry[12] &= 0xC7; - R828_Arry[12] |= SysFreq_Info1.CP_CUR; - R828_I2C.Data = R828_Arry[12]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //div buffer current - R828_I2C.RegAddr = 0x17; - R828_Arry[18] &= 0xCF; - R828_Arry[18] |= SysFreq_Info1.DIV_BUF_CUR; - R828_I2C.Data = R828_Arry[18]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // Set channel filter current - R828_I2C.RegAddr = 0x0A; - R828_Arry[5] = (R828_Arry[5] & 0x9F) | SysFreq_Info1.FILTER_CUR; - R828_I2C.Data = R828_Arry[5]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Air-In only for Astrometa - R828_Arry[0] = (R828_Arry[0] & 0x9F) | 0x00; - R828_Arry[1] = (R828_Arry[1] & 0xF7) | 0x00; - - R828_I2C.RegAddr = 0x05; - R828_I2C.Data = R828_Arry[0]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Set LNA - if(R828_INFO.R828_Standard > SECAM_L1) - { - - if(R828_SetFreqMode==FAST_MODE) //FAST mode - { - //R828_Arry[24] = (R828_Arry[24] & 0xC7) | 0x20; //LNA TOP:4 - R828_Arry[24] = (R828_Arry[24] & 0xC7) | 0x00; //LNA TOP:lowest - R828_I2C.RegAddr = 0x1D; - R828_I2C.Data = R828_Arry[24]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Arry[23] = (R828_Arry[23] & 0xFB); // 0: normal mode - R828_I2C.RegAddr = 0x1C; - R828_I2C.Data = R828_Arry[23]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Arry[1] = (R828_Arry[1] & 0xBF); //0: PRE_DECT off - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //agc clk 250hz - R828_Arry[21] = (R828_Arry[21] & 0xCF) | 0x30; - R828_I2C.RegAddr = 0x1A; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - } - else //NORMAL mode - { - - R828_Arry[24] = (R828_Arry[24] & 0xC7) | 0x00; //LNA TOP:lowest - R828_I2C.RegAddr = 0x1D; - R828_I2C.Data = R828_Arry[24]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Arry[23] = (R828_Arry[23] & 0xFB); // 0: normal mode - R828_I2C.RegAddr = 0x1C; - R828_I2C.Data = R828_Arry[23]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Arry[1] = (R828_Arry[1] & 0xBF); //0: PRE_DECT off - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //agc clk 250hz - R828_Arry[21] = (R828_Arry[21] & 0xCF) | 0x30; //250hz - R828_I2C.RegAddr = 0x1A; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Delay_MS(pTuner, 250); - - // PRE_DECT on - /* - R828_Arry[1] = (R828_Arry[1] & 0xBF) | SysFreq_Info1.PRE_DECT; - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - */ - // write LNA TOP = 3 - //R828_Arry[24] = (R828_Arry[24] & 0xC7) | (SysFreq_Info1.LNA_TOP & 0x38); - R828_Arry[24] = (R828_Arry[24] & 0xC7) | 0x18; //TOP=3 - R828_I2C.RegAddr = 0x1D; - R828_I2C.Data = R828_Arry[24]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // write discharge mode - R828_Arry[23] = (R828_Arry[23] & 0xFB) | (SysFreq_Info1.MIXER_TOP & 0x04); - R828_I2C.RegAddr = 0x1C; - R828_I2C.Data = R828_Arry[23]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // LNA discharge current - R828_Arry[25] = (R828_Arry[25] & 0xE0) | SysFreq_Info1.LNA_DISCHARGE; - R828_I2C.RegAddr = 0x1E; - R828_I2C.Data = R828_Arry[25]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //agc clk 60hz - R828_Arry[21] = (R828_Arry[21] & 0xCF) | 0x20; - R828_I2C.RegAddr = 0x1A; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - } - } - else - { - if(R828_SetFreqMode==NORMAL_MODE || R828_SetFreqMode==FAST_MODE) - { - /* - // PRE_DECT on - R828_Arry[1] = (R828_Arry[1] & 0xBF) | SysFreq_Info1.PRE_DECT; - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - */ - // PRE_DECT off - R828_Arry[1] = (R828_Arry[1] & 0xBF); //0: PRE_DECT off - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = R828_Arry[1]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // write LNA TOP - R828_Arry[24] = (R828_Arry[24] & 0xC7) | (SysFreq_Info1.LNA_TOP & 0x38); - R828_I2C.RegAddr = 0x1D; - R828_I2C.Data = R828_Arry[24]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // write discharge mode - R828_Arry[23] = (R828_Arry[23] & 0xFB) | (SysFreq_Info1.MIXER_TOP & 0x04); - R828_I2C.RegAddr = 0x1C; - R828_I2C.Data = R828_Arry[23]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // LNA discharge current - R828_Arry[25] = (R828_Arry[25] & 0xE0) | SysFreq_Info1.LNA_DISCHARGE; - R828_I2C.RegAddr = 0x1E; - R828_I2C.Data = R828_Arry[25]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - // agc clk 1Khz, external det1 cap 1u - R828_Arry[21] = (R828_Arry[21] & 0xCF) | 0x00; - R828_I2C.RegAddr = 0x1A; - R828_I2C.Data = R828_Arry[21]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_Arry[11] = (R828_Arry[11] & 0xFB) | 0x00; - R828_I2C.RegAddr = 0x10; - R828_I2C.Data = R828_Arry[11]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - } - } - - return RT_Success; - -} - -R828_ErrCode R828_Standby(void *pTuner, R828_LoopThrough_Type R828_LoopSwitch) -{ - if(R828_LoopSwitch == LOOP_THROUGH) - { - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = 0xB1; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - R828_I2C.RegAddr = 0x05; - R828_I2C.Data = 0x03; - - - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - } - else - { - R828_I2C.RegAddr = 0x05; - R828_I2C.Data = 0xA3; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x06; - R828_I2C.Data = 0xB1; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - } - - R828_I2C.RegAddr = 0x07; - R828_I2C.Data = 0x3A; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x08; - R828_I2C.Data = 0x40; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x09; - R828_I2C.Data = 0xC0; //polyfilter off - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x0A; - R828_I2C.Data = 0x36; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x0C; - R828_I2C.Data = 0x35; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x0F; - R828_I2C.Data = 0x68; /* was 0x78, which turns off CLK_Out */ - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x11; - R828_I2C.Data = 0x03; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x17; - R828_I2C.Data = 0xF4; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C.RegAddr = 0x19; - R828_I2C.Data = 0x0C; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - return RT_Success; -} - -R828_ErrCode R828_GetRfGain(void *pTuner, R828_RF_Gain_Info *pR828_rf_gain) -{ - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 4; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - pR828_rf_gain->RF_gain1 = (R828_I2C_Len.Data[3] & 0x0F); - pR828_rf_gain->RF_gain2 = ((R828_I2C_Len.Data[3] & 0xF0) >> 4); - pR828_rf_gain->RF_gain_comb = pR828_rf_gain->RF_gain1*2 + pR828_rf_gain->RF_gain2; - - return RT_Success; -} - - -/* measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm - * input power, for raw results see: - * http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/ - */ - -#define VGA_BASE_GAIN -47 -static const int r820t_vga_gain_steps[] = { - 0, 26, 26, 30, 42, 35, 24, 13, 14, 32, 36, 34, 35, 37, 35, 36 -}; - -static const int r820t_lna_gain_steps[] = { - 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13 -}; - -static const int r820t_mixer_gain_steps[] = { - 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8 -}; - -R828_ErrCode R828_SetRfGain(void *pTuner, int gain) -{ - int i, total_gain = 0; - uint8_t mix_index = 0, lna_index = 0; - - for (i = 0; i < 15; i++) { - if (total_gain >= gain) - break; - - total_gain += r820t_lna_gain_steps[++lna_index]; - - if (total_gain >= gain) - break; - - total_gain += r820t_mixer_gain_steps[++mix_index]; - } - - /* set LNA gain */ - R828_I2C.RegAddr = 0x05; - R828_Arry[0] = (R828_Arry[0] & 0xF0) | lna_index; - R828_I2C.Data = R828_Arry[0]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - /* set Mixer gain */ - R828_I2C.RegAddr = 0x07; - R828_Arry[2] = (R828_Arry[2] & 0xF0) | mix_index; - R828_I2C.Data = R828_Arry[2]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - return RT_Success; -} - -R828_ErrCode R828_RfGainMode(void *pTuner, int manual) -{ - UINT8 MixerGain; - UINT8 LnaGain; - - MixerGain = 0; - LnaGain = 0; - - if (manual) { - //LNA auto off - R828_I2C.RegAddr = 0x05; - R828_Arry[0] = R828_Arry[0] | 0x10; - R828_I2C.Data = R828_Arry[0]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Mixer auto off - R828_I2C.RegAddr = 0x07; - R828_Arry[2] = R828_Arry[2] & 0xEF; - R828_I2C.Data = R828_Arry[2]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - R828_I2C_Len.RegAddr = 0x00; - R828_I2C_Len.Len = 4; - if(I2C_Read_Len(pTuner, &R828_I2C_Len) != RT_Success) - return RT_Fail; - - /* set fixed VGA gain for now (16.3 dB) */ - R828_I2C.RegAddr = 0x0C; - R828_Arry[7] = (R828_Arry[7] & 0x60) | 0x08; - R828_I2C.Data = R828_Arry[7]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - - } else { - //LNA - R828_I2C.RegAddr = 0x05; - R828_Arry[0] = R828_Arry[0] & 0xEF; - R828_I2C.Data = R828_Arry[0]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - //Mixer - R828_I2C.RegAddr = 0x07; - R828_Arry[2] = R828_Arry[2] | 0x10; - R828_I2C.Data = R828_Arry[2]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - - /* set fixed VGA gain for now (26.5 dB) */ - R828_I2C.RegAddr = 0x0C; - R828_Arry[7] = (R828_Arry[7] & 0x60) | 0x0B; - R828_I2C.Data = R828_Arry[7]; - if(I2C_Write(pTuner, &R828_I2C) != RT_Success) - return RT_Fail; - } - - return RT_Success; -} diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c new file mode 100644 index 0000000..540899d --- /dev/null +++ b/src/tuner_r82xx.c @@ -0,0 +1,1252 @@ +/* + * Rafael Micro R820T/R828D driver + * + * Copyright (C) 2013 Mauro Carvalho Chehab + * Copyright (C) 2013 Steve Markgraf + * + * This driver is a heavily modified version of the driver found in the + * Linux kernel: + * http://git.linuxtv.org/linux-2.6.git/history/HEAD:/drivers/media/tuners/r820t.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. + * + * This program 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 program. If not, see . + */ + +#include +#include +#include +#include + +#include "rtlsdr_i2c.h" +#include "tuner_r82xx.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define VCO_POWER_REF 0x02 +#define DIP_FREQ 32000000 + +/* + * Static constants + */ + +/* Those initial values start from REG_SHADOW_START */ +static const uint8_t r82xx_init_array[NUM_REGS] = { + 0x83, 0x32, 0x75, /* 05 to 07 */ + 0xc0, 0x40, 0xd6, 0x6c, /* 08 to 0b */ + 0xf5, 0x63, 0x75, 0x68, /* 0c to 0f */ + 0x6c, 0x83, 0x80, 0x00, /* 10 to 13 */ + 0x0f, 0x00, 0xc0, 0x30, /* 14 to 17 */ + 0x48, 0xcc, 0x60, 0x00, /* 18 to 1b */ + 0x54, 0xae, 0x4a, 0xc0 /* 1c to 1f */ +}; + +/* Tuner frequency ranges */ +static const struct r82xx_freq_range freq_ranges[] = { + { + /* .freq = */ 0, /* Start freq, in MHz */ + /* .open_d = */ 0x08, /* low */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0xdf, /* R27[7:0] band2,band0 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 50, /* Start freq, in MHz */ + /* .open_d = */ 0x08, /* low */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0xbe, /* R27[7:0] band4,band1 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 55, /* Start freq, in MHz */ + /* .open_d = */ 0x08, /* low */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x8b, /* R27[7:0] band7,band4 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 60, /* Start freq, in MHz */ + /* .open_d = */ 0x08, /* low */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x7b, /* R27[7:0] band8,band4 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 65, /* Start freq, in MHz */ + /* .open_d = */ 0x08, /* low */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x69, /* R27[7:0] band9,band6 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 70, /* Start freq, in MHz */ + /* .open_d = */ 0x08, /* low */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x58, /* R27[7:0] band10,band7 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 75, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x44, /* R27[7:0] band11,band11 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 80, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x44, /* R27[7:0] band11,band11 */ + /* .xtal_cap20p = */ 0x02, /* R16[1:0] 20pF (10) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 90, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x34, /* R27[7:0] band12,band11 */ + /* .xtal_cap20p = */ 0x01, /* R16[1:0] 10pF (01) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 100, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x34, /* R27[7:0] band12,band11 */ + /* .xtal_cap20p = */ 0x01, /* R16[1:0] 10pF (01) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 110, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x24, /* R27[7:0] band13,band11 */ + /* .xtal_cap20p = */ 0x01, /* R16[1:0] 10pF (01) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 120, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x24, /* R27[7:0] band13,band11 */ + /* .xtal_cap20p = */ 0x01, /* R16[1:0] 10pF (01) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 140, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x14, /* R27[7:0] band14,band11 */ + /* .xtal_cap20p = */ 0x01, /* R16[1:0] 10pF (01) */ + /* .xtal_cap10p = */ 0x01, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 180, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x13, /* R27[7:0] band14,band12 */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 220, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x13, /* R27[7:0] band14,band12 */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 250, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x11, /* R27[7:0] highest,highest */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 280, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + /* .tf_c = */ 0x00, /* R27[7:0] highest,highest */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 310, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */ + /* .tf_c = */ 0x00, /* R27[7:0] highest,highest */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 450, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */ + /* .tf_c = */ 0x00, /* R27[7:0] highest,highest */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 588, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */ + /* .tf_c = */ 0x00, /* R27[7:0] highest,highest */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + }, { + /* .freq = */ 650, /* Start freq, in MHz */ + /* .open_d = */ 0x00, /* high */ + /* .rf_mux_ploy = */ 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */ + /* .tf_c = */ 0x00, /* R27[7:0] highest,highest */ + /* .xtal_cap20p = */ 0x00, /* R16[1:0] 0pF (00) */ + /* .xtal_cap10p = */ 0x00, + /* .xtal_cap0p = */ 0x00, + } +}; + +static int r82xx_xtal_capacitor[][2] = { + { 0x0b, XTAL_LOW_CAP_30P }, + { 0x02, XTAL_LOW_CAP_20P }, + { 0x01, XTAL_LOW_CAP_10P }, + { 0x00, XTAL_LOW_CAP_0P }, + { 0x10, XTAL_HIGH_CAP_0P }, +}; + +/* + * I2C read/write code and shadow registers logic + */ +static void shadow_store(struct r82xx_priv *priv, uint8_t reg, const uint8_t *val, + int len) +{ + int r = reg - REG_SHADOW_START; + + if (r < 0) { + len += r; + r = 0; + } + if (len <= 0) + return; + if (len > NUM_REGS - r) + len = NUM_REGS - r; + + memcpy(&priv->regs[r], val, len); +} + +static int r82xx_write(struct r82xx_priv *priv, uint8_t reg, const uint8_t *val, + unsigned int len) +{ + int rc, size, pos = 0; + + /* Store the shadow registers */ + shadow_store(priv, reg, val, len); + + do { + if (len > priv->cfg->max_i2c_msg_len - 1) + size = priv->cfg->max_i2c_msg_len - 1; + else + size = len; + + /* Fill I2C buffer */ + priv->buf[0] = reg; + memcpy(&priv->buf[1], &val[pos], size); + + rc = rtlsdr_i2c_write_fn(priv->rtl_dev, priv->cfg->i2c_addr, + priv->buf, size + 1); + + if (rc != size + 1) { + fprintf(stderr, "%s: i2c wr failed=%d reg=%02x len=%d\n", + __func__, rc, reg, size); + if (rc < 0) + return rc; + return -EREMOTEIO; + } + + reg += size; + len -= size; + pos += size; + } while (len > 0); + + return 0; +} + +static int r82xx_write_reg(struct r82xx_priv *priv, uint8_t reg, uint8_t val) +{ + return r82xx_write(priv, reg, &val, 1); +} + +static int r82xx_read_cache_reg(struct r82xx_priv *priv, int reg) +{ + reg -= REG_SHADOW_START; + + if (reg >= 0 && reg < NUM_REGS) + return priv->regs[reg]; + else + return -EINVAL; +} + +static int r82xx_write_reg_mask(struct r82xx_priv *priv, uint8_t reg, uint8_t val, + uint8_t bit_mask) +{ + int rc = r82xx_read_cache_reg(priv, reg); + + if (rc < 0) + return rc; + + val = (rc & ~bit_mask) | (val & bit_mask); + + return r82xx_write(priv, reg, &val, 1); +} + +static uint8_t r82xx_bitrev(uint8_t byte) +{ + const uint8_t lut[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; + + return (lut[byte & 0xf] << 4) | lut[byte >> 4]; +} + +static int r82xx_read(struct r82xx_priv *priv, uint8_t reg, uint8_t *val, int len) +{ + int rc, i; + uint8_t *p = &priv->buf[1]; + + priv->buf[0] = reg; + + rc = rtlsdr_i2c_write_fn(priv->rtl_dev, priv->cfg->i2c_addr, priv->buf, 1); + if (rc < 1) + return rc; + + rc = rtlsdr_i2c_read_fn(priv->rtl_dev, priv->cfg->i2c_addr, p, len); + + if (rc != len) { + fprintf(stderr, "%s: i2c rd failed=%d reg=%02x len=%d\n", + __func__, rc, reg, len); + if (rc < 0) + return rc; + return -EREMOTEIO; + } + + /* Copy data to the output buffer */ + for (i = 0; i < len; i++) + val[i] = r82xx_bitrev(p[i]); + + return 0; +} + +/* + * r82xx tuning logic + */ + +static int r82xx_set_mux(struct r82xx_priv *priv, uint32_t freq) +{ + const struct r82xx_freq_range *range; + int rc; + unsigned int i; + uint8_t val; + + /* Get the proper frequency range */ + freq = freq / 1000000; + for (i = 0; i < ARRAY_SIZE(freq_ranges) - 1; i++) { + if (freq < freq_ranges[i + 1].freq) + break; + } + range = &freq_ranges[i]; + + /* Open Drain */ + rc = r82xx_write_reg_mask(priv, 0x17, range->open_d, 0x08); + if (rc < 0) + return rc; + + /* RF_MUX,Polymux */ + rc = r82xx_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3); + if (rc < 0) + return rc; + + /* TF BAND */ + rc = r82xx_write_reg(priv, 0x1b, range->tf_c); + if (rc < 0) + return rc; + + /* XTAL CAP & Drive */ + switch (priv->xtal_cap_sel) { + case XTAL_LOW_CAP_30P: + case XTAL_LOW_CAP_20P: + val = range->xtal_cap20p | 0x08; + break; + case XTAL_LOW_CAP_10P: + val = range->xtal_cap10p | 0x08; + break; + case XTAL_HIGH_CAP_0P: + val = range->xtal_cap0p | 0x00; + break; + default: + case XTAL_LOW_CAP_0P: + val = range->xtal_cap0p | 0x08; + break; + } + rc = r82xx_write_reg_mask(priv, 0x10, val, 0x0b); + if (rc < 0) + return rc; + + rc = r82xx_write_reg_mask(priv, 0x08, 0x00, 0x3f); + if (rc < 0) + return rc; + + rc = r82xx_write_reg_mask(priv, 0x09, 0x00, 0x3f); + + return rc; +} + +static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq) +{ + int rc, i; + unsigned sleep_time = 10000; + uint64_t vco_freq; + uint32_t vco_fra; /* VCO contribution by SDM (kHz) */ + uint32_t vco_min = 1770000; + uint32_t vco_max = vco_min * 2; + uint32_t freq_khz, pll_ref, pll_ref_khz; + uint16_t n_sdm = 2; + uint16_t sdm = 0; + uint8_t mix_div = 2; + uint8_t div_buf = 0; + uint8_t div_num = 0; + uint8_t refdiv2 = 0; + uint8_t ni, si, nint, vco_fine_tune, val; + uint8_t data[5]; + + /* Frequency in kHz */ + freq_khz = (freq + 500) / 1000; + pll_ref = priv->cfg->xtal; // / 1000; + pll_ref_khz = (priv->cfg->xtal + 500) / 1000; + + rc = r82xx_write_reg_mask(priv, 0x10, refdiv2, 0x10); + if (rc < 0) + return rc; + + /* set pll autotune = 128kHz */ + rc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x0c); + if (rc < 0) + return rc; + + /* set VCO current = 100 */ + rc = r82xx_write_reg_mask(priv, 0x12, 0x80, 0xe0); + if (rc < 0) + return rc; + + /* Calculate divider */ + while (mix_div <= 64) { + if (((freq_khz * mix_div) >= vco_min) && + ((freq_khz * mix_div) < vco_max)) { + div_buf = mix_div; + while (div_buf > 2) { + div_buf = div_buf >> 1; + div_num++; + } + break; + } + mix_div = mix_div << 1; + } + + rc = r82xx_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + vco_fine_tune = (data[4] & 0x30) >> 4; + + if (vco_fine_tune > VCO_POWER_REF) + div_num = div_num - 1; + else if (vco_fine_tune < VCO_POWER_REF) + div_num = div_num + 1; + + rc = r82xx_write_reg_mask(priv, 0x10, div_num << 5, 0xe0); + if (rc < 0) + return rc; + + vco_freq = (uint64_t)freq * (uint64_t)mix_div; + nint = vco_freq / (2 * pll_ref); + vco_fra = (vco_freq - 2 * pll_ref * nint) / 1000; + + if (nint > 63) { + fprintf(stderr, "No valid PLL values for %u kHz!\n", freq); + return -EINVAL; + } + + ni = (nint - 13) / 4; + si = nint - 4 * ni - 13; + + rc = r82xx_write_reg(priv, 0x14, ni + (si << 6)); + if (rc < 0) + return rc; + + /* pw_sdm */ + if (!vco_fra) + val = 0x08; + else + val = 0x00; + + rc = r82xx_write_reg_mask(priv, 0x12, val, 0x08); + if (rc < 0) + return rc; + + /* sdm calculator */ + while (vco_fra > 1) { + if (vco_fra > (2 * pll_ref_khz / n_sdm)) { + sdm = sdm + 32768 / (n_sdm / 2); + vco_fra = vco_fra - 2 * pll_ref_khz / n_sdm; + if (n_sdm >= 0x8000) + break; + } + n_sdm <<= 1; + } + + rc = r82xx_write_reg(priv, 0x16, sdm >> 8); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x15, sdm & 0xff); + if (rc < 0) + return rc; + + for (i = 0; i < 2; i++) { +// usleep_range(sleep_time, sleep_time + 1000); + + /* Check if PLL has locked */ + rc = r82xx_read(priv, 0x00, data, 3); + if (rc < 0) + return rc; + if (data[2] & 0x40) + break; + + if (!i) { + /* Didn't lock. Increase VCO current */ + rc = r82xx_write_reg_mask(priv, 0x12, 0x60, 0xe0); + if (rc < 0) + return rc; + } + } + + if (!(data[2] & 0x40)) { + priv->has_lock = 0; + return 0; + } + + priv->has_lock = 1; + + /* set pll autotune = 8kHz */ + rc = r82xx_write_reg_mask(priv, 0x1a, 0x08, 0x08); + + return rc; +} + +static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq, + enum r82xx_tuner_type type, + uint32_t delsys) +{ + int rc; + uint8_t mixer_top, lna_top, cp_cur, div_buf_cur, lna_vth_l, mixer_vth_l; + uint8_t air_cable1_in, cable2_in, pre_dect, lna_discharge, filter_cur; + + switch (delsys) { + case SYS_DVBT: + if ((freq == 506000000) || (freq == 666000000) || + (freq == 818000000)) { + mixer_top = 0x14; /* mixer top:14 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + cp_cur = 0x28; /* 101, 0.2 */ + div_buf_cur = 0x20; /* 10, 200u */ + } else { + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + } + lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + filter_cur = 0x40; /* 10, low */ + break; + case SYS_DVBT2: + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + filter_cur = 0x40; /* 10, low */ + break; + case SYS_ISDBT: + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + lna_vth_l = 0x75; /* lna vth 1.04 , vtl 0.84 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + filter_cur = 0x40; /* 10, low */ + break; + default: /* DVB-T 8M */ + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + filter_cur = 0x40; /* 10, low */ + break; + } + + if (priv->cfg->use_diplexer && + ((priv->cfg->rafael_chip == CHIP_R820T) || + (priv->cfg->rafael_chip == CHIP_R828S) || + (priv->cfg->rafael_chip == CHIP_R820C))) { + if (freq > DIP_FREQ) + air_cable1_in = 0x00; + else + air_cable1_in = 0x60; + cable2_in = 0x00; + } + + if (priv->cfg->use_predetect) { + rc = r82xx_write_reg_mask(priv, 0x06, pre_dect, 0x40); + if (rc < 0) + return rc; + } + + rc = r82xx_write_reg_mask(priv, 0x1d, lna_top, 0xc7); + if (rc < 0) + return rc; + rc = r82xx_write_reg_mask(priv, 0x1c, mixer_top, 0xf8); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x0d, lna_vth_l); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x0e, mixer_vth_l); + if (rc < 0) + return rc; + + /* Air-IN only for Astrometa */ + rc = r82xx_write_reg_mask(priv, 0x05, air_cable1_in, 0x60); + if (rc < 0) + return rc; + rc = r82xx_write_reg_mask(priv, 0x06, cable2_in, 0x08); + if (rc < 0) + return rc; + + rc = r82xx_write_reg_mask(priv, 0x11, cp_cur, 0x38); + if (rc < 0) + return rc; + rc = r82xx_write_reg_mask(priv, 0x17, div_buf_cur, 0x30); + if (rc < 0) + return rc; + rc = r82xx_write_reg_mask(priv, 0x0a, filter_cur, 0x60); + if (rc < 0) + return rc; + /* + * Original driver initializes regs 0x05 and 0x06 with the + * same value again on this point. Probably, it is just an + * error there + */ + + /* + * Set LNA + */ + + if (type != TUNER_ANALOG_TV) { + /* LNA TOP: lowest */ + rc = r82xx_write_reg_mask(priv, 0x1d, 0, 0x38); + if (rc < 0) + return rc; + + /* 0: normal mode */ + rc = r82xx_write_reg_mask(priv, 0x1c, 0, 0x04); + if (rc < 0) + return rc; + + /* 0: PRE_DECT off */ + rc = r82xx_write_reg_mask(priv, 0x06, 0, 0x40); + if (rc < 0) + return rc; + + /* agc clk 250hz */ + rc = r82xx_write_reg_mask(priv, 0x1a, 0x30, 0x30); + if (rc < 0) + return rc; + +// msleep(250); + + /* write LNA TOP = 3 */ + rc = r82xx_write_reg_mask(priv, 0x1d, 0x18, 0x38); + if (rc < 0) + return rc; + + /* + * write discharge mode + * FIXME: IMHO, the mask here is wrong, but it matches + * what's there at the original driver + */ + rc = r82xx_write_reg_mask(priv, 0x1c, mixer_top, 0x04); + if (rc < 0) + return rc; + + /* LNA discharge current */ + rc = r82xx_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f); + if (rc < 0) + return rc; + + /* agc clk 60hz */ + rc = r82xx_write_reg_mask(priv, 0x1a, 0x20, 0x30); + if (rc < 0) + return rc; + } else { + /* PRE_DECT off */ + rc = r82xx_write_reg_mask(priv, 0x06, 0, 0x40); + if (rc < 0) + return rc; + + /* write LNA TOP */ + rc = r82xx_write_reg_mask(priv, 0x1d, lna_top, 0x38); + if (rc < 0) + return rc; + + /* + * write discharge mode + * FIXME: IMHO, the mask here is wrong, but it matches + * what's there at the original driver + */ + rc = r82xx_write_reg_mask(priv, 0x1c, mixer_top, 0x04); + if (rc < 0) + return rc; + + /* LNA discharge current */ + rc = r82xx_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f); + if (rc < 0) + return rc; + + /* agc clk 1Khz, external det1 cap 1u */ + rc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x30); + if (rc < 0) + return rc; + + rc = r82xx_write_reg_mask(priv, 0x10, 0x00, 0x04); + if (rc < 0) + return rc; + } + return 0; +} + +static int r82xx_set_tv_standard(struct r82xx_priv *priv, + unsigned bw, + enum r82xx_tuner_type type, + uint32_t delsys) + +{ + int rc, i; + uint32_t if_khz, filt_cal_lo; + uint8_t data[5], val; + uint8_t filt_gain, img_r, filt_q, hp_cor, ext_enable, loop_through; + uint8_t lt_att, flt_ext_widest, polyfil_cur; + int need_calibration; + + if (delsys == SYS_ISDBT) { + if_khz = 4063; + filt_cal_lo = 59000; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */ + ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ + } else { + if (bw <= 6) { + if_khz = 3570; + filt_cal_lo = 56000; /* 52000->56000 */ + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ + } else if (bw == 7) { +#if 0 + /* + * There are two 7 MHz tables defined on the original + * driver, but just the second one seems to be visible + * by rtl2832. Keep this one here commented, as it + * might be needed in the future + */ + + if_khz = 4070; + filt_cal_lo = 60000; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ +#endif + /* 7 MHz, second table */ + if_khz = 4570; + filt_cal_lo = 63000; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ + } else { + if_khz = 4570; + filt_cal_lo = 68500; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ + } + } + + /* Initialize the shadow registers */ + memcpy(priv->regs, r82xx_init_array, sizeof(r82xx_init_array)); + + /* Init Flag & Xtal_check Result (inits VGA gain, needed?)*/ + rc = r82xx_write_reg_mask(priv, 0x0c, 0x00, 0x0f); + if (rc < 0) + return rc; + + /* version */ + rc = r82xx_write_reg_mask(priv, 0x13, VER_NUM, 0x3f); + if (rc < 0) + return rc; + + /* for LT Gain test */ + if (type != TUNER_ANALOG_TV) { + rc = r82xx_write_reg_mask(priv, 0x1d, 0x00, 0x38); + if (rc < 0) + return rc; +// usleep_range(1000, 2000); + } + priv->int_freq = if_khz * 1000; + + /* Check if standard changed. If so, filter calibration is needed */ + /* as we call this function only once in rtlsdr, force calibration */ + need_calibration = 1; + + if (need_calibration) { + for (i = 0; i < 2; i++) { + /* Set filt_cap */ + rc = r82xx_write_reg_mask(priv, 0x0b, hp_cor, 0x60); + if (rc < 0) + return rc; + + /* set cali clk =on */ + rc = r82xx_write_reg_mask(priv, 0x0f, 0x04, 0x04); + if (rc < 0) + return rc; + + /* X'tal cap 0pF for PLL */ + rc = r82xx_write_reg_mask(priv, 0x10, 0x00, 0x03); + if (rc < 0) + return rc; + + rc = r82xx_set_pll(priv, filt_cal_lo * 1000); + if (rc < 0 || !priv->has_lock) + return rc; + + /* Start Trigger */ + rc = r82xx_write_reg_mask(priv, 0x0b, 0x10, 0x10); + if (rc < 0) + return rc; + +// usleep_range(1000, 2000); + + /* Stop Trigger */ + rc = r82xx_write_reg_mask(priv, 0x0b, 0x00, 0x10); + if (rc < 0) + return rc; + + /* set cali clk =off */ + rc = r82xx_write_reg_mask(priv, 0x0f, 0x00, 0x04); + if (rc < 0) + return rc; + + /* Check if calibration worked */ + rc = r82xx_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + priv->fil_cal_code = data[4] & 0x0f; + if (priv->fil_cal_code && priv->fil_cal_code != 0x0f) + break; + } + /* narrowest */ + if (priv->fil_cal_code == 0x0f) + priv->fil_cal_code = 0; + } + + rc = r82xx_write_reg_mask(priv, 0x0a, + filt_q | priv->fil_cal_code, 0x1f); + if (rc < 0) + return rc; + + /* Set BW, Filter_gain, & HP corner */ + rc = r82xx_write_reg_mask(priv, 0x0b, hp_cor, 0xef); + if (rc < 0) + return rc; + + /* Set Img_R */ + rc = r82xx_write_reg_mask(priv, 0x07, img_r, 0x80); + if (rc < 0) + return rc; + + /* Set filt_3dB, V6MHz */ + rc = r82xx_write_reg_mask(priv, 0x06, filt_gain, 0x30); + if (rc < 0) + return rc; + + /* channel filter extension */ + rc = r82xx_write_reg_mask(priv, 0x1e, ext_enable, 0x60); + if (rc < 0) + return rc; + + /* Loop through */ + rc = r82xx_write_reg_mask(priv, 0x05, loop_through, 0x80); + if (rc < 0) + return rc; + + /* Loop through attenuation */ + rc = r82xx_write_reg_mask(priv, 0x1f, lt_att, 0x80); + if (rc < 0) + return rc; + + /* filter extension widest */ + rc = r82xx_write_reg_mask(priv, 0x0f, flt_ext_widest, 0x80); + if (rc < 0) + return rc; + + /* RF poly filter current */ + rc = r82xx_write_reg_mask(priv, 0x19, polyfil_cur, 0x60); + if (rc < 0) + return rc; + + /* Store current standard. If it changes, re-calibrate the tuner */ + priv->delsys = delsys; + priv->type = type; + priv->bw = bw; + + return 0; +} + +static int r82xx_read_gain(struct r82xx_priv *priv) +{ + uint8_t data[4]; + int rc; + + rc = r82xx_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4); +} + +/* measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm + * input power, for raw results see: + * http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/ + */ + +#define VGA_BASE_GAIN -47 +static const int r82xx_vga_gain_steps[] = { + 0, 26, 26, 30, 42, 35, 24, 13, 14, 32, 36, 34, 35, 37, 35, 36 +}; + +static const int r82xx_lna_gain_steps[] = { + 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13 +}; + +static const int r82xx_mixer_gain_steps[] = { + 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8 +}; + +int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain) +{ + int rc; + + if (set_manual_gain) { + int i, total_gain = 0; + uint8_t mix_index = 0, lna_index = 0; + uint8_t data[4]; + + /* LNA auto off */ + rc = r82xx_write_reg_mask(priv, 0x05, 0x10, 0x10); + if (rc < 0) + return rc; + + /* Mixer auto off */ + rc = r82xx_write_reg_mask(priv, 0x07, 0, 0x10); + if (rc < 0) + return rc; + + rc = r82xx_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + /* set fixed VGA gain for now (16.3 dB) */ + rc = r82xx_write_reg_mask(priv, 0x0c, 0x08, 0x9f); + if (rc < 0) + return rc; + + for (i = 0; i < 15; i++) { + if (total_gain >= gain) + break; + + total_gain += r82xx_lna_gain_steps[++lna_index]; + + if (total_gain >= gain) + break; + + total_gain += r82xx_mixer_gain_steps[++mix_index]; + } + + /* set LNA gain */ + rc = r82xx_write_reg_mask(priv, 0x05, lna_index, 0x0f); + if (rc < 0) + return rc; + + /* set Mixer gain */ + rc = r82xx_write_reg_mask(priv, 0x07, mix_index, 0x0f); + if (rc < 0) + return rc; + } else { + /* LNA */ + rc = r82xx_write_reg_mask(priv, 0x05, 0, 0x10); + if (rc < 0) + return rc; + + /* Mixer */ + rc = r82xx_write_reg_mask(priv, 0x07, 0x10, 0x10); + if (rc < 0) + return rc; + + /* set fixed VGA gain for now (26.5 dB) */ + rc = r82xx_write_reg_mask(priv, 0x0c, 0x0b, 0x9f); + if (rc < 0) + return rc; + } + + return 0; +} + +int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq) +{ + int rc = -EINVAL; + uint32_t lo_freq = freq + priv->int_freq; + + lo_freq = freq + priv->int_freq; + + rc = r82xx_set_mux(priv, lo_freq); + if (rc < 0) + goto err; + + rc = r82xx_set_pll(priv, lo_freq); + if (rc < 0 || !priv->has_lock) + goto err; + +err: + if (rc < 0) + fprintf(stderr, "%s: failed=%d\n", __func__, rc); + return rc; +} + +/* + * r82xx standby logic + */ + +int r82xx_standby(struct r82xx_priv *priv) +{ + int rc; + + /* If device was not initialized yet, don't need to standby */ + if (!priv->init_done) + return 0; + + rc = r82xx_write_reg(priv, 0x06, 0xb1); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x05, 0x03); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x07, 0x3a); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x08, 0x40); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x09, 0xc0); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x0a, 0x36); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x0c, 0x35); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x0f, 0x68); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x11, 0x03); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x17, 0xf4); + if (rc < 0) + return rc; + rc = r82xx_write_reg(priv, 0x19, 0x0c); + + /* Force initial calibration */ + priv->type = -1; + + return rc; +} + +/* + * r82xx device init logic + */ + +static int r82xx_xtal_check(struct r82xx_priv *priv) +{ + int rc; + unsigned int i; + uint8_t data[3], val; + + /* Initialize the shadow registers */ + memcpy(priv->regs, r82xx_init_array, sizeof(r82xx_init_array)); + + /* cap 30pF & Drive Low */ + rc = r82xx_write_reg_mask(priv, 0x10, 0x0b, 0x0b); + if (rc < 0) + return rc; + + /* set pll autotune = 128kHz */ + rc = r82xx_write_reg_mask(priv, 0x1a, 0x00, 0x0c); + if (rc < 0) + return rc; + + /* set manual initial reg = 111111; */ + rc = r82xx_write_reg_mask(priv, 0x13, 0x7f, 0x7f); + if (rc < 0) + return rc; + + /* set auto */ + rc = r82xx_write_reg_mask(priv, 0x13, 0x00, 0x40); + if (rc < 0) + return rc; + + /* Try several xtal capacitor alternatives */ + for (i = 0; i < ARRAY_SIZE(r82xx_xtal_capacitor); i++) { + rc = r82xx_write_reg_mask(priv, 0x10, + r82xx_xtal_capacitor[i][0], 0x1b); + if (rc < 0) + return rc; + +// usleep_range(5000, 6000); + + rc = r82xx_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + if (!(data[2] & 0x40)) + continue; + + val = data[2] & 0x3f; + + if (priv->cfg->xtal == 16000000 && (val > 29 || val < 23)) + break; + + if (val != 0x3f) + break; + } + + if (i == ARRAY_SIZE(r82xx_xtal_capacitor)) + return -EINVAL; + + return r82xx_xtal_capacitor[i][1]; +} + +int r82xx_init(struct r82xx_priv *priv) +{ + int rc; + + /* TODO: R828D might need r82xx_xtal_check() */ + priv->xtal_cap_sel = XTAL_HIGH_CAP_0P; + + /* Initialize registers */ + rc = r82xx_write(priv, 0x05, + r82xx_init_array, sizeof(r82xx_init_array)); + + rc = r82xx_set_tv_standard(priv, 3, TUNER_DIGITAL_TV, 0); + if (rc < 0) + goto err; + + rc = r82xx_sysfreq_sel(priv, 0, TUNER_DIGITAL_TV, SYS_DVBT); + if (rc < 0) + goto err; + +err: + if (rc < 0) + fprintf(stderr, "%s: failed=%d\n", __func__, rc); + return rc; +} + +#if 0 +/* Not used, for now */ +static int r82xx_gpio(struct r82xx_priv *priv, int enable) +{ + return r82xx_write_reg_mask(priv, 0x0f, enable ? 1 : 0, 0x01); +} +#endif