driver: Jowett's tuning

This is a squashing of roughly 25 commits to assist with merging
and organization.  It will be rebased as various sections are mainlined.
jowett
Oliver Jowett 2014-09-01 20:51:34 -04:00 zatwierdzone przez Kyle Keen
rodzic 88244c041c
commit e096ddb7f8
6 zmienionych plików z 293 dodań i 165 usunięć

Wyświetl plik

@ -144,10 +144,6 @@ RTLSDR_API int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data,
RTLSDR_API int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq);
RTLSDR_API int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq);
RTLSDR_API int rtlsdr_set_if_bandwidth(rtlsdr_dev_t *dev, int bw);
/*!
* Get actual frequency the device is tuned to.
*

Wyświetl plik

@ -203,7 +203,7 @@ int e4k_standby(struct e4k_state *e4k, int enable);
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_freq(struct e4k_state *e4k, uint32_t freq, uint32_t *lo_freq);
int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p);
uint32_t 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);

Wyświetl plik

@ -93,6 +93,13 @@ struct r82xx_priv {
enum r82xx_tuner_type type;
uint32_t bw; /* in MHz */
uint32_t if_filter_freq; /* in Hz */
int pll_off;
/* current PLL limits */
uint32_t pll_low_limit;
uint32_t pll_high_limit;
void *rtl_dev;
};
@ -116,11 +123,10 @@ enum r82xx_delivery_system {
int r82xx_standby(struct r82xx_priv *priv);
int r82xx_init(struct r82xx_priv *priv);
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq);
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq, uint32_t *lo_freq_out);
int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain);
int r82xx_set_nomod(struct r82xx_priv *priv);
int r82xx_set_dither(struct r82xx_priv *priv, int dither);
int r82xx_set_bw(struct r82xx_priv *priv, uint32_t bw);
int r82xx_set_if_freq(struct r82xx_priv *priv, uint32_t freq);
#endif

Wyświetl plik

