aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Markgraf <steve@steve-m.de>2012-05-04 23:02:29 +0200
committerSteve Markgraf <steve@steve-m.de>2012-05-04 23:02:29 +0200
commit86c34428aabebc79ac0de7f1194e6b755a6fa213 (patch)
tree55aa08354560202e781846298d8f69de0acec531
parent0af094070f3aaf7f0394523025c61b0aaf25f2b6 (diff)
use new E4000 tuner driver, allow manual gain
Many thanks to Hoernchen for making the driver work properly and adding manual gain! Signed-off-by: Steve Markgraf <steve@steve-m.de>
-rw-r--r--include/Makefile.am2
-rw-r--r--include/reg_field.h60
-rw-r--r--include/rtl-sdr.h2
-rw-r--r--include/tuner_e4000.h129
-rw-r--r--include/tuner_e4k.h219
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Makefile.am2
-rw-r--r--src/rtl-sdr.c98
-rw-r--r--src/rtl_tcp.c7
-rw-r--r--src/tuner_e4000.c2067
-rw-r--r--src/tuner_e4k.c955
11 files changed, 1328 insertions, 2217 deletions
diff --git a/include/Makefile.am b/include/Makefile.am
index 0caf762..1fcc60c 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,5 +1,5 @@
rtlsdr_HEADERS = rtl-sdr.h rtl-sdr_export.h
-noinst_HEADERS = rtlsdr_i2c.h tuner_e4000.h tuner_fc0012.h tuner_fc0013.h tuner_fc2580.h
+noinst_HEADERS = rtlsdr_i2c.h tuner_e4k.h tuner_fc0012.h tuner_fc0013.h tuner_fc2580.h
rtlsdrdir = $(includedir)
diff --git a/include/reg_field.h b/include/reg_field.h
new file mode 100644
index 0000000..18a6922
--- /dev/null
+++ b/include/reg_field.h
@@ -0,0 +1,60 @@
+#ifndef _REG_FIELD_H
+#define _REG_FIELD_H
+
+#include <stdint.h>
+#include <stdarg.h>
+
+enum cmd_op {
+ CMD_OP_GET = (1 << 0),
+ CMD_OP_SET = (1 << 1),
+ CMD_OP_EXEC = (1 << 2),
+};
+
+enum pstate {
+ ST_IN_CMD,
+ ST_IN_ARG,
+};
+
+struct strbuf {
+ uint8_t idx;
+ char buf[32];
+};
+
+struct cmd_state {
+ struct strbuf cmd;
+ struct strbuf arg;
+ enum pstate state;
+ void (*out)(const char *format, va_list ap);
+};
+
+struct cmd {
+ const char *cmd;
+ uint32_t ops;
+ int (*cb)(struct cmd_state *cs, enum cmd_op op, const char *cmd,
+ int argc, char **argv);
+ const char *help;
+};
+
+/* structure describing a field in a register */
+struct reg_field {
+ uint8_t reg;
+ uint8_t shift;
+ uint8_t width;
+};
+
+struct reg_field_ops {
+ const struct reg_field *fields;
+ const char **field_names;
+ uint32_t num_fields;
+ void *data;
+ int (*write_cb)(void *data, uint32_t reg, uint32_t val);
+ uint32_t (*read_cb)(void *data, uint32_t reg);
+};
+
+uint32_t reg_field_read(struct reg_field_ops *ops, struct reg_field *field);
+int reg_field_write(struct reg_field_ops *ops, struct reg_field *field, uint32_t val);
+int reg_field_cmd(struct cmd_state *cs, enum cmd_op op,
+ const char *cmd, int argc, char **argv,
+ struct reg_field_ops *ops);
+
+#endif
diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h
index e5b3f75..9688bda 100644
--- a/include/rtl-sdr.h
+++ b/include/rtl-sdr.h
@@ -87,6 +87,8 @@ RTLSDR_API int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain);
RTLSDR_API int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev);
+RTLSDR_API int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int manual);
+
/* this will select the baseband filters according to the requested sample rate */
RTLSDR_API int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t rate);
diff --git a/include/tuner_e4000.h b/include/tuner_e4000.h
deleted file mode 100644
index 5aa71f5..0000000
--- a/include/tuner_e4000.h
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef __TUNER_E4000_H
-#define __TUNER_E4000_H
-
-// Definition (implemeted for E4000)
-#define E4000_1_SUCCESS 1
-#define E4000_1_FAIL 0
-#define E4000_I2C_SUCCESS 1
-#define E4000_I2C_FAIL 0
-
-#define E4K_I2C_ADDR 0xc8
-#define E4K_CHECK_ADDR 0x02
-#define E4K_CHECK_VAL 0x40
-
-// Function (implemeted for E4000)
-int
-I2CReadByte(void *pTuner,
- unsigned char NoUse,
- unsigned char RegAddr,
- unsigned char *pReadingByte
- );
-
-int
-I2CWriteByte(
- void *pTuner,
- unsigned char NoUse,
- unsigned char RegAddr,
- unsigned char WritingByte
- );
-
-int
-I2CWriteArray(void *pTuner,
- unsigned char NoUse,
- unsigned char RegStartAddr,
- unsigned char ByteNum,
- unsigned char *pWritingBytes
- );
-
-
-
-// Functions (from E4000 source code)
-int tunerreset (void *pTuner);
-int Tunerclock(void *pTuner);
-int Qpeak(void *pTuner);
-int DCoffloop(void *pTuner);
-int GainControlinit(void *pTuner);
-
-int Gainmanual(void *pTuner);
-int E4000_gain_freq(void *pTuner, int frequency);
-int PLL(void *pTuner, int Ref_clk, int Freq);
-int LNAfilter(void *pTuner, int Freq);
-int IFfilter(void *pTuner, int bandwidth, int Ref_clk);
-int freqband(void *pTuner, int Freq);
-int DCoffLUT(void *pTuner);
-int GainControlauto(void *pTuner);
-
-int E4000_sensitivity(void *pTuner, int Freq, int bandwidth);
-int E4000_linearity(void *pTuner, int Freq, int bandwidth);
-int E4000_high_linearity(void *pTuner);
-int E4000_nominal(void *pTuner, int Freq, int bandwidth);
-
-
-// The following context is E4000 tuner API source code
-
-// Definitions
-
-// Bandwidth in Hz
-enum E4000_BANDWIDTH_HZ
-{
- E4000_BANDWIDTH_6000000HZ = 6000000,
- E4000_BANDWIDTH_7000000HZ = 7000000,
- E4000_BANDWIDTH_8000000HZ = 8000000,
-};
-
-
-// Manipulaing functions
-void
-e4000_GetTunerType(
- void *pTuner,
- int *pTunerType
- );
-
-void
-e4000_GetDeviceAddr(
- void *pTuner,
- unsigned char *pDeviceAddr
- );
-
-int
-e4000_Initialize(
- void *pTuner
- );
-
-int
-e4000_SetRfFreqHz(
- void *pTuner,
- unsigned long RfFreqHz
- );
-
-int
-e4000_GetRfFreqHz(
- void *pTuner,
- unsigned long *pRfFreqHz
- );
-
-
-
-
-
-// Extra manipulaing functions
-int
-e4000_GetRegByte(
- void *pTuner,
- unsigned char RegAddr,
- unsigned char *pReadingByte
- );
-
-int
-e4000_SetBandwidthHz(
- void *pTuner,
- unsigned long BandwidthHz
- );
-
-int
-e4000_GetBandwidthHz(
- void *pTuner,
- unsigned long *pBandwidthHz
- );
-
-#endif
diff --git a/include/tuner_e4k.h b/include/tuner_e4k.h
new file mode 100644
index 0000000..969ef7c
--- /dev/null
+++ b/include/tuner_e4k.h
@@ -0,0 +1,219 @@
+#ifndef _E4K_TUNER_H
+#define _E4K_TUNER_H
+
+/* (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 3 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 <http://www.gnu.org/licenses/>.
+ */
+
+#define E4K_I2C_ADDR 0xc8
+#define E4K_CHECK_ADDR 0x02
+#define E4K_CHECK_VAL 0x40
+
+enum e4k_reg {
+ E4K_REG_MASTER1 = 0x00,
+ E4K_REG_MASTER2 = 0x01,
+ E4K_REG_MASTER3 = 0x02,
+ E4K_REG_MASTER4 = 0x03,
+ E4K_REG_MASTER5 = 0x04,
+ E4K_REG_CLK_INP = 0x05,
+ E4K_REG_REF_CLK = 0x06,
+ E4K_REG_SYNTH1 = 0x07,
+ E4K_REG_SYNTH2 = 0x08,
+ E4K_REG_SYNTH3 = 0x09,
+ E4K_REG_SYNTH4 = 0x0a,
+ E4K_REG_SYNTH5 = 0x0b,
+ E4K_REG_SYNTH6 = 0x0c,
+ E4K_REG_SYNTH7 = 0x0d,
+ E4K_REG_SYNTH8 = 0x0e,
+ E4K_REG_SYNTH9 = 0x0f,
+ E4K_REG_FILT1 = 0x10,
+ E4K_REG_FILT2 = 0x11,
+ E4K_REG_FILT3 = 0x12,
+ // gap
+ E4K_REG_GAIN1 = 0x14,
+ E4K_REG_GAIN2 = 0x15,
+ E4K_REG_GAIN3 = 0x16,
+ E4K_REG_GAIN4 = 0x17,
+ // gap
+ E4K_REG_AGC1 = 0x1a,
+ E4K_REG_AGC2 = 0x1b,
+ E4K_REG_AGC3 = 0x1c,
+ E4K_REG_AGC4 = 0x1d,
+ E4K_REG_AGC5 = 0x1e,
+ E4K_REG_AGC6 = 0x1f,
+ E4K_REG_AGC7 = 0x20,
+ E4K_REG_AGC8 = 0x21,
+ // gap
+ E4K_REG_AGC11 = 0x24,
+ E4K_REG_AGC12 = 0x25,
+ // gap
+ E4K_REG_DC1 = 0x29,
+ E4K_REG_DC2 = 0x2a,
+ E4K_REG_DC3 = 0x2b,
+ E4K_REG_DC4 = 0x2c,
+ E4K_REG_DC5 = 0x2d,
+ E4K_REG_DC6 = 0x2e,
+ E4K_REG_DC7 = 0x2f,
+ E4K_REG_DC8 = 0x30,
+ // gap
+ E4K_REG_QLUT0 = 0x50,
+ E4K_REG_QLUT1 = 0x51,
+ E4K_REG_QLUT2 = 0x52,
+ E4K_REG_QLUT3 = 0x53,
+ // gap
+ E4K_REG_ILUT0 = 0x60,
+ E4K_REG_ILUT1 = 0x61,
+ E4K_REG_ILUT2 = 0x62,
+ E4K_REG_ILUT3 = 0x63,
+ // gap
+ E4K_REG_DCTIME1 = 0x70,
+ E4K_REG_DCTIME2 = 0x71,
+ E4K_REG_DCTIME3 = 0x72,
+ E4K_REG_DCTIME4 = 0x73,
+ E4K_REG_PWM1 = 0x74,
+ E4K_REG_PWM2 = 0x75,
+ E4K_REG_PWM3 = 0x76,
+ E4K_REG_PWM4 = 0x77,
+ E4K_REG_BIAS = 0x78,
+ E4K_REG_CLKOUT_PWDN = 0x7a,
+ E4K_REG_CHFILT_CALIB = 0x7b,
+ E4K_REG_I2C_REG_ADDR = 0x7d,
+ // FIXME
+};
+
+#define E4K_MASTER1_RESET (1 << 0)
+#define E4K_MASTER1_NORM_STBY (1 << 1)
+#define E4K_MASTER1_POR_DET (1 << 2)
+
+#define E4K_SYNTH1_PLL_LOCK (1 << 0)
+#define E4K_SYNTH1_BAND_SHIF 1
+
+#define E4K_SYNTH7_3PHASE_EN (1 << 3)
+
+#define E4K_SYNTH8_VCOCAL_UPD (1 << 2)
+
+#define E4K_FILT3_DISABLE (1 << 5)
+
+#define E4K_AGC1_LIN_MODE (1 << 4)
+#define E4K_AGC1_LNA_UPDATE (1 << 5)
+#define E4K_AGC1_LNA_G_LOW (1 << 6)
+#define E4K_AGC1_LNA_G_HIGH (1 << 7)
+
+#define E4K_AGC6_LNA_CAL_REQ (1 << 4)
+
+#define E4K_AGC7_MIX_GAIN_AUTO (1 << 0)
+#define E4K_AGC7_GAIN_STEP_5dB (1 << 5)
+
+#define E4K_AGC8_SENS_LIN_AUTO (1 << 0)
+
+#define E4K_AGC11_LNA_GAIN_ENH (1 << 0)
+
+#define E4K_DC1_CAL_REQ (1 << 0)
+
+#define E4K_DC5_I_LUT_EN (1 << 0)
+#define E4K_DC5_Q_LUT_EN (1 << 1)
+#define E4K_DC5_RANGE_DET_EN (1 << 2)
+#define E4K_DC5_RANGE_EN (1 << 3)
+#define E4K_DC5_TIMEVAR_EN (1 << 4)
+
+#define E4K_CLKOUT_DISABLE 0x96
+
+#define E4K_CHFCALIB_CMD (1 << 0)
+
+#define E4K_AGC1_MOD_MASK 0xF
+
+enum e4k_agc_mode {
+ E4K_AGC_MOD_SERIAL = 0x0,
+ E4K_AGC_MOD_IF_PWM_LNA_SERIAL = 0x1,
+ E4K_AGC_MOD_IF_PWM_LNA_AUTONL = 0x2,
+ E4K_AGC_MOD_IF_PWM_LNA_SUPERV = 0x3,
+ E4K_AGC_MOD_IF_SERIAL_LNA_PWM = 0x4,
+ E4K_AGC_MOD_IF_PWM_LNA_PWM = 0x5,
+ E4K_AGC_MOD_IF_DIG_LNA_SERIAL = 0x6,
+ E4K_AGC_MOD_IF_DIG_LNA_AUTON = 0x7,
+ E4K_AGC_MOD_IF_DIG_LNA_SUPERV = 0x8,
+ E4K_AGC_MOD_IF_SERIAL_LNA_AUTON = 0x9,
+ E4K_AGC_MOD_IF_SERIAL_LNA_SUPERV = 0xa,
+};
+
+enum e4k_band {
+ E4K_BAND_VHF2 = 0,
+ E4K_BAND_VHF3 = 1,
+ E4K_BAND_UHF = 2,
+ E4K_BAND_L = 3,
+};
+
+enum e4k_mixer_filter_bw {
+ E4K_F_MIX_BW_27M = 0,
+ E4K_F_MIX_BW_4M6 = 8,
+ E4K_F_MIX_BW_4M2 = 9,
+ E4K_F_MIX_BW_3M8 = 10,
+ E4K_F_MIX_BW_3M4 = 11,
+ E4K_F_MIX_BW_3M = 12,
+ E4K_F_MIX_BW_2M7 = 13,
+ E4K_F_MIX_BW_2M3 = 14,
+ E4K_F_MIX_BW_1M9 = 15,
+};
+
+enum e4k_if_filter {
+ E4K_IF_FILTER_MIX,
+ E4K_IF_FILTER_CHAN,
+ E4K_IF_FILTER_RC
+};
+struct e4k_pll_params {
+ uint32_t fosc;
+ uint32_t intended_flo;
+ uint32_t flo;
+ uint16_t x;
+ uint8_t z;
+ uint8_t r;
+ uint8_t r_idx;
+ uint8_t threephase;
+};
+
+struct e4k_state {
+ void *i2c_dev;
+ uint8_t i2c_addr;
+ enum e4k_band band;
+ struct e4k_pll_params vco;
+ void *rtl_dev;
+};
+
+int e4k_init(struct e4k_state *e4k);
+int e4k_if_gain_set(struct e4k_state *e4k, uint8_t stage, int8_t value);
+int e4k_mixer_gain_set(struct e4k_state *e4k, int8_t value);
+int e4k_commonmode_set(struct e4k_state *e4k, int8_t value);
+int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq);
+int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p);
+int e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint32_t intended_flo);
+int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter);
+int e4k_if_filter_bw_set(struct e4k_state *e4k, enum e4k_if_filter filter,
+ uint32_t bandwidth);
+int e4k_if_filter_chan_enable(struct e4k_state *e4k, int on);
+int e4k_rf_filter_set(struct e4k_state *e4k);
+
+int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val);
+uint8_t e4k_reg_read(struct e4k_state *e4k, uint8_t reg);
+
+int e4k_manual_dc_offset(struct e4k_state *e4k, int8_t iofs, int8_t irange, int8_t qofs, int8_t qrange);
+int e4k_dc_offset_calibrate(struct e4k_state *e4k);
+int e4k_dc_offset_gen_table(struct e4k_state *e4k);
+
+int e4k_set_lna_gain(struct e4k_state *e4k, int32_t gain);
+int e4k_enable_manual_gain(struct e4k_state *e4k, uint8_t manual);
+int e4k_set_enh_gain(struct e4k_state *e4k, int32_t gain);
+#endif /* _E4K_TUNER_H */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0ce6f6b..6d23607 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,7 +22,7 @@
########################################################################
add_library(rtlsdr_shared SHARED
rtl-sdr.c
- tuner_e4000.c
+ tuner_e4k.c
tuner_fc0012.c
tuner_fc0013.c
tuner_fc2580.c
@@ -37,7 +37,7 @@ set_target_properties(rtlsdr_shared PROPERTIES OUTPUT_NAME rtlsdr)
add_library(rtlsdr_static STATIC
rtl-sdr.c
- tuner_e4000.c
+ tuner_e4k.c
tuner_fc0012.c
tuner_fc0013.c
tuner_fc2580.c
diff --git a/src/Makefile.am b/src/Makefile.am
index f9023cd..f8cc5d6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,7 +7,7 @@ AM_CFLAGS = -fPIC -Wall
lib_LTLIBRARIES = librtlsdr.la
-librtlsdr_la_SOURCES = rtl-sdr.c tuner_e4000.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c
+librtlsdr_la_SOURCES = rtl-sdr.c tuner_e4k.c tuner_fc0012.c tuner_fc0013.c tuner_fc2580.c
librtlsdr_la_LDFALGS = -version-info $(LIBVERSION)
bin_PROGRAMS = rtl_sdr rtl_tcp
diff --git a/src/rtl-sdr.c b/src/rtl-sdr.c
index 46bf84b..6910694 100644
--- a/src/rtl-sdr.c
+++ b/src/rtl-sdr.c
@@ -25,6 +25,7 @@
#include <math.h>
#ifndef _WIN32
#include <unistd.h>
+#define min(a, b) (((a) < (b)) ? (a) : (b))
#endif
#include <libusb.h>
@@ -40,7 +41,7 @@
#endif
#include "rtl-sdr.h"
-#include "tuner_e4000.h"
+#include "tuner_e4k.h"
#include "tuner_fc0012.h"
#include "tuner_fc0013.h"
#include "tuner_fc2580.h"
@@ -52,6 +53,7 @@ typedef struct rtlsdr_tuner {
int (*set_freq)(void *, uint32_t freq /* Hz */);
int (*set_bw)(void *, int bw /* Hz */);
int (*set_gain)(void *, int gain /* dB */);
+ int (*set_gain_mode)(void *, int manual);
} rtlsdr_tuner_t;
enum rtlsdr_async_status {
@@ -79,20 +81,48 @@ struct rtlsdr_dev {
uint32_t freq; /* Hz */
int corr; /* ppm */
int gain; /* dB */
+ struct e4k_state e4k_s;
};
void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
/* generic tuner interface functions, shall be moved to the tuner implementations */
-int e4k_init(void *dev) { return e4000_Initialize(dev); }
-int e4k_exit(void *dev) { return 0; }
-int e4k_set_freq(void *dev, uint32_t freq) {
- return e4000_SetRfFreqHz(dev, freq);
+int e4000_init(void *dev) {
+ rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
+ devt->e4k_s.i2c_addr = E4K_I2C_ADDR;
+ devt->e4k_s.vco.fosc = devt->tun_xtal;
+ devt->e4k_s.rtl_dev = dev;
+ return e4k_init(&devt->e4k_s);
}
-int e4k_set_bw(void *dev, int bw) {
- return e4000_SetBandwidthHz(dev, 4000000);
+int e4000_exit(void *dev) { return 0; }
+int e4000_set_freq(void *dev, uint32_t freq) {
+ rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
+ return e4k_tune_freq(&devt->e4k_s, freq);
+}
+int e4000_set_bw(void *dev, int bw) {
+ return 0;
+}
+int e4000_set_gain(void *dev, int gain) {
+ int rc;
+ rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
+ int mixgain = (gain > 340) ? 12 : 4;
+ int enhgain = (gain - 420);
+ if(e4k_set_lna_gain(&devt->e4k_s, min(300, gain - 40)) == -EINVAL)
+ return -1;
+ if(e4k_mixer_gain_set(&devt->e4k_s, mixgain) == -EINVAL)
+ return -1;
+ if(enhgain >= 0)
+ if(e4k_set_enh_gain(&devt->e4k_s, enhgain) == -EINVAL)
+ return -1;
+
+ return 0;
+}
+
+int e4000_set_gain_mode(void *dev, int manual) {
+ rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
+ e4k_enable_manual_gain(&devt->e4k_s, manual);
+ return 0;
}
-int e4k_set_gain(void *dev, int gain) { return 0; }
int fc0012_init(void *dev) { return FC0012_Open(dev); }
int fc0012_exit(void *dev) { return 0; }
@@ -105,6 +135,7 @@ int fc0012_set_bw(void *dev, int bw) {
return FC0012_SetFrequency(dev, ((rtlsdr_dev_t *) dev)->freq/1000, 6);
}
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_Open(dev); }
int fc0013_exit(void *dev) { return 0; }
@@ -115,6 +146,7 @@ int fc0013_set_bw(void *dev, int bw) {
return FC0013_SetFrequency(dev, ((rtlsdr_dev_t *) dev)->freq/1000, 6);
}
int fc0013_set_gain(void *dev, int gain) { return 0; }
+int fc0013_set_gain_mode(void *dev, int manual) { return 0; }
int fc2580_init(void *dev) { return fc2580_Initialize(dev); }
int fc2580_exit(void *dev) { return 0; }
@@ -125,6 +157,7 @@ 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; }
enum rtlsdr_tuners {
RTLSDR_TUNER_E4000,
@@ -135,20 +168,24 @@ enum rtlsdr_tuners {
static rtlsdr_tuner_t tuners[] = {
{
- e4k_init, e4k_exit,
- e4k_set_freq, e4k_set_bw, e4k_set_gain
+ e4000_init, e4000_exit,
+ e4000_set_freq, e4000_set_bw, e4000_set_gain,
+ e4000_set_gain_mode
},
{
fc0012_init, fc0012_exit,
- fc0012_set_freq, fc0012_set_bw, fc0012_set_gain
+ fc0012_set_freq, fc0012_set_bw, fc0012_set_gain,
+ fc0012_set_gain_mode
},
{
fc0013_init, fc0013_exit,
- fc0013_set_freq, fc0013_set_bw, fc0013_set_gain
+ fc0013_set_freq, fc0013_set_bw, fc0013_set_gain,
+ fc0013_set_gain_mode
},
{
fc2580_init, fc2580_exit,
- _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain
+ _fc2580_set_freq, fc2580_set_bw, fc2580_set_gain,
+ fc2580_set_gain_mode
},
};
@@ -277,6 +314,16 @@ uint8_t rtlsdr_i2c_read_reg(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t reg)
return data;
}
+/* TODO clean this up again */
+int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val)
+{
+ return rtlsdr_i2c_write_reg((rtlsdr_dev_t*)e4k->rtl_dev, e4k->i2c_addr, reg, val);}
+
+uint8_t e4k_reg_read(struct e4k_state *e4k, uint8_t reg)
+{
+ return rtlsdr_i2c_read_reg((rtlsdr_dev_t*)e4k->rtl_dev, e4k->i2c_addr, reg);
+}
+
int rtlsdr_i2c_write(rtlsdr_dev_t *dev, uint8_t i2c_addr, uint8_t *buffer, int len)
{
uint16_t addr = i2c_addr;
@@ -594,8 +641,11 @@ int rtlsdr_set_tuner_gain(rtlsdr_dev_t *dev, int gain)
if (!dev || !dev->tuner)
return -1;
- if (dev->tuner->set_gain)
+ if (dev->tuner->set_gain) {
+ rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->set_gain((void *)dev, gain);
+ rtlsdr_set_i2c_repeater(dev, 0);
+ }
if (!r)
dev->gain = gain;
@@ -611,6 +661,24 @@ int rtlsdr_get_tuner_gain(rtlsdr_dev_t *dev)
return dev->gain;
}
+int rtlsdr_set_tuner_gain_mode(rtlsdr_dev_t *dev, int mode)
+{
+ int r = 0;
+
+ if (!dev || !dev->tuner)
+ return -1;
+
+ if (dev->tuner->set_gain_mode) {
+ rtlsdr_set_i2c_repeater(dev, 1);
+ r = dev->tuner->set_gain_mode((void *)dev, mode);
+ rtlsdr_set_i2c_repeater(dev, 0);
+ }
+
+ return r;
+}
+
+
+
int rtlsdr_set_sample_rate(rtlsdr_dev_t *dev, uint32_t samp_rate)
{
uint16_t tmp;
@@ -862,8 +930,6 @@ err:
int rtlsdr_close(rtlsdr_dev_t *dev)
{
- int i;
-
if (!dev)
return -1;
diff --git a/src/rtl_tcp.c b/src/rtl_tcp.c
index f1f05ca..89019c0 100644
--- a/src/rtl_tcp.c
+++ b/src/rtl_tcp.c
@@ -32,6 +32,8 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
+#else
+#include <WinSock2.h>
#endif
#include <pthread.h>
@@ -278,6 +280,9 @@ static void *command_worker(void *arg)
printf("set freq %d\n", cmd.param);
rtlsdr_set_center_freq(dev, cmd.param);
break;
+ case 0x04:
+ rtlsdr_set_tuner_gain(dev, cmd.param);
+ break;
default:
break;
}
@@ -293,7 +298,7 @@ int main(int argc, char **argv)
uint32_t frequency = 0, samp_rate = 2048000;
struct sockaddr_in local, remote;
int device_count;
- uint32_t dev_index = 0, gain = 5;
+ uint32_t dev_index = 0, gain = -10;
struct llist *curelem,*prev;
pthread_attr_t attr;
void *status;
diff --git a/src/tuner_e4000.c b/src/tuner_e4000.c
deleted file mode 100644
index 5772331..0000000
--- a/src/tuner_e4000.c
+++ /dev/null
@@ -1,2067 +0,0 @@
-/*
- * Elonics E4000 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 replaced by the osmo-sdr E4000 driver
- *
- */
-
-#include <stdint.h>
-
-#include "rtlsdr_i2c.h"
-#include "tuner_e4000.h"
-
-#define FUNCTION_ERROR 1
-#define FUNCTION_SUCCESS 0
-#define NO_USE 0
-#define LEN_2_BYTE 2
-#define I2C_BUFFER_LEN 128
-#define YES 1
-#define NO 0
-#define CRYSTAL_FREQ 28800000
-
-/* glue functions to rtl-sdr code */
-int
-I2CReadByte(void *pTuner,
- unsigned char NoUse,
- unsigned char RegAddr,
- unsigned char *pReadingByte
- )
-{
- uint8_t data = RegAddr;
-
- if (rtlsdr_i2c_write_fn(pTuner, E4K_I2C_ADDR, &data, 1) < 0)
- return E4000_I2C_FAIL;
-
- if (rtlsdr_i2c_read_fn(pTuner, E4K_I2C_ADDR, &data, 1) < 0)
- return E4000_I2C_FAIL;
-
- *pReadingByte = data;
-
- return E4000_I2C_SUCCESS;
-}
-
-int
-I2CWriteByte(void *pTuner,
- unsigned char NoUse,
- unsigned char RegAddr,
- unsigned char WritingByte
- )
-{
- uint8_t data[2];
-
- data[0] = RegAddr;
- data[1] = WritingByte;
-
- if (rtlsdr_i2c_write_fn(pTuner, E4K_I2C_ADDR, data, 2) < 0)
- return E4000_I2C_FAIL;
-
- return E4000_I2C_SUCCESS;
-}
-
-int
-I2CWriteArray(void *pTuner,
- unsigned char NoUse,
- unsigned char RegStartAddr,
- unsigned char ByteNum,
- unsigned char *pWritingBytes
- )
-{
- unsigned int i;
- uint8_t WritingBuffer[I2C_BUFFER_LEN];
-
- WritingBuffer[0] = RegStartAddr;
-
- for(i = 0; i < ByteNum; i++)
- WritingBuffer[1 + i] = pWritingBytes[i];
-
- if (rtlsdr_i2c_write_fn(pTuner, E4K_I2C_ADDR, WritingBuffer, ByteNum + 1) < 0)
- return E4000_I2C_FAIL;
-
- return E4000_I2C_SUCCESS;
-}
-
-/**
-
-@see TUNER_FP_INITIALIZE
-
-*/
-int
-e4000_Initialize(void *pTuner
- )
-{
-
- // Initialize tuner.
- // Note: Call E4000 source code functions.
- if(tunerreset(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(Tunerclock(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(Qpeak(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-#if 0
- if(DCoffloop(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-#endif
- if(GainControlinit(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
-
- return FUNCTION_SUCCESS;
-
-
-error_status_execute_function:
- return FUNCTION_ERROR;
-}
-
-/**
-
-@see TUNER_FP_SET_RF_FREQ_HZ
-
-*/
-int
-e4000_SetRfFreqHz(
- void *pTuner,
- unsigned long RfFreqHz
- )
-{
-// E4000_EXTRA_MODULE *pExtra;
-
- int RfFreqKhz;
- int CrystalFreqKhz;
-
- int CrystalFreqHz = rtlsdr_get_tuner_clock(pTuner);
-
- // Set tuner RF frequency in KHz.
- // Note: 1. RfFreqKhz = round(RfFreqHz / 1000)
- // CrystalFreqKhz = round(CrystalFreqHz / 1000)
- // 2. Call E4000 source code functions.
- RfFreqKhz = (int)((RfFreqHz + 500) / 1000);
- CrystalFreqKhz = (int)((CrystalFreqHz + 500) / 1000);
-
- if(Gainmanual(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(E4000_gain_freq(pTuner, RfFreqKhz) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(PLL(pTuner, CrystalFreqKhz, RfFreqKhz) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(LNAfilter(pTuner, RfFreqKhz) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(freqband(pTuner, RfFreqKhz) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(DCoffLUT(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- if(GainControlauto(pTuner) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
- return FUNCTION_SUCCESS;
-
-
-error_status_execute_function:
- return FUNCTION_ERROR;
-}
-
-/**
-
-@brief Set E4000 tuner bandwidth.
-
-*/
-int
-e4000_SetBandwidthHz(
- void *pTuner,
- unsigned long BandwidthHz
- )
-{
-// E4000_EXTRA_MODULE *pExtra;
-
- int BandwidthKhz;
- int CrystalFreqKhz;
-
- int CrystalFreqHz = rtlsdr_get_tuner_clock(pTuner);
-
-
- // Get tuner extra module.
-// pExtra = &(pTuner->Extra.E4000);
-
-
- // Set tuner bandwidth Hz.
- // Note: 1. BandwidthKhz = round(BandwidthHz / 1000)
- // CrystalFreqKhz = round(CrystalFreqHz / 1000)
- // 2. Call E4000 source code functions.
- BandwidthKhz = (int)((BandwidthHz + 500) / 1000);
- CrystalFreqKhz = (int)((CrystalFreqHz + 500) / 1000);
-
- if(IFfilter(pTuner, BandwidthKhz, CrystalFreqKhz) != E4000_1_SUCCESS)
- goto error_status_execute_function;
-
-
- return FUNCTION_SUCCESS;
-
-error_status_execute_function:
- return FUNCTION_ERROR;
-}
-
-
-// The following context is source code provided by Elonics.
-
-// Elonics source code - E4000_API_rev2_04_realtek.cpp
-
-
-//****************************************************************************/
-//
-// Filename E4000_initialisation.c
-// Revision 2.04
-//
-// Description:
-// Initialisation script for the Elonics E4000 revC tuner
-//
-// Copyright (c) Elonics Ltd
-//
-// Any software supplied free of charge for use with elonics
-// evaluation kits is supplied without warranty and for
-// evaluation purposes only. Incorporation of any of this
-// code into products for open sale is permitted but only at
-// the user's own risk. Elonics accepts no liability for the
-// integrity of this software whatsoever.
-//
-//
-//****************************************************************************/
-//#include <stdio.h>
-//#include <stdlib.h>
-//
-// User defined variable definitions
-//
-/*
-int Ref_clk = 26000; // Reference clock frequency(kHz).
-int Freq = 590000; // RF Frequency (kHz)
-int bandwidth = 8000; //RF channel bandwith (kHz)
-*/
-//
-// API defined variable definitions
-//int VCO_freq;
-//unsigned char writearray[5];
-//unsigned char read1[1];
-//int status;
-//
-//
-// function definitions
-//
-/*
-int tunerreset ();
-int Tunerclock();
-int filtercal();
-int Qpeak();
-int PLL(int Ref_clk, int Freq);
-int LNAfilter(int Freq);
-int IFfilter(int bandwidth, int Ref_clk);
-int freqband(int Freq);
-int DCoffLUT();
-int DCoffloop();
-int commonmode();
-int GainControlinit();
-*/
-//
-//****************************************************************************
-// --- Public functions ------------------------------------------------------
-/****************************************************************************\
-* Function: tunerreset
-*
-* Detailed Description:
-* The function resets the E4000 tuner. (Register 0x00).
-*
-\****************************************************************************/
-
-int tunerreset(void *pTuner)
-{
- unsigned char writearray[5];
- int status;
-
- writearray[0] = 64;
- // For dummy I2C command, don't check executing status.
- status=I2CWriteByte (pTuner, 200,2,writearray[0]);
- status=I2CWriteByte (pTuner, 200,2,writearray[0]);
- //printf("\nRegister 0=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 0;
- status=I2CWriteByte (pTuner, 200,9,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 0;
- status=I2CWriteByte (pTuner, 200,5,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 7;
- status=I2CWriteByte (pTuner, 200,0,writearray[0]);
- //printf("\nRegister 0=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: Tunerclock
-*
-* Detailed Description:
-* The function configures the E4000 clock. (Register 0x06, 0x7a).
-* Function disables the clock - values can be modified to enable if required.
-\****************************************************************************/
-
-int Tunerclock(void *pTuner)
-{
- unsigned char writearray[5];
- int status;
-
- writearray[0] = 0;
- status=I2CWriteByte(pTuner, 200,6,writearray[0]);
- //printf("\nRegister 6=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 150;
- status=I2CWriteByte(pTuner, 200,122,writearray[0]);
- //printf("\nRegister 7a=%d", writearray[0]);
- //**Modify commands above with value required if output clock is required,
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: filtercal
-*
-* Detailed Description:
-* Instructs RC filter calibration. (Register 0x7b).
-*
-\****************************************************************************/
-/*
-int filtercal(void *pTuner)
-{
- //writearray[0] = 1;
- //I2CWriteByte (pTuner, 200,123,writearray[0]);
- //printf("\nRegister 7b=%d", writearray[0]);
- //return;
- return E4000_1_SUCCESS;
-}
-*/
-/****************************************************************************\
-* Function: Qpeak()
-*
-* Detailed Description:
-* The function configures the E4000 gains.
-* Also sigma delta controller. (Register 0x82).
-*
-\****************************************************************************/
-
-int Qpeak(void *pTuner)
-{
- unsigned char writearray[5];
- int status;
-
- writearray[0] = 1;
- writearray[1] = 254;
- status=I2CWriteArray(pTuner, 200,126,2,writearray);
- //printf("\nRegister 7e=%d", writearray[0]);
- //printf("\nRegister 7f=%d", writearray[1]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- status=I2CWriteByte (pTuner, 200,130,0);
- //printf("\nRegister 82=0");
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- status=I2CWriteByte (pTuner, 200,36,5);
- //printf("\nRegister 24=5");
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 32;
- writearray[1] = 1;
- status=I2CWriteArray(pTuner, 200,135,2,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- //printf("\nRegister 87=%d", writearray[0]);
- //printf("\nRegister 88=%d", writearray[1]);
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: E4000_gain_freq()
-*
-* Detailed Description:
-* The function configures the E4000 gains vs. freq
-* 0xa3 to 0xa7. Also 0x24.
-*
-\****************************************************************************/
-int E4000_gain_freq(void *pTuner, int Freq)
-{
- unsigned char writearray[5];
- int status;
-
- if (Freq<=350000)
- {
- writearray[0] = 0x10;
- writearray[1] = 0x42;
- writearray[2] = 0x09;
- writearray[3] = 0x21;
- writearray[4] = 0x94;
- }
- else if(Freq>=1000000)
- {
- writearray[0] = 0x10;
- writearray[1] = 0x42;
- writearray[2] = 0x09;
- writearray[3] = 0x21;
- writearray[4] = 0x94;
- }
- else
- {
- writearray[0] = 0x10;
- writearray[1] = 0x42;
- writearray[2] = 0x09;
- writearray[3] = 0x21;
- writearray[4] = 0x94;
- }
- status=I2CWriteArray(pTuner, 200,163,5,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- if (Freq<=350000)
- {
- writearray[0] = 94;
- writearray[1] = 6;
- status=I2CWriteArray(pTuner, 200,159,2,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 0;
- status=I2CWriteArray(pTuner, 200,136,1,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- }
- else
- {
- writearray[0] = 127;
- writearray[1] = 7;
- status=I2CWriteArray(pTuner, 200,159,2,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 1;
- status=I2CWriteArray(pTuner, 200,136,1,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- }
-
- //printf("\nRegister 9f=%d", writearray[0]);
- //printf("\nRegister a0=%d", writearray[1]);
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: DCoffloop
-*
-* Detailed Description:
-* Populates DC offset LUT. (Registers 0x2d, 0x70, 0x71).
-* Turns on DC offset LUT and time varying DC offset.
-\****************************************************************************/
-int DCoffloop(void *pTuner)
-{
- unsigned char writearray[5];
- int status;
-
- //writearray[0]=0;
- //I2CWriteByte(pTuner, 200,115,writearray[0]);
- //printf("\nRegister 73=%d", writearray[0]);
- writearray[0] = 31;
- status=I2CWriteByte(pTuner, 200,45,writearray[0]);
- //printf("\nRegister 2d=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 1;
- writearray[1] = 1;
- status=I2CWriteArray(pTuner, 200,112,2,writearray);
- //printf("\nRegister 70=%d", writearray[0]);
- //printf("\nRegister 71=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: commonmode
-*
-* Detailed Description:
-* Configures common mode voltage. (Registers 0x2f).
-*
-\****************************************************************************/
-/*
-int commonmode(void *pTuner)
-{
- //writearray[0] = 0;
- //I2CWriteByte(Device_address,47,writearray[0]);
- //printf("\nRegister 0x2fh = %d", writearray[0]);
- // Sets 550mV. Modify if alternative is desired.
- return E4000_1_SUCCESS;
-}
-*/
-/****************************************************************************\
-* Function: GainControlinit
-*
-* Detailed Description:
-* Configures gain control mode. (Registers 0x1d, 0x1e, 0x1f, 0x20, 0x21,
-* 0x1a, 0x74h, 0x75h).
-* User may wish to modify values depending on usage scenario.
-* Routine configures LNA: autonomous gain control
-* IF PWM gain control.
-* PWM thresholds = default
-* Mixer: switches when LNA gain =7.5dB
-* Sensitivity / Linearity mode: manual switch
-*
-\****************************************************************************/
-int GainControlinit(void *pTuner)
-{
- unsigned char writearray[5];
- unsigned char read1[1];
- int status;
-
- unsigned char sum=255;
-
- writearray[0] = 23;
- status=I2CWriteByte(pTuner, 200,26,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- //printf("\nRegister 1a=%d", writearray[0]);
-
- status=I2CReadByte(pTuner, 201,27,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 16;
- writearray[1] = 4;
- writearray[2] = 26;
- writearray[3] = 15;
- writearray[4] = 167;
- status=I2CWriteArray(pTuner, 200,29,5,writearray);
- //printf("\nRegister 1d=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 81;
- status=I2CWriteByte(pTuner, 200,134,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- //printf("\nRegister 86=%d", writearray[0]);
-
- //For Realtek - gain control logic
- status=I2CReadByte(pTuner, 201,27,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- if(read1[0]<=sum)
- {
- sum=read1[0];
- }
-
- status=I2CWriteByte(pTuner, 200,31,writearray[2]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- status=I2CReadByte(pTuner, 201,27,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- if(read1[0] <= sum)
- {
- sum=read1[0];
- }
-
- status=I2CWriteByte(pTuner, 200,31,writearray[2]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- status=I2CReadByte(pTuner, 201,27,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- if(read1[0] <= sum)
- {
- sum=read1[0];
- }
-
- status=I2CWriteByte(pTuner, 200,31,writearray[2]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- status=I2CReadByte(pTuner, 201,27,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- if(read1[0] <= sum)
- {
- sum=read1[0];
- }
-
- status=I2CWriteByte(pTuner, 200,31,writearray[2]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- status=I2CReadByte(pTuner, 201,27,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- if (read1[0]<=sum)
- {
- sum=read1[0];
- }
-
- writearray[0]=sum;
- status=I2CWriteByte(pTuner, 200,27,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- //printf("\nRegister 1b=%d", writearray[0]);
- //printf("\nRegister 1e=%d", writearray[1]);
- //printf("\nRegister 1f=%d", writearray[2]);
- //printf("\nRegister 20=%d", writearray[3]);
- //printf("\nRegister 21=%d", writearray[4]);
- //writearray[0] = 3;
- //writearray[1] = 252;
- //writearray[2] = 3;
- //writearray[3] = 252;
- //I2CWriteArray(pTuner, 200,116,4,writearray);
- //printf("\nRegister 74=%d", writearray[0]);
- //printf("\nRegister 75=%d", writearray[1]);
- //printf("\nRegister 76=%d", writearray[2]);
- //printf("\nRegister 77=%d", writearray[3]);
-
- return E4000_1_SUCCESS;
-}
-
-/****************************************************************************\
-* Main program
-*
-*
-*
-\****************************************************************************/
-/*
-int main()
-{
- tunerreset ();
- Tunerclock();
- //filtercal();
- Qpeak();
- //PLL(Ref_clk, Freq);
- //LNAfilter(Freq);
- //IFfilter(bandwidth, Ref_clk);
- //freqband(Freq);
- //DCoffLUT();
- DCoffloop();
- //commonmode();
- GainControlinit();
-// system("PAUSE");
- return(0);
-}
-*/
-
-
-// Elonics source code - frequency_change_rev2.04_realtek.c
-
-
-//****************************************************************************/
-//
-// Filename E4000_freqchangerev2.04.c
-// Revision 2.04
-//
-// Description:
-// Frequency change script for the Elonics E4000 revB tuner
-//
-// Copyright (c) Elonics Ltd
-//
-// Any software supplied free of charge for use with elonics
-// evaluation kits is supplied without warranty and for
-// evaluation purposes only. Incorporation of any of this
-// code into products for open sale is permitted but only at
-// the user's own risk. Elonics accepts no liability for the
-// integrity of this software whatsoever.
-//
-//
-//****************************************************************************/
-//#include <stdio.h>
-//#include <stdlib.h>
-//
-// User defined variable definitions
-//
-/*
-int Ref_clk = 20000; // Reference clock frequency(kHz).
-int Freq = 590000; // RF Frequency (kHz)
-int bandwidth = 8; //RF channel bandwith (MHz)
-*/
-//
-// API defined variable definitions
-//int VCO_freq;
-//unsigned char writearray[5];
-//unsigned char read1[1];
-//int E4000_1_SUCCESS;
-//int E4000_1_FAIL;
-//int E4000_I2C_SUCCESS;
-//int status;
-//
-//
-// function definitions
-//
-/*
-int Gainmanual();
-int PLL(int Ref_clk, int Freq);
-int LNAfilter(int Freq);
-int IFfilter(int bandwidth, int Ref_clk);
-int freqband(int Freq);
-int DCoffLUT();
-int GainControlauto();
-*/
-//
-//****************************************************************************
-// --- Public functions ------------------------------------------------------
-/****************************************************************************\
-//****************************************************************************\
-* Function: Gainmanual
-*
-* Detailed Description:
-* Sets Gain control to serial interface control.
-*
-\****************************************************************************/
-int Gainmanual(void *pTuner)
-{
- unsigned char writearray[5];
- int status;
-
- writearray[0]=0;
- status=I2CWriteByte(pTuner, 200,26,writearray[0]);
- //printf("\nRegister 1a=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 0;
- status=I2CWriteByte (pTuner, 200,9,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 0;
- status=I2CWriteByte (pTuner, 200,5,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-
-/****************************************************************************\
-* Function: PLL
-*
-* Detailed Description:
-* Configures E4000 PLL divider & sigma delta. 0x0d,0x09, 0x0a, 0x0b).
-*
-\****************************************************************************/
-int PLL(void *pTuner, int Ref_clk, int Freq)
-{
- int VCO_freq;
- unsigned char writearray[5];
- int status;
-
- unsigned char divider;
- int intVCOfreq;
- int SigDel;
- int SigDel2;
- int SigDel3;
-// int harmonic_freq;
-// int offset;
-
- if (Freq<=72400)
- {
- writearray[4] = 15;
- VCO_freq=Freq*48;
- }
- else if (Freq<=81200)
- {
- writearray[4] = 14;
- VCO_freq=Freq*40;
- }
- else if (Freq<=108300)
- {
- writearray[4]=13;
- VCO_freq=Freq*32;
- }
- else if (Freq<=162500)
- {
- writearray[4]=12;
- VCO_freq=Freq*24;
- }
- else if (Freq<=216600)
- {
- writearray[4]=11;
- VCO_freq=Freq*16;
- }
- else if (Freq<=325000)
- {
- writearray[4]=10;
- VCO_freq=Freq*12;
- }
- else if (Freq<=350000)
- {
- writearray[4]=9;
- VCO_freq=Freq*8;
- }
- else if (Freq<=432000)
- {
- writearray[4]=3;
- VCO_freq=Freq*8;
- }
- else if (Freq<=667000)
- {
- writearray[4]=2;
- VCO_freq=Freq*6;
- }
- else if (Freq<=1200000)
- {
- writearray[4]=1;
- VCO_freq=Freq*4;
- }
- else
- {
- writearray[4]=0;
- VCO_freq=Freq*2;
- }
-
- //printf("\nVCOfreq=%d", VCO_freq);
-// divider = VCO_freq * 1000 / Ref_clk;
- divider = VCO_freq / Ref_clk;
- //printf("\ndivider=%d", divider);
- writearray[0]= divider;
-// intVCOfreq = divider * Ref_clk /1000;
- intVCOfreq = divider * Ref_clk;
- //printf("\ninteger VCO freq=%d", intVCOfreq);
-// SigDel=65536 * 1000 * (VCO_freq - intVCOfreq) / Ref_clk;
- SigDel=65536 * (VCO_freq - intVCOfreq) / Ref_clk;
- //printf("\nSigma delta=%d", SigDel);
- if (SigDel<=1024)
- {
- SigDel = 1024;
- }
- else if (SigDel>=64512)
- {
- SigDel=64512;
- }
- SigDel2 = SigDel / 256;
- //printf("\nSigdel2=%d", SigDel2);
- writearray[2] = (unsigned char)SigDel2;
- SigDel3 = SigDel - (256 * SigDel2);
- //printf("\nSig del3=%d", SigDel3);
- writearray[1]= (unsigned char)SigDel3;
- writearray[3]=(unsigned char)0;
- status=I2CWriteArray(pTuner, 200,9,5,writearray);
- //printf("\nRegister 9=%d", writearray[0]);
- //printf("\nRegister a=%d", writearray[1]);
- //printf("\nRegister b=%d", writearray[2]);
- //printf("\nRegister d=%d", writearray[4]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- if (Freq<=82900)
- {
- writearray[0]=0;
- writearray[2]=1;
- }
- else if (Freq<=89900)
- {
- writearray[0]=3;
- writearray[2]=9;
- }
- else if (Freq<=111700)
- {
- writearray[0]=0;
- writearray[2]=1;
- }
- else if (Freq<=118700)
- {
- writearray[0]=3;
- writearray[2]=1;
- }
- else if (Freq<=140500)
- {
- writearray[0]=0;
- writearray[2]=3;
- }
- else if (Freq<=147500)
- {
- writearray[0]=3;
- writearray[2]=11;
- }
- else if (Freq<=169300)
- {
- writearray[0]=0;
- writearray[2]=3;
- }
- else if (Freq<=176300)
- {
- writearray[0]=3;
- writearray[2]=11;
- }
- else if (Freq<=198100)
- {
- writearray[0]=0;
- writearray[2]=3;
- }
- else if (Freq<=205100)
- {
- writearray[0]=3;
- writearray[2]=19;
- }
- else if (Freq<=226900)
- {
- writearray[0]=0;
- writearray[2]=3;
- }
- else if (Freq<=233900)
- {
- writearray[0]=3;
- writearray[2]=3;
- }
- else if (Freq<=350000)
- {
- writearray[0]=0;
- writearray[2]=3;
- }
- else if (Freq<=485600)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=493600)
- {
- writearray[0]=3;
- writearray[2]=5;
- }
- else if (Freq<=514400)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=522400)
- {
- writearray[0]=3;
- writearray[2]=5;
- }
- else if (Freq<=543200)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=551200)
- {
- writearray[0]=3;
- writearray[2]=13;
- }
- else if (Freq<=572000)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=580000)
- {
- writearray[0]=3;
- writearray[2]=13;
- }
- else if (Freq<=600800)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=608800)
- {
- writearray[0]=3;
- writearray[2]=13;
- }
- else if (Freq<=629600)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=637600)
- {
- writearray[0]=3;
- writearray[2]=13;
- }
- else if (Freq<=658400)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=666400)
- {
- writearray[0]=3;
- writearray[2]=13;
- }
- else if (Freq<=687200)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=695200)
- {
- writearray[0]=3;
- writearray[2]=13;
- }
- else if (Freq<=716000)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=724000)
- {
- writearray[0]=3;
- writearray[2]=13;
- }
- else if (Freq<=744800)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=752800)
- {
- writearray[0]=3;
- writearray[2]=21;
- }
- else if (Freq<=773600)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=781600)
- {
- writearray[0]=3;
- writearray[2]=21;
- }
- else if (Freq<=802400)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=810400)
- {
- writearray[0]=3;
- writearray[2]=21;
- }
- else if (Freq<=831200)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=839200)
- {
- writearray[0]=3;
- writearray[2]=21;
- }
- else if (Freq<=860000)
- {
- writearray[0]=0;
- writearray[2]=5;
- }
- else if (Freq<=868000)
- {
- writearray[0]=3;
- writearray[2]=21;
- }
- else
- {
- writearray[0]=0;
- writearray[2]=7;
- }
-
- status=I2CWriteByte (pTuner, 200,7,writearray[2]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- status=I2CWriteByte (pTuner, 200,5,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-
-/****************************************************************************\
-* Function: LNAfilter
-*
-* Detailed Description:
-* The function configures the E4000 LNA filter. (Register 0x10).
-*
-\****************************************************************************/
-
-int LNAfilter(void *pTuner, int Freq)
-{
- unsigned char writearray[5];
- int status;
-
- if(Freq<=370000)
- {
- writearray[0]=0;
- }
- else if(Freq<=392500)
- {
- writearray[0]=1;
- }
- else if(Freq<=415000)
- {
- writearray[0] =2;
- }
- else if(Freq<=437500)
- {
- writearray[0]=3;
- }
- else if(Freq<=462500)
- {
- writearray[0]=4;
- }
- else if(Freq<=490000)
- {
- writearray[0]=5;
- }
- else if(Freq<=522500)
- {
- writearray[0]=6;
- }
- else if(Freq<=557500)
- {
- writearray[0]=7;
- }
- else if(Freq<=595000)
- {
- writearray[0]=8;
- }
- else if(Freq<=642500)
- {
- writearray[0]=9;
- }
- else if(Freq<=695000)
- {
- writearray[0]=10;
- }
- else if(Freq<=740000)
- {
- writearray[0]=11;
- }
- else if(Freq<=800000)
- {
- writearray[0]=12;
- }
- else if(Freq<=865000)
- {
- writearray[0] =13;
- }
- else if(Freq<=930000)
- {
- writearray[0]=14;
- }
- else if(Freq<=1000000)
- {
- writearray[0]=15;
- }
- else if(Freq<=1310000)
- {
- writearray[0]=0;
- }
- else if(Freq<=1340000)
- {
- writearray[0]=1;
- }
- else if(Freq<=1385000)
- {
- writearray[0]=2;
- }
- else if(Freq<=1427500)
- {
- writearray[0]=3;
- }
- else if(Freq<=1452500)
- {
- writearray[0]=4;
- }
- else if(Freq<=1475000)
- {
- writearray[0]=5;
- }
- else if(Freq<=1510000)
- {
- writearray[0]=6;
- }
- else if(Freq<=1545000)
- {
- writearray[0]=7;
- }
- else if(Freq<=1575000)
- {
- writearray[0] =8;
- }
- else if(Freq<=1615000)
- {
- writearray[0]=9;
- }
- else if(Freq<=1650000)
- {
- writearray[0] =10;
- }
- else if(Freq<=1670000)
- {
- writearray[0]=11;
- }
- else if(Freq<=1690000)
- {
- writearray[0]=12;
- }
- else if(Freq<=1710000)
- {
- writearray[0]=13;
- }
- else if(Freq<=1735000)
- {
- writearray[0]=14;
- }
- else
- {
- writearray[0]=15;
- }
- status=I2CWriteByte (pTuner, 200,16,writearray[0]);
- //printf("\nRegister 10=%d", writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: IFfilter
-*
-* Detailed Description:
-* The function configures the E4000 IF filter. (Register 0x11,0x12).
-*
-\****************************************************************************/
-int IFfilter(void *pTuner, int bandwidth, int Ref_clk)
-{
- unsigned char writearray[5];
- int status;
-
- int IF_BW;
-
- IF_BW = bandwidth / 2;
- if(IF_BW<=2150)
- {
- writearray[0]=253;
- writearray[1]=31;
- }
- else if(IF_BW<=2200)
- {
- writearray[0]=253;
- writearray[1]=30;
- }
- else if(IF_BW<=2240)
- {
- writearray[0]=252;
- writearray[1]=29;
- }
- else if(IF_BW<=2280)
- {
- writearray[0]=252;
- writearray[1]=28;
- }
- else if(IF_BW<=2300)
- {
- writearray[0]=252;
- writearray[1]=27;
- }
- else if(IF_BW<=2400)
- {
- writearray[0]=252;
- writearray[1]=26;
- }
- else if(IF_BW<=2450)
- {
- writearray[0]=252;
- writearray[1]=25;
- }
- else if(IF_BW<=2500)
- {
- writearray[0]=252;
- writearray[1]=24;
- }
- else if(IF_BW<=2550)
- {
- writearray[0]=252;
- writearray[1]=23;
- }
- else if(IF_BW<=2600)
- {
- writearray[0]=252;
- writearray[1]=22;
- }
- else if(IF_BW<=2700)
- {
- writearray[0]=252;
- writearray[1]=21;
- }
- else if(IF_BW<=2750)
- {
- writearray[0]=252;
- writearray[1]=20;
- }
- else if(IF_BW<=2800)
- {
- writearray[0]=252;
- writearray[1]=19;
- }
- else if(IF_BW<=2900)
- {
- writearray[0]=251;
- writearray[1]=18;
- }
- else if(IF_BW<=2950)
- {
- writearray[0]=251;
- writearray[1]=17;
- }
- else if(IF_BW<=3000)
- {
- writearray[0]=251;
- writearray[1]=16;
- }
- else if(IF_BW<=3100)
- {
- writearray[0]=251;
- writearray[1]=15;
- }
- else if(IF_BW<=3200)
- {
- writearray[0]=250;
- writearray[1]=14;
- }
- else if(IF_BW<=3300)
- {
- writearray[0]=250;
- writearray[1]=13;
- }
- else if(IF_BW<=3400)
- {
- writearray[0]=249;
- writearray[1]=12;
- }
- else if(IF_BW<=3600)
- {
- writearray[0]=249;
- writearray[1]=11;
- }
- else if(IF_BW<=3700)
- {
- writearray[0]=249;
- writearray[1]=10;
- }
- else if(IF_BW<=3800)
- {
- writearray[0]=248;
- writearray[1]=9;
- }
- else if(IF_BW<=3900)
- {
- writearray[0]=248;
- writearray[1]=8;
- }
- else if(IF_BW<=4100)
- {
- writearray[0]=248;
- writearray[1]=7;
- }
- else if(IF_BW<=4300)
- {
- writearray[0]=247;
- writearray[1]=6;
- }
- else if(IF_BW<=4400)
- {
- writearray[0]=247;
- writearray[1]=5;
- }
- else if(IF_BW<=4600)
- {
- writearray[0]=247;
- writearray[1]=4;
- }
- else if(IF_BW<=4800)
- {
- writearray[0]=246;
- writearray[1]=3;
- }
- else if(IF_BW<=5000)
- {
- writearray[0]=246;
- writearray[1]=2;
- }
- else if(IF_BW<=5300)
- {
- writearray[0]=245;
- writearray[1]=1;
- }
- else if(IF_BW<=5500)
- {
- writearray[0]=245;
- writearray[1]=0;
- }
- else
- {
- writearray[0]=0;
- writearray[1]=32;
- }
- status=I2CWriteArray(pTuner, 200,17,2,writearray);
- //printf("\nRegister 11=%d", writearray[0]);
- //printf("\nRegister 12=%d", writearray[1]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: freqband
-*
-* Detailed Description:
-* Configures the E4000 frequency band. (Registers 0x07, 0x78).
-*
-\****************************************************************************/
-int freqband(void *pTuner, int Freq)
-{
- unsigned char writearray[5];
- int status;
-
- if (Freq<=140000)
- {
- writearray[0] = 3;
- status=I2CWriteByte(pTuner, 200,120,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- }
- else if (Freq<=350000)
- {
- writearray[0] = 3;
- status=I2CWriteByte(pTuner, 200,120,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- }
- else if (Freq<=1000000)
- {
- writearray[0] = 3;
- status=I2CWriteByte(pTuner, 200,120,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- }
- else
- {
- writearray[0] = 7;
- status=I2CWriteByte(pTuner, 200,7,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = 0;
- status=I2CWriteByte(pTuner, 200,120,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: DCoffLUT
-*
-* Detailed Description:
-* Populates DC offset LUT. (Registers 0x50 - 0x53, 0x60 - 0x63).
-*
-\****************************************************************************/
-int DCoffLUT(void *pTuner)
-{
- unsigned char writearray[5];
- int status;
-
- unsigned char read1[1];
- unsigned char IOFF;
- unsigned char QOFF;
- unsigned char RANGE1;
-// unsigned char RANGE2;
- unsigned char QRANGE;
- unsigned char IRANGE;
- writearray[0] = 0;
- writearray[1] = 126;
- writearray[2] = 36;
- status=I2CWriteArray(pTuner, 200,21,3,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Sets mixer & IF stage 1 gain = 00 and IF stg 2+ to max gain.
- writearray[0] = 1;
- status=I2CWriteByte(pTuner, 200,41,writearray[0]);
- // Instructs a DC offset calibration.
- status=I2CReadByte(pTuner, 201,42,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- IOFF=read1[0];
- status=I2CReadByte(pTuner, 201,43,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- QOFF=read1[0];
- status=I2CReadByte(pTuner, 201,44,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- RANGE1=read1[0];
- //reads DC offset values back
- if(RANGE1>=32)
- {
- RANGE1 = RANGE1 -32;
- }
- if(RANGE1>=16)
- {
- RANGE1 = RANGE1 - 16;
- }
- IRANGE=RANGE1;
- QRANGE = (read1[0] - RANGE1) / 16;
-
- writearray[0] = (IRANGE * 64) + IOFF;
- status=I2CWriteByte(pTuner, 200,96,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = (QRANGE * 64) + QOFF;
- status=I2CWriteByte(pTuner, 200,80,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Populate DC offset LUT
- writearray[0] = 0;
- writearray[1] = 127;
- status=I2CWriteArray(pTuner, 200,21,2,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Sets mixer & IF stage 1 gain = 01 leaving IF stg 2+ at max gain.
- writearray[0]= 1;
- status=I2CWriteByte(pTuner, 200,41,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Instructs a DC offset calibration.
- status=I2CReadByte(pTuner, 201,42,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- IOFF=read1[0];
- status=I2CReadByte(pTuner, 201,43,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- QOFF=read1[0];
- status=I2CReadByte(pTuner, 201,44,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- RANGE1=read1[0];
- // Read DC offset values
- if(RANGE1>=32)
- {
- RANGE1 = RANGE1 -32;
- }
- if(RANGE1>=16)
- {
- RANGE1 = RANGE1 - 16;
- }
- IRANGE = RANGE1;
- QRANGE = (read1[0] - RANGE1) / 16;
-
- writearray[0] = (IRANGE * 64) + IOFF;
- status=I2CWriteByte(pTuner, 200,97,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = (QRANGE * 64) + QOFF;
- status=I2CWriteByte(pTuner, 200,81,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Populate DC offset LUT
- writearray[0] = 1;
- status=I2CWriteByte(pTuner, 200,21,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Sets mixer & IF stage 1 gain = 11 leaving IF stg 2+ at max gain.
- writearray[0] = 1;
- status=I2CWriteByte(pTuner, 200,41,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Instructs a DC offset calibration.
- status=I2CReadByte(pTuner, 201,42,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- IOFF=read1[0];
- status=I2CReadByte(pTuner, 201,43,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- QOFF=read1[0];
- status=I2CReadByte(pTuner, 201,44,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- RANGE1 = read1[0];
- // Read DC offset values
- if(RANGE1>=32)
- {
- RANGE1 = RANGE1 -32;
- }
- if(RANGE1>=16)
- {
- RANGE1 = RANGE1 - 16;
- }
- IRANGE = RANGE1;
- QRANGE = (read1[0] - RANGE1) / 16;
- writearray[0] = (IRANGE * 64) + IOFF;
- status=I2CWriteByte(pTuner, 200,99,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = (QRANGE * 64) + QOFF;
- status=I2CWriteByte(pTuner, 200,83,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Populate DC offset LUT
- writearray[0] = 126;
- status=I2CWriteByte(pTuner, 200,22,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Sets mixer & IF stage 1 gain = 11 leaving IF stg 2+ at max gain.
- writearray[0] = 1;
- status=I2CWriteByte(pTuner, 200,41,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- // Instructs a DC offset calibration.
- status=I2CReadByte(pTuner, 201,42,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- IOFF=read1[0];
-
- status=I2CReadByte(pTuner, 201,43,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- QOFF=read1[0];
-
- status=I2CReadByte(pTuner, 201,44,read1);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
- RANGE1=read1[0];
-
- // Read DC offset values
- if(RANGE1>=32)
- {
- RANGE1 = RANGE1 -32;
- }
- if(RANGE1>=16)
- {
- RANGE1 = RANGE1 - 16;
- }
- IRANGE = RANGE1;
- QRANGE = (read1[0] - RANGE1) / 16;
-
- writearray[0]=(IRANGE * 64) + IOFF;
- status=I2CWriteByte(pTuner, 200,98,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- writearray[0] = (QRANGE * 64) + QOFF;
- status=I2CWriteByte(pTuner, 200,82,writearray[0]);
- // Populate DC offset LUT
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: GainControlinit
-*
-* Detailed Description:
-* Configures gain control mode. (Registers 0x1a)
-*
-\****************************************************************************/
-int GainControlauto(void *pTuner)
-{
- unsigned char writearray[5];
- int status;
-
- writearray[0] = 23;
- status=I2CWriteByte(pTuner, 200,26,writearray[0]);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Main program
-*
-*
-*
-\****************************************************************************/
-/*
-int main()
-{
- Gainmanual();
- PLL(Ref_clk, Freq);
- LNAfilter(Freq);
- IFfilter(bandwidth, Ref_clk);
- freqband(Freq);
- DCoffLUT();
- GainControlauto();
- return(0);
-}
-*/
-
-// Elonics source code - RT2832_SW_optimisation_rev2.c
-
-
-
-/****************************************************************************\
-* Function: E4000_sensitivity
-*
-* Detailed Description:
-* The function configures the E4000 for sensitivity mode.
-*
-\****************************************************************************/
-
-int E4000_sensitivity(void *pTuner, int Freq, int bandwidth)
-{
- unsigned char writearray[2];
- int status;
- int IF_BW;
-
- writearray[1]=0x00;
-
- if(Freq<=700000)
- {
- writearray[0] = 0x07;
- }
- else
- {
- writearray[0] = 0x05;
- }
- status = I2CWriteArray(pTuner,200,36,1,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- IF_BW = bandwidth / 2;
- if(IF_BW<=2500)
- {
- writearray[0]=0xfc;
- writearray[1]=0x17;
- }
- else if(IF_BW<=3000)
- {
- writearray[0]=0xfb;
- writearray[1]=0x0f;
- }
- else if(IF_BW<=3500)
- {
- writearray[0]=0xf9;
- writearray[1]=0x0b;
- }
- else if(IF_BW<=4000)
- {
- writearray[0]=0xf8;
- writearray[1]=0x07;
- }
- status = I2CWriteArray(pTuner,200,17,2,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: E4000_linearity
-*
-* Detailed Description:
-* The function configures the E4000 for linearity mode.
-*
-\****************************************************************************/
-int E4000_linearity(void *pTuner, int Freq, int bandwidth)
-{
-
- unsigned char writearray[2];
- int status;
- int IF_BW;
-
- writearray[1]=0x00;
-
- if(Freq<=700000)
- {
- writearray[0] = 0x03;
- }
- else
- {
- writearray[0] = 0x01;
- }
- status = I2CWriteArray(pTuner,200,36,1,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- IF_BW = bandwidth / 2;
- if(IF_BW<=2500)
- {
- writearray[0]=0xfe;
- writearray[1]=0x19;
- }
- else if(IF_BW<=3000)
- {
- writearray[0]=0xfd;
- writearray[1]=0x11;
- }
- else if(IF_BW<=3500)
- {
- writearray[0]=0xfb;
- writearray[1]=0x0d;
- }
- else if(IF_BW<=4000)
- {
- writearray[0]=0xfa;
- writearray[1]=0x0a;
- }
- status = I2CWriteArray(pTuner,200,17,2,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-/****************************************************************************\
-* Function: E4000_nominal
-*
-* Detailed Description:
-* The function configures the E4000 for nominal
-*
-\****************************************************************************/
-int E4000_nominal(void *pTuner, int Freq, int bandwidth)
-{
- unsigned char writearray[2];
- int status;
- int IF_BW;
-
- writearray[1]=0x00;
-
- if(Freq<=700000)
- {
- writearray[0] = 0x03;
- }
- else
- {
- writearray[0] = 0x01;
- }
- status = I2CWriteArray(pTuner,200,36,1,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- IF_BW = bandwidth / 2;
- if(IF_BW<=2500)
- {
- writearray[0]=0xfc;
- writearray[1]=0x17;
- }
- else if(IF_BW<=3000)
- {
- writearray[0]=0xfb;
- writearray[1]=0x0f;
- }
- else if(IF_BW<=3500)
- {
- writearray[0]=0xf9;
- writearray[1]=0x0b;
- }
- else if(IF_BW<=4000)
- {
- writearray[0]=0xf8;
- writearray[1]=0x07;
- }
- status = I2CWriteArray(pTuner,200,17,2,writearray);
- if(status != E4000_I2C_SUCCESS)
- {
- return E4000_1_FAIL;
- }
-
- return E4000_1_SUCCESS;
-}
-
diff --git a/src/tuner_e4k.c b/src/tuner_e4k.c
new file mode 100644
index 0000000..b530812
--- /dev/null
+++ b/src/tuner_e4k.c
@@ -0,0 +1,955 @@
+/* (C) 2011-2012 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 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 3 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <limits.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <reg_field.h>
+#include <tuner_e4k.h>
+
+#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 */
+
+#if 0
+/*! \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
+ */
+int e4k_reg_write(struct e4k_state *e4k, uint8_t reg, uint8_t val)
+{
+ /* FIXME */
+ return 0;
+}
+
+/*! \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
+ */
+int e4k_reg_read(struct e4k_state *e4k, uint8_t reg)
+{
+ /* FIXME */
+ return 0;
+}
+#endif
+
+/*! \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(uint32_t freq)
+{
+ int rc;
+
+ if (freq < MHZ(350))
+ rc = 0;
+ else if (freq < MHZ(1000))
+ rc = closest_arr_idx(rf_filt_center_uhf,
+ ARRAY_SIZE(rf_filt_center_uhf),
+ freq);
+ else
+ rc = closest_arr_idx(rf_filt_center_l,
+ ARRAY_SIZE(rf_filt_center_l),
+ freq);
+
+ 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->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, "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, "Fosc %u invalid\n", fosc);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int is_z_valid(uint32_t z)
+{
+ if (z > 255) {
+ fprintf(stderr, "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 int 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;
+ }
+
+ 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,
+ * negative in case of error
+ */
+int 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 -EINVAL;
+
+ 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, "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)
+{
+ uint8_t val;
+
+ /* 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(1000))
+ 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)
+{
+ int rc, i;
+ struct e4k_pll_params p;
+
+ /* determine PLL parameters */
+ rc = e4k_compute_pll_params(&p, e4k->vco.fosc, freq);
+ if (rc < 0)
+ return rc;
+
+ /* 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)) {
+ printf("[E4K] PLL not locked!\n");
+ 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[] = {
+ { 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);
+ return 0;
+}
+
+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] numbere of the stage (1..6)
+ * \param [value] gain value in dBm
+ * \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;
+
+ printf("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;
+}
+
+/***********************************************************************
+ * 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;
+}