From 4031d6ed044093d5c5d5d27029d82e02e11ee06a Mon Sep 17 00:00:00 2001 From: Steve Markgraf Date: Tue, 29 May 2012 03:31:49 +0200 Subject: [PATCH] tuner_fc0012: use new cleaned-up driver The driver was taken from http://git.linuxtv.org/ and adapted for librtlsdr. Manual gain will be added in a follow-up commit. Signed-off-by: Steve Markgraf --- include/tuner_fc0012.h | 45 ++-- src/librtlsdr.c | 14 +- src/tuner_fc0012.c | 493 ++++++++++++++++++++--------------------- 3 files changed, 274 insertions(+), 278 deletions(-) diff --git a/include/tuner_fc0012.h b/include/tuner_fc0012.h index aa1d5e9..9dd5356 100644 --- a/include/tuner_fc0012.h +++ b/include/tuner_fc0012.h @@ -1,25 +1,36 @@ -#ifndef __TUNER_FC0012_H -#define __TUNER_FC0012_H +/* + * Fitipower FC0012 tuner driver + * + * Copyright (C) 2012 Hans-Frieder Vogt + * + * modified for use in librtlsdr + * Copyright (C) 2012 Steve Markgraf + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ -#define FC0012_OK 0 -#define FC0012_ERROR 1 +#ifndef _FC0012_H_ +#define _FC0012_H_ #define FC0012_I2C_ADDR 0xc6 #define FC0012_CHECK_ADDR 0x00 #define FC0012_CHECK_VAL 0xa1 -#define FC0012_BANDWIDTH_6MHZ 6 -#define FC0012_BANDWIDTH_7MHZ 7 -#define FC0012_BANDWIDTH_8MHZ 8 - -#define FC0012_LNA_GAIN_LOW 0x00 -#define FC0012_LNA_GAIN_MID 0x08 -#define FC0012_LNA_GAIN_HI 0x17 -#define FC0012_LNA_GAIN_MAX 0x10 - -int FC0012_Open(void *pTuner); -int FC0012_Read(void *pTuner, unsigned char RegAddr, unsigned char *pByte); -int FC0012_Write(void *pTuner, unsigned char RegAddr, unsigned char Byte); -int FC0012_SetFrequency(void *pTuner, unsigned long Frequency, unsigned short Bandwidth); +int fc0012_init(void *dev); +int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth); +int fc0012_set_gain(void *dev, int gain); #endif diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 9576d5c..af4c869 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -122,17 +122,17 @@ int e4000_set_gain_mode(void *dev, int manual) { return 0; } -int fc0012_init(void *dev) { return FC0012_Open(dev); } +int _fc0012_init(void *dev) { return fc0012_init(dev); } int fc0012_exit(void *dev) { return 0; } int fc0012_set_freq(void *dev, uint32_t freq) { /* select V-band/U-band filter */ rtlsdr_set_gpio_bit(dev, 6, (freq > 300000000) ? 1 : 0); - return FC0012_SetFrequency(dev, freq/1000, 6); + return fc0012_set_params(dev, freq, 6000000); } -int fc0012_set_bw(void *dev, int bw) { - return FC0012_SetFrequency(dev, ((rtlsdr_dev_t *) dev)->freq/1000, 6); +int fc0012_set_bw(void *dev, int bw) { return 0; } +int _fc0012_set_gain(void *dev, int gain) { + return fc0012_set_gain(dev, gain); } -int fc0012_set_gain(void *dev, int gain) { return 0; } int fc0012_set_gain_mode(void *dev, int manual) { return 0; } int _fc0013_init(void *dev) { return fc0013_init(dev); } @@ -173,8 +173,8 @@ static rtlsdr_tuner_t tuners[] = { e4000_set_gain_mode }, { - fc0012_init, fc0012_exit, - fc0012_set_freq, fc0012_set_bw, fc0012_set_gain, + _fc0012_init, fc0012_exit, + fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, fc0012_set_gain_mode }, { diff --git a/src/tuner_fc0012.c b/src/tuner_fc0012.c index 2d66f3c..c1ad73c 100644 --- a/src/tuner_fc0012.c +++ b/src/tuner_fc0012.c @@ -1,21 +1,57 @@ /* - * fc0012 tuner support for rtl-sdr + * Fitipower FC0012 tuner driver * - * Based on tuner_fc0012.c found as part of the (seemingly GPLed) - * rtl2832u Linux DVB driver. + * Copyright (C) 2012 Hans-Frieder Vogt * - * Rewritten and hacked into rtl-sdr by David Basden + * modified for use in librtlsdr + * Copyright (C) 2012 Steve Markgraf + * + * 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, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include "rtlsdr_i2c.h" #include "tuner_fc0012.h" -#define CRYSTAL_FREQ 28800000 +static int fc0012_writereg(void *dev, uint8_t reg, uint8_t val) +{ + uint8_t data[2]; + data[0] = reg; + data[1] = val; -#define FC0012_LNAGAIN FC0012_LNA_GAIN_HI + if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, data, 2) < 0) + return -1; + + return 0; +} + +static int fc0012_readreg(void *dev, uint8_t reg, uint8_t *val) +{ + uint8_t data = reg; + + if (rtlsdr_i2c_write_fn(dev, FC0012_I2C_ADDR, &data, 1) < 0) + return -1; + + if (rtlsdr_i2c_read_fn(dev, FC0012_I2C_ADDR, &data, 1) < 0) + return -1; + + *val = data; + + return 0; +} /* Incomplete list of register settings: * @@ -30,7 +66,7 @@ * RF_OUTDIV_A 0x05 3-7 Power of two required? * LNA_POWER_DOWN 0x06 0 Set to 1 to switch off low noise amp * RF_OUTDIV_B 0x06 1 Set to select 3 instead of 2 for the - * RF output divider + * RF output divider * VCO_SPEED 0x06 3 Select tuning range of VCO: * 0 = Low range, (ca. 1.1 - 1.5GHz) * 1 = High range (ca. 1.4 - 1.8GHz) @@ -51,277 +87,226 @@ * (big value -> low freq) */ -/* glue functions to rtl-sdr code */ -int FC0012_Write(void *pTuner, unsigned char RegAddr, unsigned char Byte) +int fc0012_init(void *dev) { - uint8_t data[2]; + int ret = 0; + unsigned int i; + uint8_t reg[] = { + 0x00, /* dummy reg. 0 */ + 0x05, /* reg. 0x01 */ + 0x10, /* reg. 0x02 */ + 0x00, /* reg. 0x03 */ + 0x00, /* reg. 0x04 */ + 0x0f, /* reg. 0x05: may also be 0x0a */ + 0x00, /* reg. 0x06: divider 2, VCO slow */ + 0x00, /* reg. 0x07: may also be 0x0f */ + 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, + Loop Bw 1/8 */ + 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */ + 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ + 0x82, /* reg. 0x0b: Output Clock is same as clock frequency, + may also be 0x83 */ + 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ + 0x02, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */ + 0x00, /* reg. 0x0e */ + 0x00, /* reg. 0x0f */ + 0x00, /* reg. 0x10: may also be 0x0d */ + 0x00, /* reg. 0x11 */ + 0x1f, /* reg. 0x12: Set to maximum gain */ + 0x08, /* reg. 0x13: Set to Middle Gain: 0x08, + Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */ + 0x00, /* reg. 0x14 */ + 0x04, /* reg. 0x15: Enable LNA COMPS */ + }; - data[0] = RegAddr; - data[1] = Byte; - - if (rtlsdr_i2c_write_fn(pTuner, FC0012_I2C_ADDR, data, 2) < 0) - return FC0012_ERROR; - - return FC0012_OK; -} - -int FC0012_Read(void *pTuner, unsigned char RegAddr, unsigned char *pByte) -{ - uint8_t data = RegAddr; - - if (rtlsdr_i2c_write_fn(pTuner, FC0012_I2C_ADDR, &data, 1) < 0) - return FC0012_ERROR; - - if (rtlsdr_i2c_read_fn(pTuner, FC0012_I2C_ADDR, &data, 1) < 0) - return FC0012_ERROR; - - *pByte = data; - - return FC0012_OK; -} - -#ifdef DEBUG -#define DEBUGF printf -#else -#define DEBUGF(...) () -#endif #if 0 -void FC0012_Dump_Registers() -{ -#ifdef DEBUG - unsigned char regBuf; - int ret; - int i; - - DEBUGF("\nFC0012 registers:\n"); - for (i=0; i<=0x15; ++i) - { - ret = FC0012_Read(pTuner, i, ®Buf); - if (ret) DEBUGF("\nCouldn't read register %02x\n", i); - DEBUGF("R%x=%02x ",i,regBuf); - } - DEBUGF("\n"); - FC0012_Read(pTuner, 0x06, ®Buf); - DEBUGF("LNA_POWER_DOWN:\t%s\n", regBuf & 1 ? "Powered down" : "Not Powered Down"); - DEBUGF("VCO_SPEED:\t%s\n", regBuf & 0x8 ? "High speed" : "Slow speed"); - DEBUGF("Bandwidth:\t%s\n", (regBuf & 0xC) ? "8MHz" : "less than 8MHz"); - FC0012_Read(pTuner, 0x07, ®Buf); - DEBUGF("Crystal Speed:\t%s\n", (regBuf & 0x20) ? "28.8MHz" : "36MHZ"); - FC0012_Read(pTuner, 0x09, ®Buf); - DEBUGF("RSSI calibration mode:\t%s\n", (regBuf & 0x10) ? "RSSI CALIBRATION IN PROGRESS" : "Disabled"); - FC0012_Read(pTuner, 0x0d, ®Buf); - DEBUGF("LNA Force:\t%s\n", (regBuf & 0x1) ? "Forced" : "Not Forced"); - FC0012_Read(pTuner, 0x13, ®Buf); - DEBUGF("LNA Gain:\t"); - switch (regBuf & 0x18) { - case (0x00): DEBUGF("Low\n"); break; - case (0x08): DEBUGF("Middle\n"); break; - case (0x10): DEBUGF("High\n"); break; - default: DEBUGF("unknown gain value 0x18\n"); + switch (rtlsdr_get_tuner_clock(dev)) { + case FC_XTAL_27_MHZ: + case FC_XTAL_28_8_MHZ: + reg[0x07] |= 0x20; + break; + case FC_XTAL_36_MHZ: + default: + break; } #endif -} -#endif + reg[0x07] |= 0x20; -int FC0012_Open(void *pTuner) -{ -// DEBUGF("FC0012_Open start"); - if (FC0012_Write(pTuner, 0x01, 0x05)) return -1; - if (FC0012_Write(pTuner, 0x02, 0x10)) return -1; - if (FC0012_Write(pTuner, 0x03, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x04, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x05, 0x0F)) return -1; - if (FC0012_Write(pTuner, 0x06, 0x00)) return -1; // divider 2, VCO slow - if (FC0012_Write(pTuner, 0x07, 0x20)) return -1; // change to 0x00 for a 36MHz crystal - if (FC0012_Write(pTuner, 0x08, 0xFF)) return -1; // AGC Clock divide by 254, AGC gain 1/256, Loop Bw 1/8 - if (FC0012_Write(pTuner, 0x09, 0x6E)) return -1; // Disable LoopThrough - if (FC0012_Write(pTuner, 0x0A, 0xB8)) return -1; // Disable LO Test Buffer - if (FC0012_Write(pTuner, 0x0B, 0x82)) return -1; // Output Clock is same as clock frequency - //if (FC0012_Write(pTuner, 0x0C, 0xF8)) return -1; - if (FC0012_Write(pTuner, 0x0C, 0xFC)) return -1; // AGC up-down mode - if (FC0012_Write(pTuner, 0x0D, 0x02)) return -1; // AGC Not Forcing & LNA Forcing - if (FC0012_Write(pTuner, 0x0E, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x0F, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x10, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x11, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x12, 0x1F)) return -1; // Set to maximum gain - if (FC0012_Write(pTuner, 0x13, FC0012_LNAGAIN)) return -1; - if (FC0012_Write(pTuner, 0x14, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x15, 0x04)) return -1; // Enable LNA COMPS - - /* Black magic from nim_rtl2832_fc0012.c in DVB driver. - Even though we've set 0x11 to 0x00 above, this needs to happen to have - it go back - */ - if (FC0012_Write(pTuner, 0x0d, 0x02)) return -1; - if (FC0012_Write(pTuner, 0x11, 0x00)) return -1; - if (FC0012_Write(pTuner, 0x15, 0x04)) return -1; +// if (priv->dual_master) + reg[0x0c] |= 0x02; -// DEBUGF("FC0012_Open SUCCESS"); - return FC0012_OK; + for (i = 1; i < sizeof(reg); i++) { + ret = fc0012_writereg(dev, i, reg[i]); + if (ret) + break; + } + + return ret; } -# if 0 -// Frequency is in kHz. Bandwidth is in MHz -// This is pseudocode to set GPIO6 for VHF/UHF filter switching. -// Trying to do this in reality leads to fail currently. I'm probably doing it wrong. -void FC0012_Frequency_Control(unsigned int Frequency, unsigned short Bandwidth) +int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth) { - if( Frequency < 260000 && Frequency > 150000 ) - { - // set GPIO6 = low + int i, ret = 0; + uint8_t reg[7], am, pm, multi, tmp; + uint64_t f_vco; + uint32_t xtal_freq_div_2; + uint16_t xin, xdiv; + int vco_select = 0; - // 1. Set tuner frequency - // 2. if the program quality is not good enough, switch to frequency + 500kHz - // 3. if the program quality is still no good, switch to frequency - 500kHz - } - else - { - // set GPIO6 = high + xtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2; - // set tuner frequency - } -} -#endif - -int FC0012_SetFrequency(void *pTuner, unsigned long Frequency, unsigned short Bandwidth) -{ - int VCO_band = 0; - unsigned long doubleVCO; - unsigned short xin, xdiv; - unsigned char reg[21], am, pm, multi; - unsigned char read_byte; - - unsigned long CrystalFreqKhz; - -// DEBUGF("FC0012_SetFrequency start"); - - CrystalFreqKhz = (rtlsdr_get_tuner_clock(pTuner) + 500) / 1000; - - //===================================== Select frequency divider and the frequency of VCO - if (Frequency * 96 < 3560000) - { - multi = 96; reg[5] = 0x82; reg[6] = 0x00; - } - else if (Frequency * 64 < 3560000) - { - multi = 64; reg[5] = 0x82; reg[6] = 0x02; - } - else if (Frequency * 48 < 3560000) - { - multi = 48; reg[5] = 0x42; reg[6] = 0x00; - } - else if (Frequency * 32 < 3560000) - { - multi = 32; reg[5] = 0x42; reg[6] = 0x02; - } - else if (Frequency * 24 < 3560000) - { - multi = 24; reg[5] = 0x22; reg[6] = 0x00; - } - else if (Frequency * 16 < 3560000) - { - multi = 16; reg[5] = 0x22; reg[6] = 0x02; - } - else if (Frequency * 12 < 3560000) - { - multi = 12; reg[5] = 0x12; reg[6] = 0x00; - } - else if (Frequency * 8 < 3560000) - { - multi = 8; reg[5] = 0x12; reg[6] = 0x02; - } - else if (Frequency * 6 < 3560000) - { - multi = 6; reg[5] = 0x0A; reg[6] = 0x00; - } - else - { - multi = 4; reg[5] = 0x0A; reg[6] = 0x02; - } - - doubleVCO = Frequency * multi; - - reg[6] = reg[6] | 0x08; - VCO_band = 1; - xdiv = (unsigned short)(doubleVCO / (CrystalFreqKhz / 2)); - if( (doubleVCO - xdiv * (CrystalFreqKhz / 2)) >= (CrystalFreqKhz / 4) ) - xdiv = xdiv + 1; - - pm = (unsigned char)( xdiv / 8 ); - am = (unsigned char)( xdiv - (8 * pm)); - - if (am < 2) { - reg[1] = am + 8; - reg[2] = pm - 1; + /* select frequency divider and the frequency of VCO */ + if (freq < 37084000) { /* freq * 96 < 3560000000 */ + multi = 96; + reg[5] = 0x82; + reg[6] = 0x00; + } else if (freq < 55625000) { /* freq * 64 < 3560000000 */ + multi = 64; + reg[5] = 0x82; + reg[6] = 0x02; + } else if (freq < 74167000) { /* freq * 48 < 3560000000 */ + multi = 48; + reg[5] = 0x42; + reg[6] = 0x00; + } else if (freq < 111250000) { /* freq * 32 < 3560000000 */ + multi = 32; + reg[5] = 0x42; + reg[6] = 0x02; + } else if (freq < 148334000) { /* freq * 24 < 3560000000 */ + multi = 24; + reg[5] = 0x22; + reg[6] = 0x00; + } else if (freq < 222500000) { /* freq * 16 < 3560000000 */ + multi = 16; + reg[5] = 0x22; + reg[6] = 0x02; + } else if (freq < 296667000) { /* freq * 12 < 3560000000 */ + multi = 12; + reg[5] = 0x12; + reg[6] = 0x00; + } else if (freq < 445000000) { /* freq * 8 < 3560000000 */ + multi = 8; + reg[5] = 0x12; + reg[6] = 0x02; + } else if (freq < 593334000) { /* freq * 6 < 3560000000 */ + multi = 6; + reg[5] = 0x0a; + reg[6] = 0x00; } else { - reg[1] = am; - reg[2] = pm; + multi = 4; + reg[5] = 0x0a; + reg[6] = 0x02; } - // From VCO frequency determines the XIN ( fractional part of Delta Sigma PLL) and divided value (XDIV). - xin = (unsigned short)(doubleVCO - ((unsigned short)(doubleVCO / (CrystalFreqKhz / 2))) * (CrystalFreqKhz / 2)); - xin = ((xin << 15)/(unsigned short)(CrystalFreqKhz / 2)); - if( xin >= (unsigned short) 16384 ) - xin = xin + (unsigned short) 32768; + f_vco = freq * multi; - reg[3] = (unsigned char)(xin >> 8); - reg[4] = (unsigned char)(xin & 0x00FF); - -// DEBUGF("Frequency: %lu, Fa: %d, Fp: %d, Xin:%d \n", Frequency, am, pm, xin); - - switch(Bandwidth) - { - case 6: reg[6] = 0x80 | reg[6]; break; - case 7: reg[6] = (~0x80 & reg[6]) | 0x40; break; - case 8: default: reg[6] = ~0xC0 & reg[6]; break; + if (f_vco >= 3060000000U) { + reg[6] |= 0x08; + vco_select = 1; } - if (FC0012_Write(pTuner, 0x01, reg[1])) return -1; - if (FC0012_Write(pTuner, 0x02, reg[2])) return -1; - if (FC0012_Write(pTuner, 0x03, reg[3])) return -1; - if (FC0012_Write(pTuner, 0x04, reg[4])) return -1; - //reg[5] = reg[5] | 0x07; // This is really not cool. Why is it there? - if (FC0012_Write(pTuner, 0x05, reg[5])) return -1; - if (FC0012_Write(pTuner, 0x06, reg[6])) return -1; + if (freq >= 45000000) { + /* From divided value (XDIV) determined the FA and FP value */ + xdiv = (uint16_t)(f_vco / xtal_freq_div_2); + if ((f_vco - xdiv * xtal_freq_div_2) >= (xtal_freq_div_2 / 2)) + xdiv++; - // VCO Calibration - if (FC0012_Write(pTuner, 0x0E, 0x80)) return -1; - if (FC0012_Write(pTuner, 0x0E, 0x00)) return -1; + pm = (uint8_t)(xdiv / 8); + am = (uint8_t)(xdiv - (8 * pm)); - // Read resulting VCO control voltage - if (FC0012_Write(pTuner, 0x0E, 0x00)) return -1; - if (FC0012_Read(pTuner, 0x0E, &read_byte)) return -1; - reg[14] = 0x3F & read_byte; - - // Adjust VCO range if control voltage is at the limit - if (VCO_band) - { - // high-band VCO hitting low frequency bound - if (reg[14] > 0x3C) - { - // select low-band VCO - reg[6] = ~0x08 & reg[6]; - - if (FC0012_Write(pTuner, 0x06, reg[6])) return -1; - if (FC0012_Write(pTuner, 0x0E, 0x80)) return -1; - if (FC0012_Write(pTuner, 0x0E, 0x00)) return -1; + if (am < 2) { + reg[1] = am + 8; + reg[2] = pm - 1; + } else { + reg[1] = am; + reg[2] = pm; } + } else { + /* fix for frequency less than 45 MHz */ + reg[1] = 0x06; + reg[2] = 0x11; } - else - { - // low-band VCO hitting high frequency bound - if (reg[14] < 0x02) { - // select high-band VCO - reg[6] = 0x08 | reg[6]; - if (FC0012_Write(pTuner, 0x06, reg[6])) return -1; - if (FC0012_Write(pTuner, 0x0E, 0x80)) return -1; - if (FC0012_Write(pTuner, 0x0E, 0x00)) return -1; + /* fix clock out */ + reg[6] |= 0x20; + + /* From VCO frequency determines the XIN ( fractional part of Delta + Sigma PLL) and divided value (XDIV) */ + xin = (uint16_t)((f_vco - (f_vco / xtal_freq_div_2) * xtal_freq_div_2) / 1000); + xin = (xin << 15) / (xtal_freq_div_2 / 1000); + if (xin >= 16384) + xin += 32768; + + reg[3] = xin >> 8; /* xin with 9 bit resolution */ + reg[4] = xin & 0xff; + + reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ + switch (bandwidth) { + case 6000000: + reg[6] |= 0x80; + break; + case 7000000: + reg[6] |= 0x40; + break; + case 8000000: + default: + break; + } + + /* modified for Realtek demod */ + reg[5] |= 0x07; + + for (i = 1; i <= 6; i++) { + ret = fc0012_writereg(dev, i, reg[i]); + if (ret) + goto exit; + } + + /* VCO Calibration */ + ret = fc0012_writereg(dev, 0x0e, 0x80); + if (!ret) + ret = fc0012_writereg(dev, 0x0e, 0x00); + + /* VCO Re-Calibration if needed */ + if (!ret) + ret = fc0012_writereg(dev, 0x0e, 0x00); + + if (!ret) { +// msleep(10); + ret = fc0012_readreg(dev, 0x0e, &tmp); + } + if (ret) + goto exit; + + /* vco selection */ + tmp &= 0x3f; + + if (vco_select) { + if (tmp > 0x3c) { + reg[6] &= ~0x08; + ret = fc0012_writereg(dev, 0x06, reg[6]); + if (!ret) + ret = fc0012_writereg(dev, 0x0e, 0x80); + if (!ret) + ret = fc0012_writereg(dev, 0x0e, 0x00); + } + } else { + if (tmp < 0x02) { + reg[6] |= 0x08; + ret = fc0012_writereg(dev, 0x06, reg[6]); + if (!ret) + ret = fc0012_writereg(dev, 0x0e, 0x80); + if (!ret) + ret = fc0012_writereg(dev, 0x0e, 0x00); } } -// DEBUGF("FC0012_SetFrequency SUCCESS"); FC0012_Dump_Registers(); - return FC0012_OK; +exit: + return ret; } +int fc0012_set_gain(void *dev, int gain) +{ + /* TODO add gain regulation */ + return 0; +}