@ -59,12 +59,11 @@ typedef struct rtlsdr_tuner_iface {
/* tuner interface */
int (*init)(void *);
int (*exit)(void *);
int (*set_freq)(void *, uint32_t freq /* Hz */);
int (*set_freq)(void *, uint32_t freq /* Hz */, uint32_t *lo_freq_out);
int (*set_bw)(void *, int bw /* Hz */);
int (*set_gain)(void *, int gain /* tenth dB */);
int (*set_if_gain)(void *, int stage, int gain /* tenth dB */);
int (*set_gain_mode)(void *, int manual);
int (*set_if_freq)(void *, uint32_t freq /* Hz */);
} rtlsdr_tuner_iface_t;
enum rtlsdr_async_status {
@ -115,6 +114,7 @@ struct rtlsdr_dev {
uint32_t tun_xtal; /* Hz */
uint32_t freq; /* Hz */
uint32_t offs_freq; /* Hz */
uint32_t effective_freq; /* Hz */
int corr; /* ppm */
int gain; /* tenth dB */
struct e4k_state e4k_s;
@ -126,6 +126,7 @@ struct rtlsdr_dev {
unsigned int xfer_errors;
int tuner_initialized;
int i2c_repeater_on;
int spectrum_inversion;
};
void rtlsdr_set_gpio_bit(rtlsdr_dev_t *dev, uint8_t gpio, int val);
@ -142,9 +143,9 @@ int e4000_exit(void *dev) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return e4k_standby(&devt->e4k_s, 1);
}
int e4000_set_freq(void *dev, uint32_t freq) {
int e4000_set_freq(void *dev, uint32_t freq, uint32_t *lo_freq_out) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return e4k_tune_freq(&devt->e4k_s, freq);
return e4k_tune_freq(&devt->e4k_s, freq, lo_freq_out);
}
int e4000_set_bw(void *dev, int bw) {
@ -186,8 +187,9 @@ int e4000_set_gain_mode(void *dev, int manual) {
int _fc0012_init(void *dev) { return fc0012_init(dev); }
int fc0012_exit(void *dev) { return 0; }
int fc0012_set_freq(void *dev, uint32_t freq) {
int fc0012_set_freq(void *dev, uint32_t freq, uint32_t *lo_freq_out) {
/* select V-band/U-band filter */
if (lo_freq_out) *lo_freq_out = freq;
rtlsdr_set_gpio_bit(dev, 6, (freq > 300000000) ? 1 : 0);
return fc0012_set_params(dev, freq, 6000000);
}
@ -197,7 +199,8 @@ int fc0012_set_gain_mode(void *dev, int manual) { return 0; }
int _fc0013_init(void *dev) { return fc0013_init(dev); }
int fc0013_exit(void *dev) { return 0; }
int fc0013_set_freq(void *dev, uint32_t freq) {
int fc0013_set_freq(void *dev, uint32_t freq, uint32_t *lo_freq_out) {
if (lo_freq_out) *lo_freq_out = freq;
return fc0013_set_params(dev, freq, 6000000);
}
int fc0013_set_bw(void *dev, int bw) { return 0; }
@ -205,7 +208,8 @@ int _fc0013_set_gain(void *dev, int gain) { return fc0013_set_lna_gain(dev, gain
int fc2580_init(void *dev) { return fc2580_Initialize(dev); }
int fc2580_exit(void *dev) { return 0; }
int _fc2580_set_freq(void *dev, uint32_t freq) {
int _fc2580_set_freq(void *dev, uint32_t freq, uint32_t *lo_freq_out) {
if (lo_freq_out) *lo_freq_out = freq;
return fc2580_SetRfFreqHz(dev, freq);
}
int fc2580_set_bw(void *dev, int bw) { return fc2580_SetBandwidthMode(dev, 1); }
@ -237,9 +241,9 @@ int r820t_exit(void *dev) {
return r82xx_standby(&devt->r82xx_p);
}
int r820t_set_freq(void *dev, uint32_t freq) {
int r820t_set_freq(void *dev, uint32_t freq, uint32_t *lo_freq_out) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_freq(&devt->r82xx_p, freq);
return r82xx_set_freq(&devt->r82xx_p, freq, lo_freq_out);
}
int r820t_set_bw(void *dev, int bw) {
@ -247,11 +251,6 @@ int r820t_set_bw(void *dev, int bw) {
return r82xx_set_bw(&devt->r82xx_p, bw);
}
int r820t_set_if_freq(void *dev, uint32_t freq) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_if_freq(&devt->r82xx_p, freq);
}
int r820t_set_gain(void *dev, int gain) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
return r82xx_set_gain(&devt->r82xx_p, 1, gain);
@ -264,37 +263,37 @@ int r820t_set_gain_mode(void *dev, int manual) {
/* definition order must match enum rtlsdr_tuner */
static rtlsdr_tuner_iface_t tuners[] = {
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */
NULL, NULL, NULL, NULL, NULL, NULL, NULL /* dummy for unknown tuners */
},
{
e4000_init, e4000_exit,
e4000_set_freq, e4000_set_bw, e4000_set_gain, e4000_set_if_gain,
e4000_set_gain_mode, NULL
e4000_set_gain_mode
},
{
_fc0012_init, fc0012_exit,
fc0012_set_freq, fc0012_set_bw, _fc0012_set_gain, NULL,
fc0012_set_gain_mode, NULL
fc0012_set_gain_mode
},
{
_fc0013_init, fc0013_exit,
fc0013_set_freq, fc0013_set_bw, _fc0013_set_gain, NULL,
fc0013_set_gain_mode, NULL
fc0013_set_gain_mode
},
{
fc2580_init, fc2580_exit,
_fc2580_set_freq, fc2580_set_bw, fc2580_set_gain, NULL,
fc2580_set_gain_mode, NULL
fc2580_set_gain_mode
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
r820t_set_gain_mode, r820t_set_if_freq
r820t_set_gain_mode
},
{
r820t_init, r820t_exit,
r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL,
r820t_set_gain_mode, r820t_set_if_freq
r820t_set_gain_mode
},
};
@ -633,6 +632,7 @@ void rtlsdr_init_baseband(rtlsdr_dev_t *dev)
/* disable spectrum inversion and adjacent channel rejection */
rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1);
dev->spectrum_inversion = 0;
rtlsdr_demod_write_reg(dev, 1, 0x16, 0x0000, 2);
/* clear both DDC shift and IF frequency registers */
@ -690,7 +690,7 @@ int rtlsdr_deinit_baseband(rtlsdr_dev_t *dev)
return r;
}
int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq)
static int rtl2832_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq, uint32_t *freq_out)
{
uint32_t rtl_xtal;
int32_t if_freq;
@ -705,7 +705,11 @@ int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq)
if (rtlsdr_get_xtal_freq(dev, &rtl_xtal, NULL))
return -2;
if_freq = ((freq * TWO_POW(22)) / rtl_xtal) * (-1);
if_freq = ((rtl_xtal/2 + (uint64_t)freq * TWO_POW(22)) / rtl_xtal) * (-1);
if (if_freq <= -0x200000) {
/* fprintf(stderr, "rtl2832_set_if_freq(): %u Hz out of range for downconverter (divisor would be %x)\n", freq, if_freq); */
return -2;
}
tmp = (if_freq >> 16) & 0x3f;
r = rtlsdr_demod_write_reg(dev, 1, 0x19, tmp, 1);
@ -714,13 +718,8 @@ int rtlsdr_set_if_freq(rtlsdr_dev_t *dev, uint32_t freq)
tmp = if_freq & 0xff;
r |= rtlsdr_demod_write_reg(dev, 1, 0x1b, tmp, 1);
/* Tell the R820T driver which IF frequency we are currently using
* so that it can choose the optimal IF filter settings.
* Works for normal tuning as well as no-mod direct sampling! */
if(dev->tuner_initialized && dev->tuner && dev->tuner->set_if_freq) {
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->set_if_freq(dev, freq);
}
if (freq_out) *freq_out = ((int64_t)if_freq * rtl_xtal * -1 + TWO_POW(21)) / TWO_POW(22);
return r;
}
@ -900,25 +899,60 @@ int rtlsdr_read_eeprom(rtlsdr_dev_t *dev, uint8_t *data, uint8_t offset, uint16_
return r;
}
static int set_spectrum_inversion(rtlsdr_dev_t *dev, int inverted)
{
int r = 0;
if (dev->spectrum_inversion == inverted)
return r;
r |= rtlsdr_demod_write_reg(dev, 1, 0x15, inverted, 1);
/* reset demod (bit 3, soft_rst) */
r |= rtlsdr_demod_write_reg(dev, 1, 0x01, 0x14, 1);
r |= rtlsdr_demod_write_reg(dev, 1, 0x01, 0x10, 1);
dev->spectrum_inversion = inverted;
return r;
}
int rtlsdr_set_center_freq(rtlsdr_dev_t *dev, uint32_t freq)
{
int r = -1;
uint32_t tuner_lo;
uint32_t tuner_if, actual_if = 0;
int inverted;
if (!dev || !dev->tuner)
return -1;
if (dev->direct_sampling) {
rtlsdr_set_i2c_repeater(dev, 0);
r = rtlsdr_set_if_freq(dev, freq);
tuner_lo = 0;
} else if (dev->tuner && dev->tuner->set_freq) {
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->set_freq(dev, freq - dev->offs_freq);
r = dev->tuner->set_freq(dev, freq - dev->offs_freq, &tuner_lo);
rtlsdr_set_i2c_repeater(dev, 0);
}
if (!r)
dev->freq = freq;
if (tuner_lo > freq) {
/* high-side mixing, enable spectrum inversion */
tuner_if = tuner_lo - freq;
inverted = 1;
} else {
/* low-side mixing, or zero-IF, or direct sampling; disable spectrum inversion */
tuner_if = freq - tuner_lo;
inverted = 0;
}
r |= set_spectrum_inversion(dev, inverted);
r |= rtl2832_set_if_freq(dev, tuner_if, &actual_if);
dev->freq = freq;
if (inverted)
dev->effective_freq = tuner_lo - actual_if;
else
dev->freq = 0;
dev->effective_freq = tuner_lo + actual_if;
return r;
}
@ -928,7 +962,7 @@ uint32_t rtlsdr_get_center_freq(rtlsdr_dev_t *dev)
if (!dev)
return 0;
return dev->freq;
return dev->effective_freq;
}
int rtlsdr_set_freq_correction(rtlsdr_dev_t *dev, int ppm)
@ -1171,58 +1205,36 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
if (!dev)
return -1;
/* set up normal direct sampling */
if (on == 1 || on == 2) {
if (on == dev->direct_sampling)
return 0;
rtlsdr_set_i2c_repeater(dev, 0);
/* common to all direct modes */
if (on) {
if (dev->tuner && dev->tuner->exit) {
rtlsdr_set_i2c_repeater(dev, 1);
r = dev->tuner->exit(dev);
rtlsdr_set_i2c_repeater(dev, 0);
dev->tuner_initialized = 0;
}
}
/* set up no-mod direct sampling */
if (on == 3 && dev->tuner) {
if (dev->tuner_type == RTLSDR_TUNER_E4000) {
fprintf(stderr, "Tuning E4000 to 3708 MHz\n");
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->init(dev);
dev->tuner_initialized = 1;
dev->tuner->set_freq(dev, 3708000000u);
e4000_set_bw(dev, 15000000);
rtlsdr_set_i2c_repeater(dev, 0);
}
if (dev->tuner_type == RTLSDR_TUNER_R820T) {
rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev;
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->init(dev);
dev->tuner_initialized = 1;
r82xx_set_nomod(&devt->r82xx_p);
rtlsdr_set_i2c_repeater(dev, 0);
}
}
rtlsdr_set_i2c_repeater(dev, 0);
/* common to all direct modes */
if (on) {
/* disable Zero-IF mode */
r |= rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);
/* disable spectrum inversion */
r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x00, 1);
/* only enable In-phase ADC input */
r |= rtlsdr_demod_write_reg(dev, 0, 0x08, 0x4d, 1);
/* swap I and Q ADC, this allows to select between two inputs */
r |= rtlsdr_demod_write_reg(dev, 0, 0x06, (on == 2) ? 0x90 : 0x80, 1);
/* disable spectrum inversion */
r |= set_spectrum_inversion(dev, 0);
fprintf(stderr, "Enabled direct sampling mode, input %i\n", on);
dev->direct_sampling = on;
}
/* disable direct sampling */
if (!on) {
} else {
/* disable direct sampling */
if (dev->tuner && dev->tuner->init) {
rtlsdr_set_i2c_repeater(dev, 1);
r |= dev->tuner->init(dev);
@ -1232,13 +1244,14 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
if ((dev->tuner_type == RTLSDR_TUNER_R820T) ||
(dev->tuner_type == RTLSDR_TUNER_R828D)) {
r |= rtlsdr_set_if_freq(dev, R82XX_DEFAULT_IF_FREQ);
/* disable Zero-IF mode */
r |= rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);
/* enable spectrum inversion */
r |= rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
/* only enable In-phase ADC input */
r |= rtlsdr_demod_write_reg(dev, 0, 0x08, 0x4d, 1);
/* Already configured */
} else {
r |= rtlsdr_set_if_freq(dev, 0);
/* enable In-phase + Quadrature ADC input */
r |= rtlsdr_demod_write_reg(dev, 0, 0x08, 0xcd, 1);
@ -1253,6 +1266,7 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on)
dev->direct_sampling = 0;
}
/* retune now that we have changed the config */
r |= rtlsdr_set_center_freq(dev, dev->freq);
return r;
@ -1283,17 +1297,14 @@ int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on)
/* based on keenerds 1/f noise measurements */
dev->offs_freq = on ? ((dev->rate / 2) * 170 / 100) : 0;
r |= rtlsdr_set_if_freq(dev, dev->offs_freq);
if (dev->tuner && dev->tuner->set_bw) {
rtlsdr_set_i2c_repeater(dev, 1);
dev->tuner->set_bw(dev, on ? (2 * dev->offs_freq) : dev->rate);
r |= dev->tuner->set_bw(dev, on ? (2 * dev->offs_freq) : dev->rate);
rtlsdr_set_i2c_repeater(dev, 0);
}
if (dev->freq > dev->offs_freq)
r |= rtlsdr_set_center_freq(dev, dev->freq);
r |= rtlsdr_set_center_freq(dev, dev->freq);
return r;
}
@ -1622,12 +1633,6 @@ found:
/* only enable In-phase ADC input */
rtlsdr_demod_write_reg(dev, 0, 0x08, 0x4d, 1);
/* the R82XX use 3.57 MHz IF for the DVB-T 6 MHz mode, and
* 4.57 MHz for the 8 MHz mode */
rtlsdr_set_if_freq(dev, R82XX_DEFAULT_IF_FREQ);
/* enable spectrum inversion */
rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1);
break;
case RTLSDR_TUNER_UNKNOWN:
fprintf(stderr, "No supported tuner found\n");

