mirror of https://github.com/drowe67/librtlsdr.git
added librtsdr options vcocmin/vcocmax/vcoalgo for testing
* see https://github.com/librtlsdr/librtlsdr/issues/91 * vcocmin/vcocmax: sets VCO current for R820T/2 * added tuner internal caching for VCO current, that register isn't written when unnecessary * added vcoalgo option: - vcoalgo=2 allows to select/use r82xx_set_pll() from https://github.com/rtlsdrblog/rtl-sdr.git - vcoalgo=1 is previous algorithm, just with higher vco_max=3.9GHz - vcoalgo=0 is previous algorithm - the default: kept this until https://github.com/steve-m/librtlsdr/pull/10 is measured * rtl_test: added options -f and -e to define where to start and end the tuner range test .. for quicker testing if the new options change/extend the tuner's frequency range Signed-off-by: hayati ayguen <h_ayguen@web.de>development
parent
907da08bfc
commit
c7d071e17e
|
@ -68,6 +68,9 @@ enum r82xx_xtal_cap_value {
|
||||||
|
|
||||||
struct r82xx_config {
|
struct r82xx_config {
|
||||||
uint8_t i2c_addr;
|
uint8_t i2c_addr;
|
||||||
|
uint8_t vco_curr_min; /* VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */
|
||||||
|
uint8_t vco_curr_max; /* value is inverted: programmed is 7-value, that 0 is lowest current */
|
||||||
|
uint8_t vco_algo;
|
||||||
uint32_t xtal;
|
uint32_t xtal;
|
||||||
enum r82xx_chip rafael_chip;
|
enum r82xx_chip rafael_chip;
|
||||||
unsigned int max_i2c_msg_len;
|
unsigned int max_i2c_msg_len;
|
||||||
|
@ -89,6 +92,7 @@ struct r82xx_priv {
|
||||||
* on which the band center shall be positioned */
|
* on which the band center shall be positioned */
|
||||||
uint8_t fil_cal_code;
|
uint8_t fil_cal_code;
|
||||||
uint8_t input;
|
uint8_t input;
|
||||||
|
uint8_t last_vco_curr;
|
||||||
int has_lock;
|
int has_lock;
|
||||||
int init_done;
|
int init_done;
|
||||||
int sideband;
|
int sideband;
|
||||||
|
|
|
@ -99,6 +99,8 @@
|
||||||
#define LOG_API_SET_FREQ 0
|
#define LOG_API_SET_FREQ 0
|
||||||
|
|
||||||
#define INIT_R820T_TUNER_GAIN 0
|
#define INIT_R820T_TUNER_GAIN 0
|
||||||
|
#define ENABLE_VCO_OPTIONS 1
|
||||||
|
|
||||||
|
|
||||||
/* activate/use RTL's IF AGC control .. from https://github.com/old-dab/rtlsdr
|
/* activate/use RTL's IF AGC control .. from https://github.com/old-dab/rtlsdr
|
||||||
* purpose: make AGC more smooth .. and NOT freeze
|
* purpose: make AGC more smooth .. and NOT freeze
|
||||||
|
@ -379,6 +381,10 @@ int r820t_init(void *dev) {
|
||||||
devt->r82xx_c.rafael_chip = CHIP_R820T;
|
devt->r82xx_c.rafael_chip = CHIP_R820T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
devt->r82xx_c.vco_curr_min = 0xff; /* VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */
|
||||||
|
devt->r82xx_c.vco_curr_max = 0xff; /* value is inverted: programmed is 7-value, that 0 is lowest current */
|
||||||
|
devt->r82xx_c.vco_algo = 0x00;
|
||||||
|
|
||||||
rtlsdr_get_xtal_freq(devt, NULL, &devt->r82xx_c.xtal);
|
rtlsdr_get_xtal_freq(devt, NULL, &devt->r82xx_c.xtal);
|
||||||
|
|
||||||
devt->r82xx_c.max_i2c_msg_len = 8;
|
devt->r82xx_c.max_i2c_msg_len = 8;
|
||||||
|
@ -4184,6 +4190,11 @@ const char * rtlsdr_get_opt_help(int longInfo)
|
||||||
"\t\t 0: use I & Q; 1: use I; 2: use Q; 3: use I below threshold frequency;\n"
|
"\t\t 0: use I & Q; 1: use I; 2: use Q; 3: use I below threshold frequency;\n"
|
||||||
"\t\t 4: use Q below threshold frequency (=RTL-SDR v3)\n"
|
"\t\t 4: use Q below threshold frequency (=RTL-SDR v3)\n"
|
||||||
"\t\t other values set the threshold frequency\n"
|
"\t\t other values set the threshold frequency\n"
|
||||||
|
#if ENABLE_VCO_OPTIONS
|
||||||
|
"\t\tvcocmin=<current> set R820T/2 VCO current min: 0..7: higher value is more current\n"
|
||||||
|
"\t\tvcocmax=<current> set R820T/2 VCO current max: 0..7\n"
|
||||||
|
"\t\tvcoalgo=<algo> set R820T/2 VCO algorithm. 0: default. 1: with vcomax=3.9G. 2: Youssef/Carl\n"
|
||||||
|
#endif
|
||||||
"\t\tTp=<gpio_pin> set GPIO pin for Bias T, default =0 for rtl-sdr.com compatible V3\n"
|
"\t\tTp=<gpio_pin> set GPIO pin for Bias T, default =0 for rtl-sdr.com compatible V3\n"
|
||||||
"\t\tT=<bias_tee> 1 activates power at antenna one some dongles, e.g. rtl-sdr.com's V3\n"
|
"\t\tT=<bias_tee> 1 activates power at antenna one some dongles, e.g. rtl-sdr.com's V3\n"
|
||||||
#ifdef WITH_UDP_SERVER
|
#ifdef WITH_UDP_SERVER
|
||||||
|
@ -4196,7 +4207,12 @@ const char * rtlsdr_get_opt_help(int longInfo)
|
||||||
"\t[-O\tset RTL options string seperated with ':', e.g. -O 'bc=30000:agc=0' ]\n"
|
"\t[-O\tset RTL options string seperated with ':', e.g. -O 'bc=30000:agc=0' ]\n"
|
||||||
"\t\tverbose:f=<freqHz>:bw=<bw_in_kHz>:bc=<if_in_Hz>:sb=<sideband>\n"
|
"\t\tverbose:f=<freqHz>:bw=<bw_in_kHz>:bc=<if_in_Hz>:sb=<sideband>\n"
|
||||||
"\t\tagc=<tuner_gain_mode>:gain=<tenth_dB>:ifm=<tuner_if_mode>:dagc=<rtl_agc>\n"
|
"\t\tagc=<tuner_gain_mode>:gain=<tenth_dB>:ifm=<tuner_if_mode>:dagc=<rtl_agc>\n"
|
||||||
|
#if ENABLE_VCO_OPTIONS
|
||||||
|
"\t\tds=<direct_sampling>:dm=<ds_mode_thresh>:vcocmin=<c>:vcocmax=<c>:vcoalgo=<a>\n"
|
||||||
|
"\t\tT=<bias_tee>\n"
|
||||||
|
#else
|
||||||
"\t\tds=<direct_sampling>:dm=<ds_mode_thresh>:T=<bias_tee>\n"
|
"\t\tds=<direct_sampling>:dm=<ds_mode_thresh>:T=<bias_tee>\n"
|
||||||
|
#endif
|
||||||
#ifdef WITH_UDP_SERVER
|
#ifdef WITH_UDP_SERVER
|
||||||
"\t\tport=<udp_port default with 1>\n"
|
"\t\tport=<udp_port default with 1>\n"
|
||||||
#endif
|
#endif
|
||||||
|
@ -4314,6 +4330,47 @@ int rtlsdr_set_opt_string(rtlsdr_dev_t *dev, const char *opts, int verbose)
|
||||||
dev->direct_sampling_threshold = dm;
|
dev->direct_sampling_threshold = dm;
|
||||||
ret = rtlsdr_set_ds_mode(dev, dev->direct_sampling_mode, dev->direct_sampling_threshold);
|
ret = rtlsdr_set_ds_mode(dev, dev->direct_sampling_mode, dev->direct_sampling_threshold);
|
||||||
}
|
}
|
||||||
|
#if ENABLE_VCO_OPTIONS
|
||||||
|
else if (!strncmp(optPart, "vcocmin=", 8)) {
|
||||||
|
int current = atoi(optPart +8);
|
||||||
|
if ( 0 <= current && current <= 7 )
|
||||||
|
{
|
||||||
|
dev->r82xx_c.vco_curr_min = 7 - current;
|
||||||
|
ret = 0;
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed vcocmin config %d\n", current);
|
||||||
|
} else if (verbose) {
|
||||||
|
fprintf(stderr, "\nrtlsdr_set_opt_string(): error parsing vcocmin config: valid range 0 .. 7\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strncmp(optPart, "vcocmax=", 8)) {
|
||||||
|
int current = atoi(optPart +8);
|
||||||
|
if ( 0 <= current && current <= 7 )
|
||||||
|
{
|
||||||
|
dev->r82xx_c.vco_curr_max = 7 - current;
|
||||||
|
ret = 0;
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed vcocmax config %d\n", current);
|
||||||
|
} else if (verbose) {
|
||||||
|
fprintf(stderr, "\nrtlsdr_set_opt_string(): error parsing vcocmax config: valid range 0 .. 7\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!strncmp(optPart, "vcoalgo=", 8)) {
|
||||||
|
int algo = atoi(optPart +8);
|
||||||
|
if ( 0 <= algo && algo <= 2 )
|
||||||
|
{
|
||||||
|
dev->r82xx_c.vco_curr_max = algo;
|
||||||
|
ret = 0;
|
||||||
|
if (verbose)
|
||||||
|
fprintf(stderr, "\nrtlsdr_set_opt_string(): parsed vcoalgo config %d\n", algo);
|
||||||
|
} else if (verbose) {
|
||||||
|
fprintf(stderr, "\nrtlsdr_set_opt_string(): error parsing vcoalgo config: valid range 0 .. 2\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else if (!strncmp(optPart, "tp=", 3) || !strncmp(optPart, "Tp=", 3) || !strncmp(optPart, "TP=", 3) ) {
|
else if (!strncmp(optPart, "tp=", 3) || !strncmp(optPart, "Tp=", 3) || !strncmp(optPart, "TP=", 3) ) {
|
||||||
int gpio_pin_no = atoi(optPart +3);
|
int gpio_pin_no = atoi(optPart +3);
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
|
|
@ -107,6 +107,8 @@ void usage(void)
|
||||||
"\t[-d device_index or serial (default: 0)]\n"
|
"\t[-d device_index or serial (default: 0)]\n"
|
||||||
"%s"
|
"%s"
|
||||||
"\t[-t enable tuner range benchmark]\n"
|
"\t[-t enable tuner range benchmark]\n"
|
||||||
|
"\t[-f first/begin frequency for tuner range benchmark, default: 0]\n"
|
||||||
|
"\t[-e end frequency for tuner range benchmark, default: 3e9 = 3G ]\n"
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
"\t[-p[seconds] enable PPM error measurement (default: 10 seconds)]\n"
|
"\t[-p[seconds] enable PPM error measurement (default: 10 seconds)]\n"
|
||||||
#endif
|
#endif
|
||||||
|
@ -338,9 +340,9 @@ static int set_center_freq_wait(rtlsdr_dev_t *dev, uint32_t freq, const char * s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void tuner_benchmark(void)
|
void tuner_benchmark(uint32_t beg_freq, uint32_t end_freq)
|
||||||
{
|
{
|
||||||
uint32_t current = max_step(0);
|
uint32_t current = beg_freq; /* max_step(0); */
|
||||||
uint32_t band_start = 0;
|
uint32_t band_start = 0;
|
||||||
uint32_t low_bound = 0, high_bound = 0;
|
uint32_t low_bound = 0, high_bound = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -357,16 +359,16 @@ void tuner_benchmark(void)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* handle bands starting at 0Hz */
|
/* handle bands starting at 0Hz */
|
||||||
rc = set_center_freq_wait(dev, 0, "FIND_START");
|
rc = set_center_freq_wait(dev, current, "FIND_START");
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
state = FIND_START;
|
state = FIND_START;
|
||||||
else {
|
else {
|
||||||
band_start = 0;
|
band_start = current;
|
||||||
report_band_start(band_start);
|
report_band_start(band_start);
|
||||||
state = FIND_END;
|
state = FIND_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (current < 3e9 && !do_exit) {
|
while (current < end_freq && !do_exit) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case FIND_START:
|
case FIND_START:
|
||||||
/* scanning for the start of a new band */
|
/* scanning for the start of a new band */
|
||||||
|
@ -508,10 +510,12 @@ int main(int argc, char **argv)
|
||||||
int dev_index = 0;
|
int dev_index = 0;
|
||||||
int dev_given = 0;
|
int dev_given = 0;
|
||||||
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
uint32_t out_block_size = DEFAULT_BUF_LENGTH;
|
||||||
|
uint32_t tuner_bench_beg_freq = 0;
|
||||||
|
uint32_t tuner_bench_end_freq = 0;
|
||||||
int count;
|
int count;
|
||||||
int gains[100];
|
int gains[100];
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "d:s:b:O:tp::Sh")) != -1) {
|
while ((opt = getopt(argc, argv, "d:s:b:O:tf:e:p::Sh")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'd':
|
case 'd':
|
||||||
dev_index = verbose_device_search(optarg);
|
dev_index = verbose_device_search(optarg);
|
||||||
|
@ -529,6 +533,12 @@ int main(int argc, char **argv)
|
||||||
case 't':
|
case 't':
|
||||||
test_mode = TUNER_BENCHMARK;
|
test_mode = TUNER_BENCHMARK;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
tuner_bench_beg_freq = (uint32_t)atofs(optarg);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
tuner_bench_end_freq = (uint32_t)atofs(optarg);
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
test_mode = PPM_BENCHMARK;
|
test_mode = PPM_BENCHMARK;
|
||||||
if (optarg)
|
if (optarg)
|
||||||
|
@ -598,7 +608,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_mode == TUNER_BENCHMARK) {
|
if (test_mode == TUNER_BENCHMARK) {
|
||||||
tuner_benchmark();
|
tuner_benchmark(tuner_bench_beg_freq, tuner_bench_end_freq);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
#define WITH_ASYM_FILTER 0
|
#define WITH_ASYM_FILTER 0
|
||||||
#define PRINT_PLL_ERRORS 0
|
#define PRINT_PLL_ERRORS 0
|
||||||
#define PRINT_VGA_REG 0
|
#define PRINT_VGA_REG 0
|
||||||
|
#define PRINT_INITIAL_REGISTERS 0
|
||||||
|
#define PRINT_ACTUAL_VCO_AND_ERR 0
|
||||||
|
|
||||||
|
|
||||||
/* #define VGA_FOR_AGC_MODE 16 */
|
/* #define VGA_FOR_AGC_MODE 16 */
|
||||||
#define DEFAULT_IF_VGA_VAL 11
|
#define DEFAULT_IF_VGA_VAL 11
|
||||||
|
@ -280,35 +283,35 @@ static const uint8_t r82xx_init_array[] = {
|
||||||
|
|
||||||
0xc0, /* Reg 0x08 */
|
0xc0, /* Reg 0x08 */
|
||||||
0x40, /* Reg 0x09 */
|
0x40, /* Reg 0x09 */
|
||||||
0xdb, /* Reg 0x0a */
|
0xdb, /* Reg 0x0a */
|
||||||
0x6b, /* Reg 0x0b */
|
0x6b, /* Reg 0x0b */
|
||||||
|
|
||||||
/* Reg 0x0c:
|
/* Reg 0x0c:
|
||||||
* for manual gain was: set fixed VGA gain for now (16.3 dB): 0x08
|
* for manual gain was: set fixed VGA gain for now (16.3 dB): 0x08
|
||||||
* with active agc was: set fixed VGA gain for now (26.5 dB): 0x0b */
|
* with active agc was: set fixed VGA gain for now (26.5 dB): 0x0b */
|
||||||
0xe0 | DEFAULT_IF_VGA_VAL, /* Reg 0x0c */
|
0xe0 | DEFAULT_IF_VGA_VAL, /* Reg 0x0c */
|
||||||
0x53, /* Reg 0x0d */
|
0x53, /* Reg 0x0d */
|
||||||
0x75, /* Reg 0x0e */
|
0x75, /* Reg 0x0e */
|
||||||
0x68, /* Reg 0x0f */
|
0x68, /* Reg 0x0f */
|
||||||
|
|
||||||
0x6c, /* Reg 0x10 */
|
0x6c, /* Reg 0x10 */
|
||||||
0xbb, /* Reg 0x11 */
|
0xbb, /* Reg 0x11 */
|
||||||
0x80, /* Reg 0x12 */
|
0x80, /* Reg 0x12 */
|
||||||
VER_NUM & 0x3f, /* Reg 0x13 */
|
VER_NUM & 0x3f, /* Reg 0x13 */
|
||||||
|
|
||||||
0x0f, /* Reg 0x14 */
|
0x0f, /* Reg 0x14 */
|
||||||
0x00, /* Reg 0x15 */
|
0x00, /* Reg 0x15 */
|
||||||
0xc0, /* Reg 0x16 */
|
0xc0, /* Reg 0x16 */
|
||||||
0x30, /* Reg 0x17 */
|
0x30, /* Reg 0x17 */
|
||||||
|
|
||||||
0x48, /* Reg 0x18 */
|
0x48, /* Reg 0x18 */
|
||||||
0xec, /* Reg 0x19 */
|
0xec, /* Reg 0x19 */
|
||||||
0x60, /* Reg 0x1a */
|
0x60, /* Reg 0x1a */
|
||||||
0x00, /* Reg 0x1b */
|
0x00, /* Reg 0x1b */
|
||||||
|
|
||||||
0x24, /* Reg 0x1c */
|
0x24, /* Reg 0x1c */
|
||||||
0xdd, /* Reg 0x1d */
|
0xdd, /* Reg 0x1d */
|
||||||
0x0e, /* Reg 0x1e */
|
0x0e, /* Reg 0x1e */
|
||||||
0x40 /* Reg 0x1f */
|
0x40 /* Reg 0x1f */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -711,6 +714,128 @@ static int r82xx_set_mux(struct r82xx_priv *priv, uint32_t freq)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* function of Youssef (AirSpy) and Carl (RTL-SDR) */
|
||||||
|
static int r82xx_set_pll_yc(struct r82xx_priv *priv, uint32_t freq)
|
||||||
|
{
|
||||||
|
const uint32_t vco_min = 1770000000;
|
||||||
|
const uint32_t vco_max = 3900000000;
|
||||||
|
uint32_t pll_ref = (priv->cfg->xtal);
|
||||||
|
uint32_t pll_ref_2x = (pll_ref * 2);
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
uint32_t vco_exact;
|
||||||
|
uint32_t vco_frac;
|
||||||
|
uint32_t con_frac;
|
||||||
|
uint32_t div_num;
|
||||||
|
uint32_t n_sdm;
|
||||||
|
uint16_t sdm;
|
||||||
|
uint8_t ni;
|
||||||
|
uint8_t si;
|
||||||
|
uint8_t nint;
|
||||||
|
uint8_t val_dith;
|
||||||
|
uint8_t data[5];
|
||||||
|
|
||||||
|
/* Calculate divider */
|
||||||
|
for (div_num = 0; div_num < 5; div_num++)
|
||||||
|
{
|
||||||
|
vco_exact = freq << (div_num + 1);
|
||||||
|
if (vco_exact >= vco_min && vco_exact <= vco_max)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vco_exact = freq << (div_num + 1);
|
||||||
|
nint = (uint8_t) ((vco_exact + (pll_ref >> 16)) / pll_ref_2x);
|
||||||
|
vco_frac = vco_exact - pll_ref_2x * nint;
|
||||||
|
|
||||||
|
nint -= 13;
|
||||||
|
ni = (nint >> 2);
|
||||||
|
si = nint - (ni << 2);
|
||||||
|
|
||||||
|
/* Set the phase splitter */
|
||||||
|
rc = r82xx_write_reg_mask(priv, 0x10, (uint8_t) (div_num << 5), 0xe0);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Disable Dither */
|
||||||
|
val_dith = (priv->disable_dither) ? 0x10 : 0x00;
|
||||||
|
rc = r82xx_write_reg_mask(priv, 0x12, val_dith, 0x18);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Set the rough VCO frequency */
|
||||||
|
rc = r82xx_write_reg(priv, 0x14, (uint8_t) (ni + (si << 6)));
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (vco_frac == 0)
|
||||||
|
{
|
||||||
|
/* Disable frac pll */
|
||||||
|
rc = r82xx_write_reg_mask(priv, 0x12, 0x08, 0x08);
|
||||||
|
if(rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vco_frac += pll_ref >> 16;
|
||||||
|
sdm = 0;
|
||||||
|
for(n_sdm = 0; n_sdm < 16; n_sdm++)
|
||||||
|
{
|
||||||
|
con_frac = pll_ref >> n_sdm;
|
||||||
|
if (vco_frac >= con_frac)
|
||||||
|
{
|
||||||
|
sdm |= (uint16_t) (0x8000 >> n_sdm);
|
||||||
|
vco_frac -= con_frac;
|
||||||
|
if (vco_frac == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
actual_freq = (((nint << 16) + sdm) * (uint64_t) pll_ref_2x) >> (div_num + 1 + 16);
|
||||||
|
delta = freq - actual_freq
|
||||||
|
if (actual_freq != freq)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Tunning delta: %d Hz", delta);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
rc = r82xx_write_reg(priv, 0x15, (uint8_t)(sdm & 0xff));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = r82xx_write_reg(priv, 0x16, (uint8_t)(sdm >> 8));
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Enable frac pll */
|
||||||
|
rc = r82xx_write_reg_mask(priv, 0x12, 0x00, 0x08);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***/
|
||||||
|
|
||||||
|
/* Check if PLL has locked */
|
||||||
|
rc = r82xx_read(priv, 0x00, data, 3);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
if (!(data[2] & 0x40)) {
|
||||||
|
#if PRINT_PLL_ERRORS
|
||||||
|
fprintf(stderr, "[R82XX] PLL not locked at Tuner LO %u Hz for RF %u Hz!\n",
|
||||||
|
freq, priv->rf_freq);
|
||||||
|
#endif
|
||||||
|
priv->has_lock = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
priv->has_lock = 1;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
||||||
{
|
{
|
||||||
/* freq == tuner's LO frequency */
|
/* freq == tuner's LO frequency */
|
||||||
|
@ -718,7 +843,7 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
||||||
uint64_t vco_freq;
|
uint64_t vco_freq;
|
||||||
uint64_t vco_div;
|
uint64_t vco_div;
|
||||||
uint32_t vco_min = 1770000; /* kHz */
|
uint32_t vco_min = 1770000; /* kHz */
|
||||||
uint32_t vco_max = vco_min * 2; /* kHz */
|
uint32_t vco_max = (priv->cfg->vco_algo == 0) ? (vco_min * 2) : 3900000; /* kHz */
|
||||||
uint32_t freq_khz, pll_ref;
|
uint32_t freq_khz, pll_ref;
|
||||||
uint32_t sdm = 0;
|
uint32_t sdm = 0;
|
||||||
uint8_t mix_div = 2;
|
uint8_t mix_div = 2;
|
||||||
|
@ -727,8 +852,24 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
||||||
uint8_t vco_power_ref = 2;
|
uint8_t vco_power_ref = 2;
|
||||||
uint8_t refdiv2 = 0;
|
uint8_t refdiv2 = 0;
|
||||||
uint8_t ni, si, nint, vco_fine_tune, val;
|
uint8_t ni, si, nint, vco_fine_tune, val;
|
||||||
|
uint8_t vco_curr_min = (priv->cfg->vco_curr_min == 0xff) ? 0x80 : ( priv->cfg->vco_curr_min << 5 );
|
||||||
|
uint8_t vco_curr_max = (priv->cfg->vco_curr_max == 0xff) ? 0x60 : ( priv->cfg->vco_curr_max << 5 );
|
||||||
|
/* devt->r82xx_c.vco_min = 0xff; * VCO min/max current for R18/0x12 bits [7:5] in 0 .. 7. use 0xff for default */
|
||||||
|
/* devt->r82xx_c.vco_max = 0xff; * value is inverted: programmed is 7-value, that 0 is lowest current */
|
||||||
uint8_t data[5];
|
uint8_t data[5];
|
||||||
|
|
||||||
|
if (priv->cfg->vco_algo == 2)
|
||||||
|
{
|
||||||
|
/* r82xx_set_pll_yc() assumes fixed maximum current */
|
||||||
|
if (priv->last_vco_curr != vco_curr_max) {
|
||||||
|
rc = r82xx_write_reg_mask(priv, 0x12, vco_curr_max, 0xe0);
|
||||||
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
priv->last_vco_curr = vco_curr_max;
|
||||||
|
}
|
||||||
|
return r82xx_set_pll_yc(priv, freq);
|
||||||
|
}
|
||||||
|
|
||||||
/* Frequency in kHz */
|
/* Frequency in kHz */
|
||||||
freq_khz = (freq + 500) / 1000;
|
freq_khz = (freq + 500) / 1000;
|
||||||
pll_ref = priv->cfg->xtal;
|
pll_ref = priv->cfg->xtal;
|
||||||
|
@ -743,9 +884,12 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* set VCO current = 100 */
|
/* set VCO current = 100 */
|
||||||
rc = r82xx_write_reg_mask(priv, 0x12, 0x80, 0xe0);
|
if (priv->last_vco_curr != vco_curr_min) {
|
||||||
if (rc < 0)
|
rc = r82xx_write_reg_mask(priv, 0x12, vco_curr_min, 0xe0);
|
||||||
return rc;
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
priv->last_vco_curr = vco_curr_min;
|
||||||
|
}
|
||||||
|
|
||||||
/* Calculate divider */
|
/* Calculate divider */
|
||||||
while (mix_div <= 64) {
|
while (mix_div <= 64) {
|
||||||
|
@ -802,10 +946,10 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
||||||
nint = (uint32_t) (vco_div / 65536);
|
nint = (uint32_t) (vco_div / 65536);
|
||||||
sdm = (uint32_t) (vco_div % 65536);
|
sdm = (uint32_t) (vco_div % 65536);
|
||||||
|
|
||||||
#if 0
|
#if PRINT_ACTUAL_VCO_AND_ERR
|
||||||
{
|
{
|
||||||
uint64_t actual_vco = (uint64_t)2 * pll_ref * nint + (uint64_t)2 * pll_ref * sdm / 65536;
|
uint64_t actual_vco = (uint64_t)2 * pll_ref * nint + (uint64_t)2 * pll_ref * sdm / 65536;
|
||||||
fprintf(stderr, "[R82XX] requested %uHz; selected mix_div=%u vco_freq=%lu nint=%u sdm=%u; actual_vco=%lu; tuning error=%+dHz\n",
|
fprintf(stderr, "[R82XX] requested %u Hz; selected mix_div=%u vco_freq=%lu nint=%u sdm=%u; actual_vco=%lu; tuning error=%+dHz\n",
|
||||||
freq, mix_div, vco_freq, nint, sdm, actual_vco, (int32_t) (actual_vco - vco_freq) / mix_div);
|
freq, mix_div, vco_freq, nint, sdm, actual_vco, (int32_t) (actual_vco - vco_freq) / mix_div);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -850,14 +994,17 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
|
||||||
rc = r82xx_read(priv, 0x00, data, 3);
|
rc = r82xx_read(priv, 0x00, data, 3);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
if (data[2] & 0x40)
|
if ( (data[2] & 0x40) || vco_curr_max == vco_curr_min )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!i) {
|
if (!i) {
|
||||||
/* Didn't lock. Increase VCO current */
|
/* Didn't lock. Increase VCO current */
|
||||||
rc = r82xx_write_reg_mask(priv, 0x12, 0x60, 0xe0);
|
if (priv->last_vco_curr != vco_curr_max) {
|
||||||
if (rc < 0)
|
rc = r82xx_write_reg_mask(priv, 0x12, vco_curr_max, 0xe0);
|
||||||
return rc;
|
if (rc < 0)
|
||||||
|
return rc;
|
||||||
|
priv->last_vco_curr = vco_curr_max;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1752,6 +1899,19 @@ int r82xx_init(struct r82xx_priv *priv)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
#if PRINT_INITIAL_REGISTERS
|
||||||
|
#define INIT_NUM_READ_REGS 16
|
||||||
|
uint8_t initial_register_values[INIT_NUM_READ_REGS]; /* see what is 'default' */
|
||||||
|
int k;
|
||||||
|
/* get initial register values - just to see .. */
|
||||||
|
memset( &(initial_register_values[0]), 0, sizeof(initial_register_values) );
|
||||||
|
printf("R820T/2 initial register settings:\n");
|
||||||
|
r82xx_read(priv, 0x00, initial_register_values, sizeof(initial_register_values));
|
||||||
|
for (k=0; k < INIT_NUM_READ_REGS; ++k)
|
||||||
|
printf("register 0x%02x: 0x%02x\n", k, initial_register_values[k]);
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* TODO: R828D might need r82xx_xtal_check() */
|
/* TODO: R828D might need r82xx_xtal_check() */
|
||||||
priv->xtal_cap_sel = XTAL_HIGH_CAP_0P;
|
priv->xtal_cap_sel = XTAL_HIGH_CAP_0P;
|
||||||
|
|
||||||
|
@ -1764,6 +1924,7 @@ int r82xx_init(struct r82xx_priv *priv)
|
||||||
priv->last_LNA_value = 0;
|
priv->last_LNA_value = 0;
|
||||||
priv->last_Mixer_value = 0;
|
priv->last_Mixer_value = 0;
|
||||||
priv->last_VGA_value = DEFAULT_IF_VGA_VAL;
|
priv->last_VGA_value = DEFAULT_IF_VGA_VAL;
|
||||||
|
priv->last_vco_curr = 0xff;
|
||||||
|
|
||||||
/* Initialize override registers */
|
/* Initialize override registers */
|
||||||
memset( &(priv->override_data[0]), 0, NUM_REGS * sizeof(uint8_t) );
|
memset( &(priv->override_data[0]), 0, NUM_REGS * sizeof(uint8_t) );
|
||||||
|
@ -1773,6 +1934,8 @@ int r82xx_init(struct r82xx_priv *priv)
|
||||||
rc = r82xx_write_arr(priv, 0x05,
|
rc = r82xx_write_arr(priv, 0x05,
|
||||||
r82xx_init_array, sizeof(r82xx_init_array));
|
r82xx_init_array, sizeof(r82xx_init_array));
|
||||||
|
|
||||||
|
priv->last_vco_curr = r82xx_init_array[0x12 - 0x05] & 0xe0;
|
||||||
|
|
||||||
rc = r82xx_set_tv_standard(priv, TUNER_DIGITAL_TV, 0);
|
rc = r82xx_set_tv_standard(priv, TUNER_DIGITAL_TV, 0);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
Loading…
Reference in New Issue