From 18e567bd588d9976deefbd0191d495c57a0acd60 Mon Sep 17 00:00:00 2001 From: dinashi Date: Fri, 6 Jan 2023 20:55:52 +0000 Subject: Removed support for old tuners --- src/librtlsdr.c | 113 +++--- src/make.mk | 2 +- src/tuner_e4k.c | 1000 ---------------------------------------------------- src/tuner_fc0012.c | 345 ------------------ src/tuner_fc0013.c | 500 -------------------------- src/tuner_fc2580.c | 494 -------------------------- 6 files changed, 63 insertions(+), 2391 deletions(-) delete mode 100644 src/tuner_e4k.c delete mode 100644 src/tuner_fc0012.c delete mode 100644 src/tuner_fc0013.c delete mode 100644 src/tuner_fc2580.c (limited to 'src') diff --git a/src/librtlsdr.c b/src/librtlsdr.c index 096abae..538c0dd 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -43,10 +43,10 @@ #define TWO_POW(n) ((double)(1ULL<<(n))) #include "rtl-sdr.h" -#include "tuner_e4k.h" -#include "tuner_fc0012.h" -#include "tuner_fc0013.h" -#include "tuner_fc2580.h" +//#include "tuner_e4k.h" +//#include "tuner_fc0012.h" +//#include "tuner_fc0013.h" +//#include "tuner_fc2580.h" #include "tuner_r82xx.h" typedef struct rtlsdr_tuner_iface { @@ -112,7 +112,7 @@ struct rtlsdr_dev { uint32_t offs_freq; /* Hz */ int corr; /* ppm */ int gain; /* tenth dB */ - struct e4k_state e4k_s; + //struct e4k_state e4k_s; struct r82xx_config r82xx_c; struct r82xx_priv r82xx_p; /* status */ @@ -125,7 +125,7 @@ void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val); static int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq); /* generic tuner interface functions, shall be moved to the tuner implementations */ -int e4000_init(void *dev) { +/*int e4000_init(void *dev) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; devt->e4k_s.i2c_addr = E4K_I2C_ADDR; rtlsdr_get_xtal_freq(devt, NULL, &devt->e4k_s.vco.fosc); @@ -150,25 +150,26 @@ int e4000_set_bw(void *dev, int bw) { r |= e4k_if_filter_bw_set(&devt->e4k_s, E4K_IF_FILTER_CHAN, bw); return r; -} +}*/ -int e4000_set_gain(void *dev, int gain) { - rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; - int mixgain = (gain > 340) ? 12 : 4; +//int e4000_set_gain(void *dev, int gain) { +// rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; +// int mixgain = (gain > 340) ? 12 : 4; #if 0 int enhgain = (gain - 420); #endif - if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL) - return -1; - if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL) - return -1; +// if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - mixgain * 10)) == -EINVAL) +// return -1; +// if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL) +// return -1; #if 0 /* enhanced mixer gain seems to have no effect */ if(enhgain >= 0) if(e4k_set_enh_gain(&devt->e4k_s, enhgain) == -EINVAL) return -1; #endif - return 0; -} +// return 0; +//} +/* int e4000_set_if_gain(void *dev, int stage, int gain) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; return e4k_if_gain_set(&devt->e4k_s, (uint8_t)stage, (int8_t)(gain / 10)); @@ -176,36 +177,36 @@ int e4000_set_if_gain(void *dev, int stage, int gain) { int e4000_set_gain_mode(void *dev, int manual) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; return e4k_enable_manual_gain(&devt->e4k_s, manual); -} +}*/ -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) { +//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_set_params(dev, freq, 6000000); -} -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_mode(void *dev, int manual) { return 0; } - -int _fc0013_init(void *dev) { return fc0013_init(dev); } -int fc0013_exit(void *dev) { return 0; } -int fc0013_set_freq(void *dev, uint32_t freq) { - return fc0013_set_params(dev, freq, 6000000); -} -int fc0013_set_bw(void *dev, int bw) { return 0; } -int _fc0013_set_gain(void *dev, int gain) { return fc0013_set_lna_gain(dev, gain); } - -int fc2580_init(void *dev) { return fc2580_Initialize(dev); } -int fc2580_exit(void *dev) { return 0; } -int _fc2580_set_freq(void *dev, uint32_t freq) { +// rtlsdr_set_gpio_bit(dev, 6, (freq > 300000000) ? 1 : 0); +// return fc0012_set_params(dev, freq, 6000000); +//} +//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_mode(void *dev, int manual) { return 0; } + +//int _fc0013_init(void *dev) { return fc0013_init(dev); } +//int fc0013_exit(void *dev) { return 0; } +//int fc0013_set_freq(void *dev, uint32_t freq) { +// return fc0013_set_params(dev, freq, 6000000); +//} +//int fc0013_set_bw(void *dev, int bw) { return 0; } +//int _fc0013_set_gain(void *dev, int gain) { return fc0013_set_lna_gain(dev, gain); } + +//int fc2580_init(void *dev) { return fc2580_Initialize(dev); } +//int fc2580_exit(void *dev) { return 0; } +/*int _fc2580_set_freq(void *dev, uint32_t freq) { return fc2580_SetRfFreqHz(dev, freq); } int fc2580_set_bw(void *dev, int bw) { return fc2580_SetBandwidthMode(dev, 1); } 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) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; devt->r82xx_p.rtl_dev = dev; @@ -263,7 +264,7 @@ static rtlsdr_tuner_iface_t tuners[] = { { NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */ }, - { + /*{ e4000_init, e4000_exit, e4000_set_freq, e4000_set_bw, e4000_set_gain, e4000_set_if_gain, e4000_set_gain_mode @@ -282,7 +283,7 @@ static rtlsdr_tuner_iface_t tuners[] = { fc2580_init, fc2580_exit, _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL, fc2580_set_gain_mode - }, + },*/ { r820t_init, r820t_exit, r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, @@ -747,8 +748,10 @@ int rtlsdr_set_xtal_freq(rtlsdr_dev_t *dev, uint32_t rtl_freq, uint32_t tuner_fr dev->tun_xtal = tuner_freq; /* read corrected clock value into e4k and r82xx structure */ - if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc) || + /*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 (rtlsdr_get_xtal_freq(dev, NULL, &dev->r82xx_c.xtal)) return -3; /* update xtal-dependent settings */ @@ -925,9 +928,11 @@ 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 and r82xx structure */ - if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc) || + /*if (rtlsdr_get_xtal_freq(dev, NULL, &dev->e4k_s.vco.fosc) || rtlsdr_get_xtal_freq(dev, NULL, &dev->r82xx_c.xtal)) - return -3; + return -3;*/ + if (rtlsdr_get_xtal_freq(dev, NULL, &dev->r82xx_c.xtal)) + return -3; if (dev->freq) /* retune to apply new correction value */ r |= rtlsdr_set_center_freq(dev, dev->freq); @@ -954,13 +959,13 @@ enum rtlsdr_tuner rtlsdr_get_tuner_type(rtlsdr_dev_t *dev) int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) { /* all gain values are expressed in tenths of a dB */ - const int e4k_gains[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, + /*const int e4k_gains[] = { -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, 240, 290, 340, 420 }; const int fc0012_gains[] = { -99, -40, 71, 179, 192 }; const int fc0013_gains[] = { -99, -73, -65, -63, -60, -58, -54, 58, 61, 63, 65, 67, 68, 70, 71, 179, 181, 182, - 184, 186, 188, 191, 197 }; - const int fc2580_gains[] = { 0 /* no gain values */ }; + 184, 186, 188, 191, 197 };*/ + //const int fc2580_gains[] = { 0 /* no gain values */ }; const int r82xx_gains[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 421, 434, 439, @@ -974,7 +979,7 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) return -1; switch (dev->tuner_type) { - case RTLSDR_TUNER_E4000: + /*case RTLSDR_TUNER_E4000: ptr = e4k_gains; len = sizeof(e4k_gains); break; case RTLSDR_TUNER_FC0012: @@ -985,7 +990,7 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) break; case RTLSDR_TUNER_FC2580: ptr = fc2580_gains; len = sizeof(fc2580_gains); - break; + break;*/ case RTLSDR_TUNER_R820T: case RTLSDR_TUNER_R828D: ptr = r82xx_gains; len = sizeof(r82xx_gains); @@ -1531,19 +1536,22 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) /* Probe tuners */ rtlsdr_set_i2c_repeater(dev, 1); + /* reg = rtlsdr_i2c_read_reg(dev, E4K_I2C_ADDR, E4K_CHECK_ADDR); if (reg == E4K_CHECK_VAL) { fprintf(stderr, "Found Elonics E4000 tuner\n"); dev->tuner_type = RTLSDR_TUNER_E4000; goto found; } + */ + /* reg = rtlsdr_i2c_read_reg(dev, FC0013_I2C_ADDR, FC0013_CHECK_ADDR); if (reg == FC0013_CHECK_VAL) { fprintf(stderr, "Found Fitipower FC0013 tuner\n"); dev->tuner_type = RTLSDR_TUNER_FC0013; goto found; - } + }*/ reg = rtlsdr_i2c_read_reg(dev, R820T_I2C_ADDR, R82XX_CHECK_ADDR); if (reg == R82XX_CHECK_VAL) { @@ -1566,20 +1574,23 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) rtlsdr_set_gpio_bit(dev, 4, 1); rtlsdr_set_gpio_bit(dev, 4, 0); + /* reg = rtlsdr_i2c_read_reg(dev, FC2580_I2C_ADDR, FC2580_CHECK_ADDR); if ((reg & 0x7f) == FC2580_CHECK_VAL) { fprintf(stderr, "Found FCI 2580 tuner\n"); dev->tuner_type = RTLSDR_TUNER_FC2580; goto found; } + */ + /* reg = rtlsdr_i2c_read_reg(dev, FC0012_I2C_ADDR, FC0012_CHECK_ADDR); if (reg == FC0012_CHECK_VAL) { fprintf(stderr, "Found Fitipower FC0012 tuner\n"); rtlsdr_set_gpio_output(dev, 6); dev->tuner_type = RTLSDR_TUNER_FC0012; goto found; - } + }*/ found: /* use the rtl clock value by default */ diff --git a/src/make.mk b/src/make.mk index 33d9033..938f3d7 100644 --- a/src/make.mk +++ b/src/make.mk @@ -1,7 +1,7 @@ DIR_SRC=src SRC_LIB += $(wildcard $(DIR_SRC)/*.c) OBJ_LIB += $(SRC_LIB:.c=.o) -LDFLAGS_LIB=`pkg-config --libs libusb` -lc +LDFLAGS_LIB=`pkg-config --libs libusb` -lc $(DIR_SRC)-lib-o: $(OBJ_LIB) diff --git a/src/tuner_e4k.c b/src/tuner_e4k.c deleted file mode 100644 index 400e745..0000000 --- a/src/tuner_e4k.c +++ /dev/null @@ -1,1000 +0,0 @@ -/* - * Elonics E4000 tuner driver - * - * (C) 2011-2012 by Harald Welte - * (C) 2012 by Sylvain Munaut - * (C) 2012 by Hoernchen - * - * All Rights Reserved - * - * 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 - -#include -#include -#include - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -/* If this is defined, the limits are somewhat relaxed compared to what the - * vendor claims is possible */ -#define OUT_OF_SPEC - -#define MHZ(x) ((x)*1000*1000) -#define KHZ(x) ((x)*1000) - -uint32_t unsigned_delta(uint32_t a, uint32_t b) -{ - if (a > b) - return a - b; - else - return b - a; -} - -/* look-up table bit-width -> mask */ -static const uint8_t width2mask[] = { - 0, 1, 3, 7, 0xf, 0x1f, 0x3f, 0x7f, 0xff -}; - -/*********************************************************************** - * Register Access */ - -/*! \brief Write a register of the tuner chip - * \param[in] e4k reference to the tuner - * \param[in] reg number of the register - * \param[in] val value to be written - * \returns 0 on success, negative in case of error - */ -static int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val) -{ - int r; - uint8_t data[2]; - data[0] = reg; - data[1] = val; - - r = rtlsdr_i2c_write_fn(e4k->rtl_dev, e4k->i2c_addr, data, 2); - return r == 2 ? 0 : -1; -} - -/*! \brief Read a register of the tuner chip - * \param[in] e4k reference to the tuner - * \param[in] reg number of the register - * \returns positive 8bit register contents on success, negative in case of error - */ -static int e4k_reg_read(struct e4k_state *e4k, uint8_t reg) -{ - uint8_t data = reg; - - if (rtlsdr_i2c_write_fn(e4k->rtl_dev, e4k->i2c_addr, &data, 1) < 1) - return -1; - - if (rtlsdr_i2c_read_fn(e4k->rtl_dev, e4k->i2c_addr, &data, 1) < 1) - return -1; - - return data; -} - -/*! \brief Set or clear some (masked) bits inside a register - * \param[in] e4k reference to the tuner - * \param[in] reg number of the register - * \param[in] mask bit-mask of the value - * \param[in] val data value to be written to register - * \returns 0 on success, negative in case of error - */ -static int e4k_reg_set_mask(struct e4k_state *e4k, uint8_t reg, - uint8_t mask, uint8_t val) -{ - uint8_t tmp = e4k_reg_read(e4k, reg); - - if ((tmp & mask) == val) - return 0; - - return e4k_reg_write(e4k, reg, (tmp & ~mask) | (val & mask)); -} - -/*! \brief Write a given field inside a register - * \param[in] e4k reference to the tuner - * \param[in] field structure describing the field - * \param[in] val value to be written - * \returns 0 on success, negative in case of error - */ -static int e4k_field_write(struct e4k_state *e4k, const struct reg_field *field, uint8_t val) -{ - int rc; - uint8_t mask; - - rc = e4k_reg_read(e4k, field->reg); - if (rc < 0) - return rc; - - mask = width2mask[field->width] << field->shift; - - return e4k_reg_set_mask(e4k, field->reg, mask, val << field->shift); -} - -/*! \brief Read a given field inside a register - * \param[in] e4k reference to the tuner - * \param[in] field structure describing the field - * \returns positive value of the field, negative in case of error - */ -static int e4k_field_read(struct e4k_state *e4k, const struct reg_field *field) -{ - int rc; - - rc = e4k_reg_read(e4k, field->reg); - if (rc < 0) - return rc; - - rc = (rc >> field->shift) & width2mask[field->width]; - - return rc; -} - -/*********************************************************************** - * Filter Control */ - -static const uint32_t rf_filt_center_uhf[] = { - MHZ(360), MHZ(380), MHZ(405), MHZ(425), - MHZ(450), MHZ(475), MHZ(505), MHZ(540), - MHZ(575), MHZ(615), MHZ(670), MHZ(720), - MHZ(760), MHZ(840), MHZ(890), MHZ(970) -}; - -static const uint32_t rf_filt_center_l[] = { - MHZ(1300), MHZ(1320), MHZ(1360), MHZ(1410), - MHZ(1445), MHZ(1460), MHZ(1490), MHZ(1530), - MHZ(1560), MHZ(1590), MHZ(1640), MHZ(1660), - MHZ(1680), MHZ(1700), MHZ(1720), MHZ(1750) -}; - -static int closest_arr_idx(const uint32_t *arr, unsigned int arr_size, uint32_t freq) -{ - unsigned int i, bi = 0; - uint32_t best_delta = 0xffffffff; - - /* iterate over the array containing a list of the center - * frequencies, selecting the closest one */ - for (i = 0; i < arr_size; i++) { - uint32_t delta = unsigned_delta(freq, arr[i]); - if (delta < best_delta) { - best_delta = delta; - bi = i; - } - } - - return bi; -} - -/* return 4-bit index as to which RF filter to select */ -static int choose_rf_filter(enum e4k_band band, uint32_t freq) -{ - int rc; - - switch (band) { - case E4K_BAND_VHF2: - case E4K_BAND_VHF3: - rc = 0; - break; - case E4K_BAND_UHF: - rc = closest_arr_idx(rf_filt_center_uhf, - ARRAY_SIZE(rf_filt_center_uhf), - freq); - break; - case E4K_BAND_L: - rc = closest_arr_idx(rf_filt_center_l, - ARRAY_SIZE(rf_filt_center_l), - freq); - break; - default: - rc = -EINVAL; - break; - } - - return rc; -} - -/* \brief Automatically select apropriate RF filter based on e4k state */ -int e4k_rf_filter_set(struct e4k_state *e4k) -{ - int rc; - - rc = choose_rf_filter(e4k->band, e4k->vco.flo); - if (rc < 0) - return rc; - - return e4k_reg_set_mask(e4k, E4K_REG_FILT1, 0xF, rc); -} - -/* Mixer Filter */ -static const uint32_t mix_filter_bw[] = { - KHZ(27000), KHZ(27000), KHZ(27000), KHZ(27000), - KHZ(27000), KHZ(27000), KHZ(27000), KHZ(27000), - KHZ(4600), KHZ(4200), KHZ(3800), KHZ(3400), - KHZ(3300), KHZ(2700), KHZ(2300), KHZ(1900) -}; - -/* IF RC Filter */ -static const uint32_t ifrc_filter_bw[] = { - KHZ(21400), KHZ(21000), KHZ(17600), KHZ(14700), - KHZ(12400), KHZ(10600), KHZ(9000), KHZ(7700), - KHZ(6400), KHZ(5300), KHZ(4400), KHZ(3400), - KHZ(2600), KHZ(1800), KHZ(1200), KHZ(1000) -}; - -/* IF Channel Filter */ -static const uint32_t ifch_filter_bw[] = { - KHZ(5500), KHZ(5300), KHZ(5000), KHZ(4800), - KHZ(4600), KHZ(4400), KHZ(4300), KHZ(4100), - KHZ(3900), KHZ(3800), KHZ(3700), KHZ(3600), - KHZ(3400), KHZ(3300), KHZ(3200), KHZ(3100), - KHZ(3000), KHZ(2950), KHZ(2900), KHZ(2800), - KHZ(2750), KHZ(2700), KHZ(2600), KHZ(2550), - KHZ(2500), KHZ(2450), KHZ(2400), KHZ(2300), - KHZ(2280), KHZ(2240), KHZ(2200), KHZ(2150) -}; - -static const uint32_t *if_filter_bw[] = { - mix_filter_bw, - ifch_filter_bw, - ifrc_filter_bw, -}; - -static const uint32_t if_filter_bw_len[] = { - ARRAY_SIZE(mix_filter_bw), - ARRAY_SIZE(ifch_filter_bw), - ARRAY_SIZE(ifrc_filter_bw), -}; - -static const struct reg_field if_filter_fields[] = { - { - E4K_REG_FILT2, 4, 4, - }, - { - E4K_REG_FILT3, 0, 5, - }, - { - E4K_REG_FILT2, 0, 4, - } -}; - -static int find_if_bw(enum e4k_if_filter filter, uint32_t bw) -{ - if (filter >= ARRAY_SIZE(if_filter_bw)) - return -EINVAL; - - return closest_arr_idx(if_filter_bw[filter], - if_filter_bw_len[filter], bw); -} - -/*! \brief Set the filter band-width of any of the IF filters - * \param[in] e4k reference to the tuner chip - * \param[in] filter filter to be configured - * \param[in] bandwidth bandwidth to be configured - * \returns positive actual filter band-width, negative in case of error - */ -int e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter, - uint32_t bandwidth) -{ - int bw_idx; - const struct reg_field *field; - - if (filter >= ARRAY_SIZE(if_filter_bw)) - return -EINVAL; - - bw_idx = find_if_bw(filter, bandwidth); - - field = &if_filter_fields[filter]; - - return e4k_field_write(e4k, field, bw_idx); -} - -/*! \brief Enables / Disables the channel filter - * \param[in] e4k reference to the tuner chip - * \param[in] on 1=filter enabled, 0=filter disabled - * \returns 0 success, negative errors - */ -int e4k_if_filter_chan_enable(struct e4k_state *e4k, int on) -{ - return e4k_reg_set_mask(e4k, E4K_REG_FILT3, E4K_FILT3_DISABLE, - on ? 0 : E4K_FILT3_DISABLE); -} - -int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter) -{ - const uint32_t *arr; - int rc; - const struct reg_field *field; - - if (filter >= ARRAY_SIZE(if_filter_bw)) - return -EINVAL; - - field = &if_filter_fields[filter]; - - rc = e4k_field_read(e4k, field); - if (rc < 0) - return rc; - - arr = if_filter_bw[filter]; - - return arr[rc]; -} - - -/*********************************************************************** - * Frequency Control */ - -#define E4K_FVCO_MIN_KHZ 2600000 /* 2.6 GHz */ -#define E4K_FVCO_MAX_KHZ 3900000 /* 3.9 GHz */ -#define E4K_PLL_Y 65536 - -#ifdef OUT_OF_SPEC -#define E4K_FLO_MIN_MHZ 50 -#define E4K_FLO_MAX_MHZ 2200UL -#else -#define E4K_FLO_MIN_MHZ 64 -#define E4K_FLO_MAX_MHZ 1700 -#endif - -struct pll_settings { - uint32_t freq; - uint8_t reg_synth7; - uint8_t mult; -}; - -static const struct pll_settings pll_vars[] = { - {KHZ(72400), (1 << 3) | 7, 48}, - {KHZ(81200), (1 << 3) | 6, 40}, - {KHZ(108300), (1 << 3) | 5, 32}, - {KHZ(162500), (1 << 3) | 4, 24}, - {KHZ(216600), (1 << 3) | 3, 16}, - {KHZ(325000), (1 << 3) | 2, 12}, - {KHZ(350000), (1 << 3) | 1, 8}, - {KHZ(432000), (0 << 3) | 3, 8}, - {KHZ(667000), (0 << 3) | 2, 6}, - {KHZ(1200000), (0 << 3) | 1, 4} -}; - -static int is_fvco_valid(uint32_t fvco_z) -{ - /* check if the resulting fosc is valid */ - if (fvco_z/1000 < E4K_FVCO_MIN_KHZ || - fvco_z/1000 > E4K_FVCO_MAX_KHZ) { - fprintf(stderr, "[E4K] Fvco %u invalid\n", fvco_z); - return 0; - } - - return 1; -} - -static int is_fosc_valid(uint32_t fosc) -{ - if (fosc < MHZ(16) || fosc > MHZ(30)) { - fprintf(stderr, "[E4K] Fosc %u invalid\n", fosc); - return 0; - } - - return 1; -} - -static int is_z_valid(uint32_t z) -{ - if (z > 255) { - fprintf(stderr, "[E4K] Z %u invalid\n", z); - return 0; - } - - return 1; -} - -/*! \brief Determine if 3-phase mixing shall be used or not */ -static int use_3ph_mixing(uint32_t flo) -{ - /* this is a magic number somewhre between VHF and UHF */ - if (flo < MHZ(350)) - return 1; - - return 0; -} - -/* \brief compute Fvco based on Fosc, Z and X - * \returns positive value (Fvco in Hz), 0 in case of error */ -static uint64_t compute_fvco(uint32_t f_osc, uint8_t z, uint16_t x) -{ - uint64_t fvco_z, fvco_x, fvco; - - /* We use the following transformation in order to - * handle the fractional part with integer arithmetic: - * Fvco = Fosc * (Z + X/Y) <=> Fvco = Fosc * Z + (Fosc * X)/Y - * This avoids X/Y = 0. However, then we would overflow a 32bit - * integer, as we cannot hold e.g. 26 MHz * 65536 either. - */ - fvco_z = (uint64_t)f_osc * z; - -#if 0 - if (!is_fvco_valid(fvco_z)) - return 0; -#endif - - fvco_x = ((uint64_t)f_osc * x) / E4K_PLL_Y; - - fvco = fvco_z + fvco_x; - - return fvco; -} - -static uint32_t compute_flo(uint32_t f_osc, uint8_t z, uint16_t x, uint8_t r) -{ - uint64_t fvco = compute_fvco(f_osc, z, x); - if (fvco == 0) - return -EINVAL; - - return fvco / r; -} - -static int e4k_band_set(struct e4k_state *e4k, enum e4k_band band) -{ - int rc; - - switch (band) { - case E4K_BAND_VHF2: - case E4K_BAND_VHF3: - case E4K_BAND_UHF: - e4k_reg_write(e4k, E4K_REG_BIAS, 3); - break; - case E4K_BAND_L: - e4k_reg_write(e4k, E4K_REG_BIAS, 0); - break; - } - - /* workaround: if we don't reset this register before writing to it, - * we get a gap between 325-350 MHz */ - rc = e4k_reg_set_mask(e4k, E4K_REG_SYNTH1, 0x06, 0); - rc = e4k_reg_set_mask(e4k, E4K_REG_SYNTH1, 0x06, band << 1); - if (rc >= 0) - e4k->band = band; - - return rc; -} - -/*! \brief Compute PLL parameters for givent target frequency - * \param[out] oscp Oscillator parameters, if computation successful - * \param[in] fosc Clock input frequency applied to the chip (Hz) - * \param[in] intended_flo target tuning frequency (Hz) - * \returns actual PLL frequency, as close as possible to intended_flo, - * 0 in case of error - */ -uint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo) -{ - uint32_t i; - uint8_t r = 2; - uint64_t intended_fvco, remainder; - uint64_t z = 0; - uint32_t x; - int flo; - int three_phase_mixing = 0; - oscp->r_idx = 0; - - if (!is_fosc_valid(fosc)) - return 0; - - for(i = 0; i < ARRAY_SIZE(pll_vars); ++i) { - if(intended_flo < pll_vars[i].freq) { - three_phase_mixing = (pll_vars[i].reg_synth7 & 0x08) ? 1 : 0; - oscp->r_idx = pll_vars[i].reg_synth7; - r = pll_vars[i].mult; - break; - } - } - - //fprintf(stderr, "[E4K] Fint=%u, R=%u\n", intended_flo, r); - - /* flo(max) = 1700MHz, R(max) = 48, we need 64bit! */ - intended_fvco = (uint64_t)intended_flo * r; - - /* compute integral component of multiplier */ - z = intended_fvco / fosc; - - /* compute fractional part. this will not overflow, - * as fosc(max) = 30MHz and z(max) = 255 */ - remainder = intended_fvco - (fosc * z); - /* remainder(max) = 30MHz, E4K_PLL_Y = 65536 -> 64bit! */ - x = (remainder * E4K_PLL_Y) / fosc; - /* x(max) as result of this computation is 65536 */ - - flo = compute_flo(fosc, z, x, r); - - oscp->fosc = fosc; - oscp->flo = flo; - oscp->intended_flo = intended_flo; - oscp->r = r; -// oscp->r_idx = pll_vars[i].reg_synth7 & 0x0; - oscp->threephase = three_phase_mixing; - oscp->x = x; - oscp->z = z; - - return flo; -} - -int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p) -{ - /* program R + 3phase/2phase */ - e4k_reg_write(e4k, E4K_REG_SYNTH7, p->r_idx); - /* program Z */ - e4k_reg_write(e4k, E4K_REG_SYNTH3, p->z); - /* program X */ - e4k_reg_write(e4k, E4K_REG_SYNTH4, p->x & 0xff); - e4k_reg_write(e4k, E4K_REG_SYNTH5, p->x >> 8); - - /* we're in auto calibration mode, so there's no need to trigger it */ - - memcpy(&e4k->vco, p, sizeof(e4k->vco)); - - /* set the band */ - if (e4k->vco.flo < MHZ(140)) - e4k_band_set(e4k, E4K_BAND_VHF2); - else if (e4k->vco.flo < MHZ(350)) - e4k_band_set(e4k, E4K_BAND_VHF3); - else if (e4k->vco.flo < MHZ(1135)) - e4k_band_set(e4k, E4K_BAND_UHF); - else - e4k_band_set(e4k, E4K_BAND_L); - - /* select and set proper RF filter */ - e4k_rf_filter_set(e4k); - - return e4k->vco.flo; -} - -/*! \brief High-level tuning API, just specify frquency - * - * This function will compute matching PLL parameters, program them into the - * hardware and set the band as well as RF filter. - * - * \param[in] e4k reference to tuner - * \param[in] freq frequency in Hz - * \returns actual tuned frequency, negative in case of error - */ -int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq) -{ - uint32_t rc; - struct e4k_pll_params p; - - /* determine PLL parameters */ - rc = e4k_compute_pll_params(&p, e4k->vco.fosc, freq); - if (!rc) - return -EINVAL; - - /* actually tune to those parameters */ - rc = e4k_tune_params(e4k, &p); - - /* check PLL lock */ - rc = e4k_reg_read(e4k, E4K_REG_SYNTH1); - if (!(rc & 0x01)) { - fprintf(stderr, "[E4K] PLL not locked for %u Hz!\n", freq); - return -1; - } - - return 0; -} - -/*********************************************************************** - * Gain Control */ - -static const int8_t if_stage1_gain[] = { - -3, 6 -}; - -static const int8_t if_stage23_gain[] = { - 0, 3, 6, 9 -}; - -static const int8_t if_stage4_gain[] = { - 0, 1, 2, 2 -}; - -static const int8_t if_stage56_gain[] = { - 3, 6, 9, 12, 15, 15, 15, 15 -}; - -static const int8_t *if_stage_gain[] = { - 0, - if_stage1_gain, - if_stage23_gain, - if_stage23_gain, - if_stage4_gain, - if_stage56_gain, - if_stage56_gain -}; - -static const uint8_t if_stage_gain_len[] = { - 0, - ARRAY_SIZE(if_stage1_gain), - ARRAY_SIZE(if_stage23_gain), - ARRAY_SIZE(if_stage23_gain), - ARRAY_SIZE(if_stage4_gain), - ARRAY_SIZE(if_stage56_gain), - ARRAY_SIZE(if_stage56_gain) -}; - -static const struct reg_field if_stage_gain_regs[] = { - { 0, 0, 0 }, - { E4K_REG_GAIN3, 0, 1 }, - { E4K_REG_GAIN3, 1, 2 }, - { E4K_REG_GAIN3, 3, 2 }, - { E4K_REG_GAIN3, 5, 2 }, - { E4K_REG_GAIN4, 0, 3 }, - { E4K_REG_GAIN4, 3, 3 } -}; - -static const int32_t lnagain[] = { - -50, 0, - -25, 1, - 0, 4, - 25, 5, - 50, 6, - 75, 7, - 100, 8, - 125, 9, - 150, 10, - 175, 11, - 200, 12, - 250, 13, - 300, 14, -}; - -static const int32_t enhgain[] = { - 10, 30, 50, 70 -}; - -int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain) -{ - uint32_t i; - for(i = 0; i < ARRAY_SIZE(lnagain)/2; ++i) { - if(lnagain[i*2] == gain) { - e4k_reg_set_mask(e4k, E4K_REG_GAIN1, 0xf, lnagain[i*2+1]); - return gain; - } - } - return -EINVAL; -} - -int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain) -{ - uint32_t i; - for(i = 0; i < ARRAY_SIZE(enhgain); ++i) { - if(enhgain[i] == gain) { - e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, E4K_AGC11_LNA_GAIN_ENH | (i << 1)); - return gain; - } - } - e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0); - - /* special case: 0 = off*/ - if(0 == gain) - return 0; - else - return -EINVAL; -} - -int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual) -{ - if (manual) { - /* Set LNA mode to manual */ - e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_SERIAL); - - /* Set Mixer Gain Control to manual */ - e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0); - } else { - /* Set LNA mode to auto */ - e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, E4K_AGC_MOD_IF_SERIAL_LNA_AUTON); - /* Set Mixer Gain Control to auto */ - e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 1); - - e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, 0); - } - - return 0; -} - -static int find_stage_gain(uint8_t stage, int8_t val) -{ - const int8_t *arr; - int i; - - if (stage >= ARRAY_SIZE(if_stage_gain)) - return -EINVAL; - - arr = if_stage_gain[stage]; - - for (i = 0; i < if_stage_gain_len[stage]; i++) { - if (arr[i] == val) - return i; - } - return -EINVAL; -} - -/*! \brief Set the gain of one of the IF gain stages - * \param [e4k] handle to the tuner chip - * \param [stage] number of the stage (1..6) - * \param [value] gain value in dB - * \returns 0 on success, negative in case of error - */ -int e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value) -{ - int rc; - uint8_t mask; - const struct reg_field *field; - - rc = find_stage_gain(stage, value); - if (rc < 0) - return rc; - - /* compute the bit-mask for the given gain field */ - field = &if_stage_gain_regs[stage]; - mask = width2mask[field->width] << field->shift; - - return e4k_reg_set_mask(e4k, field->reg, mask, rc << field->shift); -} - -int e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value) -{ - uint8_t bit; - - switch (value) { - case 4: - bit = 0; - break; - case 12: - bit = 1; - break; - default: - return -EINVAL; - } - - return e4k_reg_set_mask(e4k, E4K_REG_GAIN2, 1, bit); -} - -int e4k_commonmode_set(struct e4k_state *e4k, int8_t value) -{ - if(value < 0) - return -EINVAL; - else if(value > 7) - return -EINVAL; - - return e4k_reg_set_mask(e4k, E4K_REG_DC7, 7, value); -} - -/*********************************************************************** - * DC Offset */ - -int e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange) -{ - int res; - - if((iofs < 0x00) || (iofs > 0x3f)) - return -EINVAL; - if((irange < 0x00) || (irange > 0x03)) - return -EINVAL; - if((qofs < 0x00) || (qofs > 0x3f)) - return -EINVAL; - if((qrange < 0x00) || (qrange > 0x03)) - return -EINVAL; - - res = e4k_reg_set_mask(e4k, E4K_REG_DC2, 0x3f, iofs); - if(res < 0) - return res; - - res = e4k_reg_set_mask(e4k, E4K_REG_DC3, 0x3f, qofs); - if(res < 0) - return res; - - res = e4k_reg_set_mask(e4k, E4K_REG_DC4, 0x33, (qrange << 4) | irange); - return res; -} - -/*! \brief Perform a DC offset calibration right now - * \param [e4k] handle to the tuner chip - */ -int e4k_dc_offset_calibrate(struct e4k_state *e4k) -{ - /* make sure the DC range detector is enabled */ - e4k_reg_set_mask(e4k, E4K_REG_DC5, E4K_DC5_RANGE_DET_EN, E4K_DC5_RANGE_DET_EN); - - return e4k_reg_write(e4k, E4K_REG_DC1, 0x01); -} - - -static const int8_t if_gains_max[] = { - 0, 6, 9, 9, 2, 15, 15 -}; - -struct gain_comb { - int8_t mixer_gain; - int8_t if1_gain; - uint8_t reg; -}; - -static const struct gain_comb dc_gain_comb[] = { - { 4, -3, 0x50 }, - { 4, 6, 0x51 }, - { 12, -3, 0x52 }, - { 12, 6, 0x53 }, -}; - -#define TO_LUT(offset, range) (offset | (range << 6)) - -int e4k_dc_offset_gen_table(struct e4k_state *e4k) -{ - uint32_t i; - - /* FIXME: read ont current gain values and write them back - * before returning to the caller */ - - /* disable auto mixer gain */ - e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0); - - /* set LNA/IF gain to full manual */ - e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, - E4K_AGC_MOD_SERIAL); - - /* set all 'other' gains to maximum */ - for (i = 2; i <= 6; i++) - e4k_if_gain_set(e4k, i, if_gains_max[i]); - - /* iterate over all mixer + if_stage_1 gain combinations */ - for (i = 0; i < ARRAY_SIZE(dc_gain_comb); i++) { - uint8_t offs_i, offs_q, range, range_i, range_q; - - /* set the combination of mixer / if1 gain */ - e4k_mixer_gain_set(e4k, dc_gain_comb[i].mixer_gain); - e4k_if_gain_set(e4k, 1, dc_gain_comb[i].if1_gain); - - /* perform actual calibration */ - e4k_dc_offset_calibrate(e4k); - - /* extract I/Q offset and range values */ - offs_i = e4k_reg_read(e4k, E4K_REG_DC2) & 0x3f; - offs_q = e4k_reg_read(e4k, E4K_REG_DC3) & 0x3f; - range = e4k_reg_read(e4k, E4K_REG_DC4); - range_i = range & 0x3; - range_q = (range >> 4) & 0x3; - - fprintf(stderr, "[E4K] Table %u I=%u/%u, Q=%u/%u\n", - i, range_i, offs_i, range_q, offs_q); - - /* write into the table */ - e4k_reg_write(e4k, dc_gain_comb[i].reg, - TO_LUT(offs_q, range_q)); - e4k_reg_write(e4k, dc_gain_comb[i].reg + 0x10, - TO_LUT(offs_i, range_i)); - } - - return 0; -} - -/*********************************************************************** - * Standby */ - -/*! \brief Enable/disable standby mode - */ -int e4k_standby(struct e4k_state *e4k, int enable) -{ - e4k_reg_set_mask(e4k, E4K_REG_MASTER1, E4K_MASTER1_NORM_STBY, - enable ? 0 : E4K_MASTER1_NORM_STBY); - - return 0; -} - -/*********************************************************************** - * Initialization */ - -static int magic_init(struct e4k_state *e4k) -{ - e4k_reg_write(e4k, 0x7e, 0x01); - e4k_reg_write(e4k, 0x7f, 0xfe); - e4k_reg_write(e4k, 0x82, 0x00); - e4k_reg_write(e4k, 0x86, 0x50); /* polarity A */ - e4k_reg_write(e4k, 0x87, 0x20); - e4k_reg_write(e4k, 0x88, 0x01); - e4k_reg_write(e4k, 0x9f, 0x7f); - e4k_reg_write(e4k, 0xa0, 0x07); - - return 0; -} - -/*! \brief Initialize the E4K tuner - */ -int e4k_init(struct e4k_state *e4k) -{ - /* make a dummy i2c read or write command, will not be ACKed! */ - e4k_reg_read(e4k, 0); - - /* Make sure we reset everything and clear POR indicator */ - e4k_reg_write(e4k, E4K_REG_MASTER1, - E4K_MASTER1_RESET | - E4K_MASTER1_NORM_STBY | - E4K_MASTER1_POR_DET - ); - - /* Configure clock input */ - e4k_reg_write(e4k, E4K_REG_CLK_INP, 0x00); - - /* Disable clock output */ - e4k_reg_write(e4k, E4K_REG_REF_CLK, 0x00); - e4k_reg_write(e4k, E4K_REG_CLKOUT_PWDN, 0x96); - - /* Write some magic values into registers */ - magic_init(e4k); -#if 0 - /* Set common mode voltage a bit higher for more margin 850 mv */ - e4k_commonmode_set(e4k, 4); - - /* Initialize DC offset lookup tables */ - e4k_dc_offset_gen_table(e4k); - - /* Enable time variant DC correction */ - e4k_reg_write(e4k, E4K_REG_DCTIME1, 0x01); - e4k_reg_write(e4k, E4K_REG_DCTIME2, 0x01); -#endif - - /* Set LNA mode to manual */ - e4k_reg_write(e4k, E4K_REG_AGC4, 0x10); /* High threshold */ - e4k_reg_write(e4k, E4K_REG_AGC5, 0x04); /* Low threshold */ - e4k_reg_write(e4k, E4K_REG_AGC6, 0x1a); /* LNA calib + loop rate */ - - e4k_reg_set_mask(e4k, E4K_REG_AGC1, E4K_AGC1_MOD_MASK, - E4K_AGC_MOD_SERIAL); - - /* Set Mixer Gain Control to manual */ - e4k_reg_set_mask(e4k, E4K_REG_AGC7, E4K_AGC7_MIX_GAIN_AUTO, 0); - -#if 0 - /* Enable LNA Gain enhancement */ - e4k_reg_set_mask(e4k, E4K_REG_AGC11, 0x7, - E4K_AGC11_LNA_GAIN_ENH | (2 << 1)); - - /* Enable automatic IF gain mode switching */ - e4k_reg_set_mask(e4k, E4K_REG_AGC8, 0x1, E4K_AGC8_SENS_LIN_AUTO); -#endif - - /* Use auto-gain as default */ - e4k_enable_manual_gain(e4k, 0); - - /* Select moderate gain levels */ - e4k_if_gain_set(e4k, 1, 6); - e4k_if_gain_set(e4k, 2, 0); - e4k_if_gain_set(e4k, 3, 0); - e4k_if_gain_set(e4k, 4, 0); - e4k_if_gain_set(e4k, 5, 9); - e4k_if_gain_set(e4k, 6, 9); - - /* Set the most narrow filter we can possibly use */ - e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_MIX, KHZ(1900)); - e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_RC, KHZ(1000)); - e4k_if_filter_bw_set(e4k, E4K_IF_FILTER_CHAN, KHZ(2150)); - e4k_if_filter_chan_enable(e4k, 1); - - /* Disable time variant DC correction and LUT */ - e4k_reg_set_mask(e4k, E4K_REG_DC5, 0x03, 0); - e4k_reg_set_mask(e4k, E4K_REG_DCTIME1, 0x03, 0); - e4k_reg_set_mask(e4k, E4K_REG_DCTIME2, 0x03, 0); - - return 0; -} diff --git a/src/tuner_fc0012.c b/src/tuner_fc0012.c deleted file mode 100644 index 768cf1c..0000000 --- a/src/tuner_fc0012.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include "rtlsdr_i2c.h" -#include "tuner_fc0012.h" - -static int fc0012_writereg(void *dev, uint8_t reg, uint8_t val) -{ - uint8_t data[2]; - data[0] = reg; - data[1] = val; - - 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: - * - * Name Reg Bits Desc - * CHIP_ID 0x00 0-7 Chip ID (constant 0xA1) - * RF_A 0x01 0-3 Number of count-to-9 cycles in RF - * divider (suggested: 2..9) - * RF_M 0x02 0-7 Total number of cycles (to-8 and to-9) - * in RF divider - * RF_K_HIGH 0x03 0-6 Bits 8..14 of fractional divider - * RF_K_LOW 0x04 0-7 Bits 0..7 of fractional RF divider - * 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 - * 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) - * BANDWIDTH 0x06 6-7 Set bandwidth. 6MHz = 0x80, 7MHz=0x40 - * 8MHz=0x00 - * XTAL_SPEED 0x07 5 Set to 1 for 28.8MHz Crystal input - * or 0 for 36MHz - * 0x08 0-7 - * EN_CAL_RSSI 0x09 4 Enable calibrate RSSI - * (Receive Signal Strength Indicator) - * LNA_FORCE 0x0d 0 - * AGC_FORCE 0x0d ? - * LNA_GAIN 0x13 3-4 Low noise amp gain - * LNA_COMPS 0x15 3 ? - * VCO_CALIB 0x0e 7 Set high then low to calibrate VCO - * (fast lock?) - * VCO_VOLTAGE 0x0e 0-6 Read Control voltage of VCO - * (big value -> low freq) - */ - -int fc0012_init(void *dev) -{ - 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 */ - }; - -#if 0 - 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 - reg[0x07] |= 0x20; - -// if (priv->dual_master) - reg[0x0c] |= 0x02; - - for (i = 1; i < sizeof(reg); i++) { - ret = fc0012_writereg(dev, i, reg[i]); - if (ret) - break; - } - - return ret; -} - -int fc0012_set_params(void *dev, uint32_t freq, uint32_t bandwidth) -{ - 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; - - xtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2; - - /* 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 { - multi = 4; - reg[5] = 0x0a; - reg[6] = 0x02; - } - - f_vco = freq * multi; - - if (f_vco >= 3060000000U) { - reg[6] |= 0x08; - vco_select = 1; - } - - /* 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++; - - pm = (uint8_t)(xdiv / 8); - am = (uint8_t)(xdiv - (8 * pm)); - - if (am < 2) { - am += 8; - pm--; - } - - if (pm > 31) { - reg[1] = am + (8 * (pm - 31)); - reg[2] = 31; - } else { - reg[1] = am; - reg[2] = pm; - } - - if ((reg[1] > 15) || (reg[2] < 0x0b)) { - fprintf(stderr, "[FC0012] no valid PLL combination " - "found for %u Hz!\n", freq); - 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); - } - } - -exit: - return ret; -} - -int fc0012_set_gain(void *dev, int gain) -{ - int ret; - uint8_t tmp = 0; - - ret = fc0012_readreg(dev, 0x13, &tmp); - - /* mask bits off */ - tmp &= 0xe0; - - switch (gain) { - case -99: /* -9.9 dB */ - tmp |= 0x02; - break; - case -40: /* -4 dB */ - break; - case 71: - tmp |= 0x08; /* 7.1 dB */ - break; - case 179: - tmp |= 0x17; /* 17.9 dB */ - break; - case 192: - default: - tmp |= 0x10; /* 19.2 dB */ - break; - } - - ret = fc0012_writereg(dev, 0x13, tmp); - - return ret; -} diff --git a/src/tuner_fc0013.c b/src/tuner_fc0013.c deleted file mode 100644 index 5984dfb..0000000 --- a/src/tuner_fc0013.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Fitipower FC0013 tuner driver - * - * Copyright (C) 2012 Hans-Frieder Vogt - * partially based on driver code from Fitipower - * Copyright (C) 2010 Fitipower Integrated Technology Inc - * - * 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_fc0013.h" - -static int fc0013_writereg(void *dev, uint8_t reg, uint8_t val) -{ - uint8_t data[2]; - data[0] = reg; - data[1] = val; - - if (rtlsdr_i2c_write_fn(dev, FC0013_I2C_ADDR, data, 2) < 0) - return -1; - - return 0; -} - -static int fc0013_readreg(void *dev, uint8_t reg, uint8_t *val) -{ - uint8_t data = reg; - - if (rtlsdr_i2c_write_fn(dev, FC0013_I2C_ADDR, &data, 1) < 0) - return -1; - - if (rtlsdr_i2c_read_fn(dev, FC0013_I2C_ADDR, &data, 1) < 0) - return -1; - - *val = data; - - return 0; -} - -int fc0013_init(void *dev) -{ - int ret = 0; - unsigned int i; - uint8_t reg[] = { - 0x00, /* reg. 0x00: dummy */ - 0x09, /* reg. 0x01 */ - 0x16, /* reg. 0x02 */ - 0x00, /* reg. 0x03 */ - 0x00, /* reg. 0x04 */ - 0x17, /* reg. 0x05 */ - 0x02, /* reg. 0x06: LPF bandwidth */ - 0x0a, /* reg. 0x07: CHECK */ - 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: CHECK */ - 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ - 0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */ - 0x00, /* reg. 0x0e */ - 0x00, /* reg. 0x0f */ - 0x00, /* reg. 0x10 */ - 0x00, /* reg. 0x11 */ - 0x00, /* reg. 0x12 */ - 0x00, /* reg. 0x13 */ - 0x50, /* reg. 0x14: DVB-t High Gain, UHF. - Middle Gain: 0x48, Low Gain: 0x40 */ - 0x01, /* reg. 0x15 */ - }; -#if 0 - 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 - reg[0x07] |= 0x20; - -// if (dev->dual_master) - reg[0x0c] |= 0x02; - - for (i = 1; i < sizeof(reg); i++) { - ret = fc0013_writereg(dev, i, reg[i]); - if (ret < 0) - break; - } - - return ret; -} - -int fc0013_rc_cal_add(void *dev, int rc_val) -{ - int ret; - uint8_t rc_cal; - int val; - - /* push rc_cal value, get rc_cal value */ - ret = fc0013_writereg(dev, 0x10, 0x00); - if (ret) - goto error_out; - - /* get rc_cal value */ - ret = fc0013_readreg(dev, 0x10, &rc_cal); - if (ret) - goto error_out; - - rc_cal &= 0x0f; - - val = (int)rc_cal + rc_val; - - /* forcing rc_cal */ - ret = fc0013_writereg(dev, 0x0d, 0x11); - if (ret) - goto error_out; - - /* modify rc_cal value */ - if (val > 15) - ret = fc0013_writereg(dev, 0x10, 0x0f); - else if (val < 0) - ret = fc0013_writereg(dev, 0x10, 0x00); - else - ret = fc0013_writereg(dev, 0x10, (uint8_t)val); - -error_out: - return ret; -} - -int fc0013_rc_cal_reset(void *dev) -{ - int ret; - - ret = fc0013_writereg(dev, 0x0d, 0x01); - if (!ret) - ret = fc0013_writereg(dev, 0x10, 0x00); - - return ret; -} - -static int fc0013_set_vhf_track(void *dev, uint32_t freq) -{ - int ret; - uint8_t tmp; - - ret = fc0013_readreg(dev, 0x1d, &tmp); - if (ret) - goto error_out; - tmp &= 0xe3; - if (freq <= 177500000) { /* VHF Track: 7 */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x1c); - } else if (freq <= 184500000) { /* VHF Track: 6 */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x18); - } else if (freq <= 191500000) { /* VHF Track: 5 */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x14); - } else if (freq <= 198500000) { /* VHF Track: 4 */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x10); - } else if (freq <= 205500000) { /* VHF Track: 3 */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x0c); - } else if (freq <= 219500000) { /* VHF Track: 2 */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x08); - } else if (freq < 300000000) { /* VHF Track: 1 */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x04); - } else { /* UHF and GPS */ - ret = fc0013_writereg(dev, 0x1d, tmp | 0x1c); - } - -error_out: - return ret; -} - -int fc0013_set_params(void *dev, uint32_t freq, uint32_t bandwidth) -{ - 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; - - xtal_freq_div_2 = rtlsdr_get_tuner_clock(dev) / 2; - - /* set VHF track */ - ret = fc0013_set_vhf_track(dev, freq); - if (ret) - goto exit; - - if (freq < 300000000) { - /* enable VHF filter */ - ret = fc0013_readreg(dev, 0x07, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(dev, 0x07, tmp | 0x10); - if (ret) - goto exit; - - /* disable UHF & disable GPS */ - ret = fc0013_readreg(dev, 0x14, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(dev, 0x14, tmp & 0x1f); - if (ret) - goto exit; - } else if (freq <= 862000000) { - /* disable VHF filter */ - ret = fc0013_readreg(dev, 0x07, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(dev, 0x07, tmp & 0xef); - if (ret) - goto exit; - - /* enable UHF & disable GPS */ - ret = fc0013_readreg(dev, 0x14, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x40); - if (ret) - goto exit; - } else { - /* disable VHF filter */ - ret = fc0013_readreg(dev, 0x07, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(dev, 0x07, tmp & 0xef); - if (ret) - goto exit; - - /* enable UHF & disable GPS */ - ret = fc0013_readreg(dev, 0x14, &tmp); - if (ret) - goto exit; - ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x40); - if (ret) - goto exit; - } - - /* 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] = 0x02; - 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] = 0x82; - 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] = 0x42; - 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] = 0x22; - reg[6] = 0x02; - } else if (freq < 593334000) { /* freq * 6 < 3560000000 */ - multi = 6; - reg[5] = 0x0a; - reg[6] = 0x00; - } else if (freq < 950000000) { /* freq * 4 < 3800000000 */ - multi = 4; - reg[5] = 0x12; - reg[6] = 0x02; - } else { - multi = 2; - reg[5] = 0x0a; - reg[6] = 0x02; - } - - f_vco = freq * multi; - - if (f_vco >= 3060000000U) { - reg[6] |= 0x08; - vco_select = 1; - } - - /* 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++; - - pm = (uint8_t)(xdiv / 8); - am = (uint8_t)(xdiv - (8 * pm)); - - if (am < 2) { - am += 8; - pm--; - } - - if (pm > 31) { - reg[1] = am + (8 * (pm - 31)); - reg[2] = 31; - } else { - reg[1] = am; - reg[2] = pm; - } - - if ((reg[1] > 15) || (reg[2] < 0x0b)) { - fprintf(stderr, "[FC0013] no valid PLL combination " - "found for %u Hz!\n", freq); - 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; - 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 = fc0013_writereg(dev, i, reg[i]); - if (ret) - goto exit; - } - - ret = fc0013_readreg(dev, 0x11, &tmp); - if (ret) - goto exit; - if (multi == 64) - ret = fc0013_writereg(dev, 0x11, tmp | 0x04); - else - ret = fc0013_writereg(dev, 0x11, tmp & 0xfb); - if (ret) - goto exit; - - /* VCO Calibration */ - ret = fc0013_writereg(dev, 0x0e, 0x80); - if (!ret) - ret = fc0013_writereg(dev, 0x0e, 0x00); - - /* VCO Re-Calibration if needed */ - if (!ret) - ret = fc0013_writereg(dev, 0x0e, 0x00); - - if (!ret) { -// msleep(10); - ret = fc0013_readreg(dev, 0x0e, &tmp); - } - if (ret) - goto exit; - - /* vco selection */ - tmp &= 0x3f; - - if (vco_select) { - if (tmp > 0x3c) { - reg[6] &= ~0x08; - ret = fc0013_writereg(dev, 0x06, reg[6]); - if (!ret) - ret = fc0013_writereg(dev, 0x0e, 0x80); - if (!ret) - ret = fc0013_writereg(dev, 0x0e, 0x00); - } - } else { - if (tmp < 0x02) { - reg[6] |= 0x08; - ret = fc0013_writereg(dev, 0x06, reg[6]); - if (!ret) - ret = fc0013_writereg(dev, 0x0e, 0x80); - if (!ret) - ret = fc0013_writereg(dev, 0x0e, 0x00); - } - } - -exit: - return ret; -} - -int fc0013_set_gain_mode(void *dev, int manual) -{ - int ret = 0; - uint8_t tmp = 0; - - ret |= fc0013_readreg(dev, 0x0d, &tmp); - - if (manual) - tmp |= (1 << 3); - else - tmp &= ~(1 << 3); - - ret |= fc0013_writereg(dev, 0x0d, tmp); - - /* set a fixed IF-gain for now */ - ret |= fc0013_writereg(dev, 0x13, 0x0a); - - return ret; -} - -int fc0013_lna_gains[] ={ - -99, 0x02, - -73, 0x03, - -65, 0x05, - -63, 0x04, - -63, 0x00, - -60, 0x07, - -58, 0x01, - -54, 0x06, - 58, 0x0f, - 61, 0x0e, - 63, 0x0d, - 65, 0x0c, - 67, 0x0b, - 68, 0x0a, - 70, 0x09, - 71, 0x08, - 179, 0x17, - 181, 0x16, - 182, 0x15, - 184, 0x14, - 186, 0x13, - 188, 0x12, - 191, 0x11, - 197, 0x10 -}; - -#define GAIN_CNT (sizeof(fc0013_lna_gains) / sizeof(int) / 2) - -int fc0013_set_lna_gain(void *dev, int gain) -{ - int ret = 0; - unsigned int i; - uint8_t tmp = 0; - - ret |= fc0013_readreg(dev, 0x14, &tmp); - - /* mask bits off */ - tmp &= 0xe0; - - for (i = 0; i < GAIN_CNT; i++) { - if ((fc0013_lna_gains[i*2] >= gain) || (i+1 == GAIN_CNT)) { - tmp |= fc0013_lna_gains[i*2 + 1]; - break; - } - } - - /* set gain */ - ret |= fc0013_writereg(dev, 0x14, tmp); - - return ret; -} diff --git a/src/tuner_fc2580.c b/src/tuner_fc2580.c deleted file mode 100644 index d2eeba5..0000000 --- a/src/tuner_fc2580.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * FCI FC2580 tuner driver, taken from the kernel driver that can be found - * on http://linux.terratec.de/tv_en.html - * - * This driver is a mess, and should be cleaned up/rewritten. - * - */ - -#include - -#include "rtlsdr_i2c.h" -#include "tuner_fc2580.h" - -/* 16.384 MHz (at least on the Logilink VG0002A) */ -#define CRYSTAL_FREQ 16384000 - -/* glue functions to rtl-sdr code */ - -fc2580_fci_result_type fc2580_i2c_write(void *pTuner, unsigned char reg, unsigned char val) -{ - uint8_t data[2]; - - data[0] = reg; - data[1] = val; - - if (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, data, 2) < 0) - return FC2580_FCI_FAIL; - - return FC2580_FCI_SUCCESS; -} - -fc2580_fci_result_type fc2580_i2c_read(void *pTuner, unsigned char reg, unsigned char *read_data) -{ - uint8_t data = reg; - - if (rtlsdr_i2c_write_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0) - return FC2580_FCI_FAIL; - - if (rtlsdr_i2c_read_fn(pTuner, FC2580_I2C_ADDR, &data, 1) < 0) - return FC2580_FCI_FAIL; - - *read_data = data; - - return FC2580_FCI_SUCCESS; -} - -int -fc2580_Initialize( - void *pTuner - ) -{ - int AgcMode; - unsigned int CrystalFreqKhz; - - //TODO set AGC mode - AgcMode = FC2580_AGC_EXTERNAL; - - // Initialize tuner with AGC mode. - // Note: CrystalFreqKhz = round(CrystalFreqHz / 1000) - CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000); - - if(fc2580_set_init(pTuner, AgcMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS) - goto error_status_initialize_tuner; - - - return FUNCTION_SUCCESS; - - -error_status_initialize_tuner: - return FUNCTION_ERROR; -} - -int -fc2580_SetRfFreqHz( - void *pTuner, - unsigned long RfFreqHz - ) -{ - unsigned int RfFreqKhz; - unsigned int CrystalFreqKhz; - - // Set tuner RF frequency in KHz. - // Note: RfFreqKhz = round(RfFreqHz / 1000) - // CrystalFreqKhz = round(CrystalFreqHz / 1000) - RfFreqKhz = (unsigned int)((RfFreqHz + 500) / 1000); - CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000); - - if(fc2580_set_freq(pTuner, RfFreqKhz, CrystalFreqKhz) != FC2580_FCI_SUCCESS) - goto error_status_set_tuner_rf_frequency; - - return FUNCTION_SUCCESS; - -error_status_set_tuner_rf_frequency: - return FUNCTION_ERROR; -} - -/** - -@brief Set FC2580 tuner bandwidth mode. - -*/ -int -fc2580_SetBandwidthMode( - void *pTuner, - int BandwidthMode - ) -{ - unsigned int CrystalFreqKhz; - - // Set tuner bandwidth mode. - // Note: CrystalFreqKhz = round(CrystalFreqHz / 1000) - CrystalFreqKhz = (unsigned int)((CRYSTAL_FREQ + 500) / 1000); - - if(fc2580_set_filter(pTuner, (unsigned char)BandwidthMode, CrystalFreqKhz) != FC2580_FCI_SUCCESS) - goto error_status_set_tuner_bandwidth_mode; - - return FUNCTION_SUCCESS; - - -error_status_set_tuner_bandwidth_mode: - return FUNCTION_ERROR; -} - -void fc2580_wait_msec(void *pTuner, int a) -{ - /* USB latency is enough for now ;) */ -// usleep(a * 1000); - return; -} - -/*============================================================================== - fc2580 initial setting - - This function is a generic function which gets called to initialize - - fc2580 in DVB-H mode or L-Band TDMB mode - - - - ifagc_mode - type : integer - 1 : Internal AGC - 2 : Voltage Control Mode - -==============================================================================*/ -fc2580_fci_result_type fc2580_set_init( void *pTuner, int ifagc_mode, unsigned int freq_xtal ) -{ - fc2580_fci_result_type result = FC2580_FCI_SUCCESS; - - result &= fc2580_i2c_write(pTuner, 0x00, 0x00); /*** Confidential ***/ - result &= fc2580_i2c_write(pTuner, 0x12, 0x86); - result &= fc2580_i2c_write(pTuner, 0x14, 0x5C); - result &= fc2580_i2c_write(pTuner, 0x16, 0x3C); - result &= fc2580_i2c_write(pTuner, 0x1F, 0xD2); - result &= fc2580_i2c_write(pTuner, 0x09, 0xD7); - result &= fc2580_i2c_write(pTuner, 0x0B, 0xD5); - result &= fc2580_i2c_write(pTuner, 0x0C, 0x32); - result &= fc2580_i2c_write(pTuner, 0x0E, 0x43); - result &= fc2580_i2c_write(pTuner, 0x21, 0x0A); - result &= fc2580_i2c_write(pTuner, 0x22, 0x82); - if( ifagc_mode == 1 ) - { - result &= fc2580_i2c_write(pTuner, 0x45, 0x10); //internal AGC - result &= fc2580_i2c_write(pTuner, 0x4C, 0x00); //HOLD_AGC polarity - } - else if( ifagc_mode == 2 ) - { - result &= fc2580_i2c_write(pTuner, 0x45, 0x20); //Voltage Control Mode - result &= fc2580_i2c_write(pTuner, 0x4C, 0x02); //HOLD_AGC polarity - } - result &= fc2580_i2c_write(pTuner, 0x3F, 0x88); - result &= fc2580_i2c_write(pTuner, 0x02, 0x0E); - result &= fc2580_i2c_write(pTuner, 0x58, 0x14); - result &= fc2580_set_filter(pTuner, 8, freq_xtal); //BW = 7.8MHz - - return result; -} - - -/*============================================================================== - fc2580 frequency setting - - This function is a generic function which gets called to change LO Frequency - - of fc2580 in DVB-H mode or L-Band TDMB mode - - - freq_xtal: kHz - - f_lo - Value of target LO Frequency in 'kHz' unit - ex) 2.6GHz = 2600000 - -==============================================================================*/ -fc2580_fci_result_type fc2580_set_freq( void *pTuner, unsigned int f_lo, unsigned int freq_xtal ) -{ - unsigned int f_diff, f_diff_shifted, n_val, k_val; - unsigned int f_vco, r_val, f_comp; - unsigned char pre_shift_bits = 4;// number of preshift to prevent overflow in shifting f_diff to f_diff_shifted - unsigned char data_0x18; - unsigned char data_0x02 = (USE_EXT_CLK<<5)|0x0E; - - fc2580_band_type band = ( f_lo > 1000000 )? FC2580_L_BAND : ( f_lo > 400000 )? FC2580_UHF_BAND : FC2580_VHF_BAND; - - fc2580_fci_result_type result = FC2580_FCI_SUCCESS; - - f_vco = ( band == FC2580_UHF_BAND )? f_lo * 4 : (( band == FC2580_L_BAND )? f_lo * 2 : f_lo * 12); - r_val = ( f_vco >= 2*76*freq_xtal )? 1 : ( f_vco >= 76*freq_xtal )? 2 : 4; - f_comp = freq_xtal/r_val; - n_val = ( f_vco / 2 ) / f_comp; - - f_diff = f_vco - 2* f_comp * n_val; - f_diff_shifted = f_diff << ( 20 - pre_shift_bits ); - k_val = f_diff_shifted / ( ( 2* f_comp ) >> pre_shift_bits ); - - if( f_diff_shifted - k_val * ( ( 2* f_comp ) >> pre_shift_bits ) >= ( f_comp >> pre_shift_bits ) ) - k_val = k_val + 1; - - if( f_vco >= BORDER_FREQ ) //Select VCO Band - data_0x02 = data_0x02 | 0x08; //0x02[3] = 1; - else - data_0x02 = data_0x02 & 0xF7; //0x02[3] = 0; - -// if( band != curr_band ) { - switch(band) - { - case FC2580_UHF_BAND: - data_0x02 = (data_0x02 & 0x3F); - - result &= fc2580_i2c_write(pTuner, 0x25, 0xF0); - result &= fc2580_i2c_write(pTuner, 0x27, 0x77); - result &= fc2580_i2c_write(pTuner, 0x28, 0x53); - result &= fc2580_i2c_write(pTuner, 0x29, 0x60); - result &= fc2580_i2c_write(pTuner, 0x30, 0x09); - result &= fc2580_i2c_write(pTuner, 0x50, 0x8C); - result &= fc2580_i2c_write(pTuner, 0x53, 0x50); - - if( f_lo < 538000 ) - result &= fc2580_i2c_write(pTuner, 0x5F, 0x13); - else - result &= fc2580_i2c_write(pTuner, 0x5F, 0x15); - - if( f_lo < 538000 ) - { - result &= fc2580_i2c_write(pTuner, 0x61, 0x07); - result &= fc2580_i2c_write(pTuner, 0x62, 0x06); - result &= fc2580_i2c_write(pTuner, 0x67, 0x06); - result &= fc2580_i2c_write(pTuner, 0x68, 0x08); - result &= fc2580_i2c_write(pTuner, 0x69, 0x10); - result &= fc2580_i2c_write(pTuner, 0x6A, 0x12); - } - else if( f_lo < 794000 ) - { - result &= fc2580_i2c_write(pTuner, 0x61, 0x03); - result &= fc2580_i2c_write(pTuner, 0x62, 0x03); - result &= fc2580_i2c_write(pTuner, 0x67, 0x03); //ACI improve - result &= fc2580_i2c_write(pTuner, 0x68, 0x05); //ACI improve - result &= fc2580_i2c_write(pTuner, 0x69, 0x0C); - result &= fc2580_i2c_write(pTuner, 0x6A, 0x0E); - } - else - { - result &= fc2580_i2c_write(pTuner, 0x61, 0x07); - result &= fc2580_i2c_write(pTuner, 0x62, 0x06); - result &= fc2580_i2c_write(pTuner, 0x67, 0x07); - result &= fc2580_i2c_write(pTuner, 0x68, 0x09); - result &= fc2580_i2c_write(pTuner, 0x69, 0x10); - result &= fc2580_i2c_write(pTuner, 0x6A, 0x12); - } - - result &= fc2580_i2c_write(pTuner, 0x63, 0x15); - - result &= fc2580_i2c_write(pTuner, 0x6B, 0x0B); - result &= fc2580_i2c_write(pTuner, 0x6C, 0x0C); - result &= fc2580_i2c_write(pTuner, 0x6D, 0x78); - result &= fc2580_i2c_write(pTuner, 0x6E, 0x32); - result &= fc2580_i2c_write(pTuner, 0x6F, 0x14); - result &= fc2580_set_filter(pTuner, 8, freq_xtal); //BW = 7.8MHz - break; - case FC2580_VHF_BAND: - data_0x02 = (data_0x02 & 0x3F) | 0x80; - result &= fc2580_i2c_write(pTuner, 0x27, 0x77); - result &= fc2580_i2c_write(pTuner, 0x28, 0x33); - result &= fc2580_i2c_write(pTuner, 0x29, 0x40); - result &= fc2580_i2c_write(pTuner, 0x30, 0x09); - result &= fc2580_i2c_write(pTuner, 0x50, 0x8C); - result &= fc2580_i2c_write(pTuner, 0x53, 0x50); - result &= fc2580_i2c_write(pTuner, 0x5F, 0x0F); - result &= fc2580_i2c_write(pTuner, 0x61, 0x07); - result &= fc2580_i2c_write(pTuner, 0x62, 0x00); - result &= fc2580_i2c_write(pTuner, 0x63, 0x15); - result &= fc2580_i2c_write(pTuner, 0x67, 0x03); - result &= fc2580_i2c_write(pTuner, 0x68, 0x05); - result &= fc2580_i2c_write(pTuner, 0x69, 0x10); - result &= fc2580_i2c_write(pTuner, 0x6A, 0x12); - result &= fc2580_i2c_write(pTuner, 0x6B, 0x08); - result &= fc2580_i2c_write(pTuner, 0x6C, 0x0A); - result &= fc2580_i2c_write(pTuner, 0x6D, 0x78); - result &= fc2580_i2c_write(pTuner, 0x6E, 0x32); - result &= fc2580_i2c_write(pTuner, 0x6F, 0x54); - result &= fc2580_set_filter(pTuner, 7, freq_xtal); //BW = 6.8MHz - break; - case FC2580_L_BAND: - data_0x02 = (data_0x02 & 0x3F) | 0x40; - result &= fc2580_i2c_write(pTuner, 0x2B, 0x70); - result &= fc2580_i2c_write(pTuner, 0x2C, 0x37); - result &= fc2580_i2c_write(pTuner, 0x2D, 0xE7); - result &= fc2580_i2c_write(pTuner, 0x30, 0x09); - result &= fc2580_i2c_write(pTuner, 0x44, 0x20); - result &= fc2580_i2c_write(pTuner, 0x50, 0x8C); - result &= fc2580_i2c_write(pTuner, 0x53, 0x50); - result &= fc2580_i2c_write(pTuner, 0x5F, 0x0F); - result &= fc2580_i2c_write(pTuner, 0x61, 0x0F); - result &= fc2580_i2c_write(pTuner, 0x62, 0x00); - result &= fc2580_i2c_write(pTuner, 0x63, 0x13); - result &= fc2580_i2c_write(pTuner, 0x67, 0x00); - result &= fc2580_i2c_write(pTuner, 0x68, 0x02); - result &= fc2580_i2c_write(pTuner, 0x69, 0x0C); - result &= fc2580_i2c_write(pTuner, 0x6A, 0x0E); - result &= fc2580_i2c_write(pTuner, 0x6B, 0x08); - result &= fc2580_i2c_write(pTuner, 0x6C, 0x0A); - result &= fc2580_i2c_write(pTuner, 0x6D, 0xA0); - result &= fc2580_i2c_write(pTuner, 0x6E, 0x50); - result &= fc2580_i2c_write(pTuner, 0x6F, 0x14); - result &= fc2580_set_filter(pTuner, 1, freq_xtal); //BW = 1.53MHz - break; - default: - break; - } -// curr_band = band; -// } - - //A command about AGC clock's pre-divide ratio - if( freq_xtal >= 28000 ) - result &= fc2580_i2c_write(pTuner, 0x4B, 0x22 ); - - //Commands about VCO Band and PLL setting. - result &= fc2580_i2c_write(pTuner, 0x02, data_0x02); - data_0x18 = ( ( r_val == 1 )? 0x00 : ( ( r_val == 2 )? 0x10 : 0x20 ) ) + (unsigned char)(k_val >> 16); - result &= fc2580_i2c_write(pTuner, 0x18, data_0x18); //Load 'R' value and high part of 'K' values - result &= fc2580_i2c_write(pTuner, 0x1A, (unsigned char)( k_val >> 8 ) ); //Load middle part of 'K' value - result &= fc2580_i2c_write(pTuner, 0x1B, (unsigned char)( k_val ) ); //Load lower part of 'K' value - result &= fc2580_i2c_write(pTuner, 0x1C, (unsigned char)( n_val ) ); //Load 'N' value - - //A command about UHF LNA Load Cap - if( band == FC2580_UHF_BAND ) - result &= fc2580_i2c_write(pTuner, 0x2D, ( f_lo <= (unsigned int)794000 )? 0x9F : 0x8F ); //LNA_OUT_CAP - - - return result; -} - - -/*============================================================================== - fc2580 filter BW setting - - This function is a generic function which gets called to change Bandwidth - - frequency of fc2580's channel selection filter - - - freq_xtal: kHz - - filter_bw - 1 : 1.53MHz(TDMB) - 6 : 6MHz (Bandwidth 6MHz) - 7 : 6.8MHz (Bandwidth 7MHz) - 8 : 7.8MHz (Bandwidth 8MHz) - - -==============================================================================*/ -fc2580_fci_result_type fc2580_set_filter( void *pTuner, unsigned char filter_bw, unsigned int freq_xtal ) -{ - unsigned char cal_mon = 0, i; - fc2580_fci_result_type result = FC2580_FCI_SUCCESS; - - if(filter_bw == 1) - { - result &= fc2580_i2c_write(pTuner, 0x36, 0x1C); - result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4151*freq_xtal/1000000) ); - result &= fc2580_i2c_write(pTuner, 0x39, 0x00); - result &= fc2580_i2c_write(pTuner, 0x2E, 0x09); - } - if(filter_bw == 6) - { - result &= fc2580_i2c_write(pTuner, 0x36, 0x18); - result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(4400*freq_xtal/1000000) ); - result &= fc2580_i2c_write(pTuner, 0x39, 0x00); - result &= fc2580_i2c_write(pTuner, 0x2E, 0x09); - } - else if(filter_bw == 7) - { - result &= fc2580_i2c_write(pTuner, 0x36, 0x18); - result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3910*freq_xtal/1000000) ); - result &= fc2580_i2c_write(pTuner, 0x39, 0x80); - result &= fc2580_i2c_write(pTuner, 0x2E, 0x09); - } - else if(filter_bw == 8) - { - result &= fc2580_i2c_write(pTuner, 0x36, 0x18); - result &= fc2580_i2c_write(pTuner, 0x37, (unsigned char)(3300*freq_xtal/1000000) ); - result &= fc2580_i2c_write(pTuner, 0x39, 0x80); - result &= fc2580_i2c_write(pTuner, 0x2E, 0x09); - } - - - for(i=0; i<5; i++) - { - fc2580_wait_msec(pTuner, 5);//wait 5ms - result &= fc2580_i2c_read(pTuner, 0x2F, &cal_mon); - if( (cal_mon & 0xC0) != 0xC0) - { - result &= fc2580_i2c_write(pTuner, 0x2E, 0x01); - result &= fc2580_i2c_write(pTuner, 0x2E, 0x09); - } - else - break; - } - - result &= fc2580_i2c_write(pTuner, 0x2E, 0x01); - - return result; -} - -/*============================================================================== - fc2580 RSSI function - - This function is a generic function which returns fc2580's - - current RSSI value. - - - none - - - int - rssi : estimated input power. - -==============================================================================*/ -//int fc2580_get_rssi(void) { -// -// unsigned char s_lna, s_rfvga, s_cfs, s_ifvga; -// int ofs_lna, ofs_rfvga, ofs_csf, ofs_ifvga, rssi; -// -// fc2580_i2c_read(0x71, &s_lna ); -// fc2580_i2c_read(0x72, &s_rfvga ); -// fc2580_i2c_read(0x73, &s_cfs ); -// fc2580_i2c_read(0x74, &s_ifvga ); -// -// -// ofs_lna = -// (curr_band==FC2580_UHF_BAND)? -// (s_lna==0)? 0 : -// (s_lna==1)? -6 : -// (s_lna==2)? -17 : -// (s_lna==3)? -22 : -30 : -// (curr_band==FC2580_VHF_BAND)? -// (s_lna==0)? 0 : -// (s_lna==1)? -6 : -// (s_lna==2)? -19 : -// (s_lna==3)? -24 : -32 : -// (curr_band==FC2580_L_BAND)? -// (s_lna==0)? 0 : -// (s_lna==1)? -6 : -// (s_lna==2)? -11 : -// (s_lna==3)? -16 : -34 : -// 0;//FC2580_NO_BAND -// ofs_rfvga = -s_rfvga+((s_rfvga>=11)? 1 : 0) + ((s_rfvga>=18)? 1 : 0); -// ofs_csf = -6*s_cfs; -// ofs_ifvga = s_ifvga/4; -// -// return rssi = ofs_lna+ofs_rfvga+ofs_csf+ofs_ifvga+OFS_RSSI; -// -//} - -/*============================================================================== - fc2580 Xtal frequency Setting - - This function is a generic function which sets - - the frequency of xtal. - - - - frequency - frequency value of internal(external) Xtal(clock) in kHz unit. - -==============================================================================*/ -//void fc2580_set_freq_xtal(unsigned int frequency) { -// -// freq_xtal = frequency; -// -//} - -- cgit v1.2.3