Wyświetl plik

@ -213,7 +213,7 @@ int e4k_rf_filter_set(struct e4k_state *e4k)
{
int rc;
rc = choose_rf_filter(e4k->band, e4k->vco.flo);
rc = choose_rf_filter(e4k->band, e4k->vco.intended_flo);
if (rc < 0)
return rc;
@ -338,16 +338,17 @@ int e4k_if_filter_bw_get(struct e4k_state *e4k, enum e4k_if_filter filter)
/***********************************************************************
* 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
#define E4K_FVCO_MIN_KHZ 2400000UL /* 2.4 GHz; min FLO is 2400/48 = 50MHz */
#define E4K_FVCO_MAX_KHZ 4400000UL /* 4.4 GHz; max FLO is 4400/2 = 2200MHz */
#else
#define E4K_FLO_MIN_MHZ 64
#define E4K_FLO_MAX_MHZ 1700
/* NB: Datasheet values for RF input and LO ranges are 64 - 1700MHz.
* The values below are from the slightly wider VCO ranges.
*/
#define E4K_FVCO_MIN_KHZ 2600000UL /* 2.6 GHz; min FLO is 2600/48 = 54MHz */
#define E4K_FVCO_MAX_KHZ 3900000UL /* 3.9 GHz; max FLO is 3900/2 = 1950MHz */
#endif
struct pll_settings {
@ -505,6 +506,11 @@ uint32_t e4k_compute_pll_params(struct e4k_pll_params *oscp, uint32_t fosc, uint
/* flo(max) = 1700MHz, R(max) = 48, we need 64bit! */
intended_fvco = (uint64_t)intended_flo * r;
if (intended_fvco < KHZ(E4K_FVCO_MIN_KHZ)) {
intended_fvco = KHZ(E4K_FVCO_MIN_KHZ);
} else if (intended_fvco > KHZ(E4K_FVCO_MAX_KHZ)) {
intended_fvco = KHZ(E4K_FVCO_MAX_KHZ);
}
/* compute integral component of multiplier */
z = intended_fvco / fosc;
@ -545,11 +551,11 @@ int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p)
memcpy(&e4k->vco, p, sizeof(e4k->vco));
/* set the band */
if (e4k->vco.flo < MHZ(140))
if (e4k->vco.intended_flo < MHZ(140))
e4k_band_set(e4k, E4K_BAND_VHF2);
else if (e4k->vco.flo < MHZ(350))
else if (e4k->vco.intended_flo < MHZ(350))
e4k_band_set(e4k, E4K_BAND_VHF3);
else if (e4k->vco.flo < MHZ(1135))
else if (e4k->vco.intended_flo < MHZ(1135))
e4k_band_set(e4k, E4K_BAND_UHF);
else
e4k_band_set(e4k, E4K_BAND_L);
@ -567,9 +573,10 @@ int e4k_tune_params(struct e4k_state *e4k, struct e4k_pll_params *p)
*
* \param[in] e4k reference to tuner
* \param[in] freq frequency in Hz
* \returns actual tuned frequency, negative in case of error
* \param[out] lo_freq if non-NULL, set to actually tuned frequency in Hz
* \returns zero on success, negative on error
*/
int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq)
int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq, uint32_t *lo_freq)
{
uint32_t rc;
struct e4k_pll_params p;
@ -589,6 +596,9 @@ int e4k_tune_freq(struct e4k_state *e4k, uint32_t freq)
return -1;
}
if (lo_freq)
*lo_freq = e4k->vco.flo;
return 0;
}

Wyświetl plik

@ -37,6 +37,30 @@
* Static constants
*/
/*
* These should be "safe" values, always. If we fail to get PLL lock in this range,
* it's a hard error.
*/
#define PLL_SAFE_LOW 28e6
#define PLL_SAFE_HIGH 1845e6
/*
* These are the initial, widest, PLL limits that we will try.
*
* Be cautious with lowering the low bound further - the PLL can claim to be locked
* when configured to a lower frequency, but actually be running at around 26.6MHz
* regardless of what it was configured for.
*
* This shows up as a tuning offset at low frequencies, and a "dead zone" about
* 6MHz below the PLL lower bound where retuning within that region has no effect.
*/
#define PLL_INITIAL_LOW 26.7e6
#define PLL_INITIAL_HIGH 1860e6
/* We shrink the range edges by at least this much each time there is a soft PLL lock failure */
#define PLL_STEP_LOW 0.1e6
#define PLL_STEP_HIGH 1.0e6
/* Those initial values start from REG_SHADOW_START */
static const uint8_t r82xx_init_array[NUM_REGS] = {
0x83, 0x32, 0x75, /* 05 to 07 */
@ -344,7 +368,7 @@ static int r82xx_write_batch_sync(struct r82xx_priv *priv)
return -1;
priv->reg_batch = 0;
if (priv->reg_low > priv->reg_high)
return 0; /* No registers were changed */
return 0; /* No work to do */
offset = priv->reg_low - REG_SHADOW_START;
len = priv->reg_high - priv->reg_low + 1;
rc = r82xx_write(priv, priv->reg_low, priv->regs+offset, len);
@ -451,13 +475,13 @@ static int r82xx_set_mux(struct r82xx_priv *priv, uint32_t freq)
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, uint32_t *freq_out)
{
int rc, i;
unsigned sleep_time = 10000;
uint64_t vco_freq;
uint64_t vco_div;
uint32_t vco_min = 1770000; /* kHz */
uint32_t vco_min = 1750000; /* kHz */
uint32_t vco_max = vco_min * 2; /* kHz */
uint32_t freq_khz, pll_ref;
uint32_t sdm = 0;
@ -485,30 +509,16 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
return rc;
/* set VCO current = 100 */
priv->pll_off = 0;
rc = r82xx_write_reg_mask(priv, 0x12, 0x80, 0xe0);
if (rc < 0)
return rc;
/* Calculate divider */
if(freq_khz < vco_min/64) vco_min /= 2;
if(freq_khz >= vco_max/2) vco_max *= 2;
while (mix_div <= 64) {
if (((freq_khz * mix_div) >= vco_min) &&
((freq_khz * mix_div) < vco_max)) {
div_buf = mix_div;
while (div_buf > 2) {
div_buf = div_buf >> 1;
div_num++;
}
break;
}
mix_div = mix_div << 1;
}
if (mix_div > 64) {
fprintf(stderr, "[R82XX] No valid PLL values for %u Hz!\n", freq);
return -1;
}
for (mix_div = 2, div_num = 0; mix_div < 64; mix_div <<= 1, div_num++)
if ((freq_khz * mix_div) >= vco_min)
break;
if (priv->cfg->rafael_chip == CHIP_R828D)
vco_power_ref = 1;
@ -557,6 +567,11 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
ni = (nint - 13) / 4;
si = nint - 4 * ni - 13;
if (freq_out) {
uint64_t actual_vco = (uint64_t)2 * pll_ref * nint + (uint64_t)2 * pll_ref * sdm / 65536;
*freq_out = (uint32_t) ((actual_vco + mix_div/2) / mix_div);
}
rc = r82xx_write_reg(priv, 0x14, ni + (si << 6));
if (rc < 0)
return rc;
@ -574,8 +589,6 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
if (rc < 0)
return rc;
//fprintf(stderr, "LO: %u kHz, MixDiv: %u, PLLDiv: %u, VCO %u kHz, SDM: %u \n", (uint32_t)(freq/1000), mix_div, nint, (uint32_t)(vco_freq/1000), sdm);
rc = r82xx_write_reg(priv, 0x16, sdm >> 8);
if (rc < 0)
return rc;
@ -611,8 +624,7 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq)
}
if (!(data[2] & 0x40)) {
fprintf(stderr, "[R82XX] PLL not locked!\n");
return -1;
return -42;
}
/* set pll autotune = 8kHz */
@ -906,10 +918,14 @@ static int r82xx_init_tv_standard(struct r82xx_priv *priv,
return 0;
}
static int r82xx_set_if_filter(struct r82xx_priv *priv, int hpf, int lpf) {
int rc, i;
static int update_if_filter(struct r82xx_priv *priv) {
int rc, i, hpf, lpf;
uint8_t filt_q, hp_cor;
int cal;
hpf = ((int)priv->if_filter_freq - (int)priv->bw/2)/1000;
lpf = ((int)priv->if_filter_freq + (int)priv->bw/2)/1000;
filt_q = 0x10; /* r10[4]:low q(1'b1) */
if(lpf <= 2500) {
@ -950,8 +966,6 @@ static int r82xx_set_if_filter(struct r82xx_priv *priv, int hpf, int lpf) {
else if(cal > 15) cal = 15;
priv->fil_cal_code = cal;
//fprintf(stderr, "Setting IF filter for %d...%d kHz: hp_cor=0x%02x, fil_cal_code=%d\n", hpf, lpf, hp_cor, cal);
rc = r82xx_write_reg_mask(priv, 0x0a,
filt_q | priv->fil_cal_code, 0x1f);
if (rc < 0)
@ -967,12 +981,7 @@ static int r82xx_set_if_filter(struct r82xx_priv *priv, int hpf, int lpf) {
int r82xx_set_bw(struct r82xx_priv *priv, uint32_t bw) {
priv->bw = bw;
return r82xx_set_if_filter(priv, ((int)priv->int_freq - (int)bw/2)/1000, ((int)priv->int_freq + (int)bw/2)/1000);
}
int r82xx_set_if_freq(struct r82xx_priv *priv, uint32_t freq) {
priv->int_freq = freq;
return r82xx_set_if_filter(priv, ((int)freq - (int)priv->bw/2)/1000, ((int)freq + (int)priv->bw/2)/1000);
return update_if_filter(priv);
}
static int r82xx_read_gain(struct r82xx_priv *priv)
@ -1074,21 +1083,19 @@ int r82xx_set_gain(struct r82xx_priv *priv, int set_manual_gain, int gain)
return 0;
}
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq)
int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq, uint32_t *lo_freq_out)
{
int rc = -1;
int rc;
uint32_t lo_freq = freq + priv->int_freq;
uint32_t margin = 1e6 + priv->bw/2;
uint8_t air_cable1_in;
int changed_pll_limits = 0;
r82xx_write_batch_init(priv);
rc = r82xx_set_mux(priv, lo_freq);
if (rc < 0)
goto err;
/* RF input settings */
rc = r82xx_set_pll(priv, lo_freq);
if (rc < 0)
goto err;
rc = r82xx_set_mux(priv, freq);
/* switch between 'Cable1' and 'Air-In' inputs on sticks with
* R828D tuner. We switch at 345 MHz, because that's where the
@ -1099,12 +1106,118 @@ int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq)
if ((priv->cfg->rafael_chip == CHIP_R828D) &&
(air_cable1_in != priv->input)) {
priv->input = air_cable1_in;
rc = r82xx_write_reg_mask(priv, 0x05, air_cable1_in, 0x60);
rc |= r82xx_write_reg_mask(priv, 0x05, air_cable1_in, 0x60);
}
if (priv->reg_batch) {
rc = r82xx_write_batch_sync(priv);
/* IF generation settings */
retune:
if (freq < 14.4e6 && freq < (priv->pll_low_limit - 14.4e6)) {
/* Previously "no-mod direct sampling" - confuse the VCO/PLL
* sufficiently that we get the HF signal leaking through
* the tuner, then sample that directly.
*
* Disable the VCO, as far as we can.
* This throws a big spike of noise into the signal,
* so only do it once when crossing the 14.4MHz boundary,
* not on every retune.
*/
if (!priv->pll_off) {
rc |= r82xx_set_pll(priv, 50e6, NULL); /* Might influence the noise floor? */
rc |= r82xx_write_reg_mask(priv, 0x10, 0xd0, 0xe0); /* impossible mix_div setting */
rc |= r82xx_write_reg_mask(priv, 0x12, 0xe0, 0xe0); /* VCO current = 0 */
priv->pll_off = 1;
}
/* We are effectively tuned to 0Hz - the downconverter must do all the heavy lifting now */
lo_freq = 0;
if (lo_freq_out) *lo_freq_out = 0;
} else {
/* Normal tuning case */
int pll_error = 0;
if (priv->pll_off) {
/* Crossed the 14.4MHz boundary, power the VCO back on */
rc |= r82xx_write_reg_mask(priv, 0x12, 0x80, 0xe0);
priv->pll_off = 0;
}
/*
* Keep PLL within empirically stable bounds; outside those bounds,
* we prefer to tune to the "wrong" frequency; the difference will be
* mopped up by the 2832 downconverter.
*
* Beware that outside the stable range, the PLL can claim to be locked
* while it is actually stuck at a different frequency (e.g. sometimes
* it can claim to get PLL lock when configured anywhere between 24 and
* 26MHz, but it actually always locks to 26.6-ish).
*
* Make sure to keep the LO away from tuned frequency as there seems
* to be a ~600kHz high-pass filter in the IF path, so you don't want
* any interesting frequencies to land near the IF.
*/
if (lo_freq < priv->pll_low_limit) {
if (freq > (priv->pll_low_limit-margin) && freq < (priv->pll_low_limit+margin)) {
lo_freq = freq + margin;
} else {
lo_freq = priv->pll_low_limit;
}
} else if (lo_freq > priv->pll_high_limit) {
if (freq > (priv->pll_high_limit-margin) && freq < (priv->pll_high_limit+margin)) {
lo_freq = freq - margin;
} else {
lo_freq = priv->pll_high_limit;
}
}
pll_error = r82xx_set_pll(priv, lo_freq, lo_freq_out);
if (pll_error == -42) {
/* Magic return value to say that the PLL didn't lock.
* If we are close to the edge of the PLL range, shift the range and try again.
*/
if (lo_freq < PLL_SAFE_LOW) {
priv->pll_low_limit = lo_freq + PLL_STEP_LOW;
if (priv->pll_low_limit > PLL_SAFE_LOW)
priv->pll_low_limit = PLL_SAFE_LOW;
changed_pll_limits = 1;
goto retune;
} else if (lo_freq > PLL_SAFE_HIGH) {
priv->pll_high_limit = lo_freq - PLL_STEP_HIGH;
if (priv->pll_high_limit < PLL_SAFE_HIGH)
priv->pll_high_limit = PLL_SAFE_HIGH;
changed_pll_limits = 1;
goto retune;
} else {
fprintf(stderr, "[r82xx] Failed to get PLL lock at %u Hz\n", lo_freq);
}
}
rc |= pll_error;
}
if (changed_pll_limits) {
fprintf(stderr, "[r82xx] Updated PLL limits to %u .. %u Hz\n", priv->pll_low_limit, priv->pll_high_limit);
}
/* IF filter / image rejection settings */
if (lo_freq > freq) {
/* high-side mixing, image negative */
rc |= r82xx_write_reg_mask(priv, 0x07, 0x00, 0x80);
priv->if_filter_freq = lo_freq - freq;
} else {
/* low-side mixing, image positive */
rc |= r82xx_write_reg_mask(priv, 0x07, 0x80, 0x80);
priv->if_filter_freq = freq - lo_freq;
}
update_if_filter(priv);
if (priv->reg_batch) {
rc |= r82xx_write_batch_sync(priv);
}
err:
if (rc < 0)
fprintf(stderr, "%s: failed=%d\n", __FUNCTION__, rc);
@ -1117,22 +1230,17 @@ int r82xx_set_nomod(struct r82xx_priv *priv)
fprintf(stderr, "Using R820T no-mod direct sampling mode\n");
/* should probably play a bit more with the mux settings
to see if something works even better than this */
/*rc = r82xx_set_bw(priv, 1000000);
if (rc < 0)
goto err;*/
/* experimentally determined magic numbers
* needs more experimenting with all the registers */
rc = r82xx_set_mux(priv, 300000000);
if (rc < 0) goto err;
if (rc < 0)
goto err;
/* the VCO frequency setting still seems to have some effect on the noise floor */
rc = r82xx_set_pll(priv, 50000000);
if (rc < 0) goto err;
/* the most important part: set a divider number that does not really work */
rc = r82xx_write_reg_mask(priv, 0x10, 0xd0, 0xe0);
if (rc < 0) goto err;
/* VCO power off */
rc = r82xx_write_reg_mask(priv, 0x12, 0xe0, 0xe0);
r82xx_set_pll(priv, 25000000, NULL);
err:
if (rc < 0)
@ -1282,6 +1390,9 @@ int r82xx_init(struct r82xx_priv *priv)
rc |= r82xx_sysfreq_sel(priv, 0, TUNER_DIGITAL_TV, SYS_DVBT);
priv->pll_low_limit = PLL_INITIAL_LOW;
priv->pll_high_limit = PLL_INITIAL_HIGH;
priv->init_done = 1;
priv->reg_cache = 1;