diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h index 75bfd3f..ca89b77 100644 --- a/include/rtl-sdr.h +++ b/include/rtl-sdr.h @@ -1,6 +1,6 @@ /* * rtl-sdr, turns your Realtek RTL2832 based DVB dongle into a SDR receiver - * Copyright (C) 2012 by Steve Markgraf + * Copyright (C) 2012-2013 by Steve Markgraf * Copyright (C) 2012 by Dimitri Stolnikov * * This program is free software: you can redistribute it and/or modify @@ -175,7 +175,8 @@ enum rtlsdr_tuner { RTLSDR_TUNER_FC0012, RTLSDR_TUNER_FC0013, RTLSDR_TUNER_FC2580, - RTLSDR_TUNER_R820T + RTLSDR_TUNER_R820T, + RTLSDR_TUNER_R828D }; /*! diff --git a/include/tuner_r82xx.h b/include/tuner_r82xx.h index 2295574..fd81e1d 100644 --- a/include/tuner_r82xx.h +++ b/include/tuner_r82xx.h @@ -26,8 +26,11 @@ #define R82XX_H #define R820T_I2C_ADDR 0x34 -#define R820T_CHECK_ADDR 0x00 -#define R820T_CHECK_VAL 0x69 +#define R828D_I2C_ADDR 0x74 +#define R828D_XTAL_FREQ 16000000 + +#define R82XX_CHECK_ADDR 0x00 +#define R82XX_CHECK_VAL 0x69 #define R82XX_IF_FREQ 3570000 @@ -66,7 +69,6 @@ struct r82xx_config { uint32_t xtal; enum r82xx_chip rafael_chip; unsigned int max_i2c_msg_len; - int use_diplexer; int use_predetect; }; @@ -79,6 +81,7 @@ struct r82xx_priv { uint16_t pll; /* kHz */ uint32_t int_freq; uint8_t fil_cal_code; + uint8_t input; int has_lock; int init_done; diff --git a/src/librtlsdr.c b/src/librtlsdr.c index a0026fd..d66caad 100644 --- a/src/librtlsdr.c +++ b/src/librtlsdr.c @@ -184,13 +184,18 @@ int fc2580_set_gain_mode(void *dev, int manual) { return 0; } int r820t_init(void *dev) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; devt->r82xx_p.rtl_dev = dev; - devt->r82xx_c.i2c_addr = R820T_I2C_ADDR; + + if (devt->tuner_type == RTLSDR_TUNER_R828D) { + devt->r82xx_c.i2c_addr = R828D_I2C_ADDR; + devt->r82xx_c.rafael_chip = CHIP_R828D; + } else { + devt->r82xx_c.i2c_addr = R820T_I2C_ADDR; + devt->r82xx_c.rafael_chip = CHIP_R820T; + } rtlsdr_get_xtal_freq(devt, NULL, &devt->r82xx_c.xtal); - devt->r82xx_c.rafael_chip = CHIP_R820T; devt->r82xx_c.max_i2c_msg_len = 2; - devt->r82xx_c.use_diplexer = 0; devt->r82xx_c.use_predetect = 0; devt->r82xx_p.cfg = &devt->r82xx_c; @@ -214,6 +219,7 @@ int r820t_set_gain_mode(void *dev, int manual) { rtlsdr_dev_t* devt = (rtlsdr_dev_t*)dev; return r82xx_set_gain(&devt->r82xx_p, manual, 0); } + /* definition order must match enum rtlsdr_tuner */ static rtlsdr_tuner_iface_t tuners[] = { { @@ -244,6 +250,11 @@ static rtlsdr_tuner_iface_t tuners[] = { r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, r820t_set_gain_mode }, + { + r820t_init, r820t_exit, + r820t_set_freq, r820t_set_bw, r820t_set_gain, NULL, + r820t_set_gain_mode + }, }; typedef struct rtlsdr_dongle { @@ -892,7 +903,7 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) 63, 65, 67, 68, 70, 71, 179, 181, 182, 184, 186, 188, 191, 197 }; const int fc2580_gains[] = { 0 /* no gain values */ }; - const int r820t_gains[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, + const int r82xx_gains[] = { 0, 9, 14, 27, 37, 77, 87, 125, 144, 157, 166, 197, 207, 229, 254, 280, 297, 328, 338, 364, 372, 386, 402, 421, 434, 439, 445, 480, 496 }; @@ -918,7 +929,8 @@ int rtlsdr_get_tuner_gains(rtlsdr_dev_t *dev, int *gains) ptr = fc2580_gains; len = sizeof(fc2580_gains); break; case RTLSDR_TUNER_R820T: - ptr = r820t_gains; len = sizeof(r820t_gains); + case RTLSDR_TUNER_R828D: + ptr = r82xx_gains; len = sizeof(r82xx_gains); break; default: ptr = unknown_gains; len = sizeof(unknown_gains); @@ -1103,7 +1115,8 @@ int rtlsdr_set_direct_sampling(rtlsdr_dev_t *dev, int on) rtlsdr_set_i2c_repeater(dev, 0); } - if (dev->tuner_type == RTLSDR_TUNER_R820T) { + if ((dev->tuner_type == RTLSDR_TUNER_R820T) || + (dev->tuner_type == RTLSDR_TUNER_R828D)) { r |= rtlsdr_set_if_freq(dev, R82XX_IF_FREQ); /* enable spectrum inversion */ @@ -1145,7 +1158,8 @@ int rtlsdr_set_offset_tuning(rtlsdr_dev_t *dev, int on) if (!dev) return -1; - if (dev->tuner_type == RTLSDR_TUNER_R820T) + if ((dev->tuner_type == RTLSDR_TUNER_R820T) || + (dev->tuner_type == RTLSDR_TUNER_R828D)) return -2; if (dev->direct_sampling) @@ -1432,27 +1446,19 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) goto found; } - reg = rtlsdr_i2c_read_reg(dev, R820T_I2C_ADDR, R820T_CHECK_ADDR); - if (reg == R820T_CHECK_VAL) { + reg = rtlsdr_i2c_read_reg(dev, R820T_I2C_ADDR, R82XX_CHECK_ADDR); + if (reg == R82XX_CHECK_VAL) { fprintf(stderr, "Found Rafael Micro R820T tuner\n"); dev->tuner_type = RTLSDR_TUNER_R820T; - - /* disable Zero-IF mode */ - rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1); - - /* only enable In-phase ADC input */ - rtlsdr_demod_write_reg(dev, 0, 0x08, 0x4d, 1); - - /* the R820T uses 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_IF_FREQ); - - /* enable spectrum inversion */ - rtlsdr_demod_write_reg(dev, 1, 0x15, 0x01, 1); - goto found; } + reg = rtlsdr_i2c_read_reg(dev, R828D_I2C_ADDR, R82XX_CHECK_ADDR); + if (reg == R82XX_CHECK_VAL) { + fprintf(stderr, "Found Rafael Micro R828D tuner\n"); + dev->tuner_type = RTLSDR_TUNER_R828D; + } + /* initialise GPIOs */ rtlsdr_set_gpio_output(dev, 5); @@ -1476,14 +1482,35 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index) } found: - if (dev->tuner_type == RTLSDR_TUNER_UNKNOWN) { + /* use the rtl clock value by default */ + dev->tun_xtal = dev->rtl_xtal; + dev->tuner = &tuners[dev->tuner_type]; + + switch (dev->tuner_type) { + case RTLSDR_TUNER_R828D: + dev->tun_xtal = R828D_XTAL_FREQ; + case RTLSDR_TUNER_R820T: + /* disable Zero-IF mode */ + rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1); + + /* 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_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"); rtlsdr_set_direct_sampling(dev, 1); + break; + default: + break; } - dev->tuner = &tuners[dev->tuner_type]; - dev->tun_xtal = dev->rtl_xtal; /* use the rtl clock value by default */ - if (dev->tuner->init) r = dev->tuner->init(dev); diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c index 540899d..e8859a4 100644 --- a/src/tuner_r82xx.c +++ b/src/tuner_r82xx.c @@ -31,9 +31,8 @@ #include "tuner_r82xx.h" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -#define VCO_POWER_REF 0x02 -#define DIP_FREQ 32000000 +#define MHZ(x) ((x)*1000*1000) +#define KHZ(x) ((x)*1000) /* * Static constants @@ -430,13 +429,14 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq) uint8_t mix_div = 2; uint8_t div_buf = 0; uint8_t div_num = 0; + uint8_t vco_power_ref = 2; uint8_t refdiv2 = 0; uint8_t ni, si, nint, vco_fine_tune, val; uint8_t data[5]; /* Frequency in kHz */ freq_khz = (freq + 500) / 1000; - pll_ref = priv->cfg->xtal; // / 1000; + pll_ref = priv->cfg->xtal; pll_ref_khz = (priv->cfg->xtal + 500) / 1000; rc = r82xx_write_reg_mask(priv, 0x10, refdiv2, 0x10); @@ -471,11 +471,14 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq) if (rc < 0) return rc; + if (priv->cfg->rafael_chip == CHIP_R828D) + vco_power_ref = 1; + vco_fine_tune = (data[4] & 0x30) >> 4; - if (vco_fine_tune > VCO_POWER_REF) + if (vco_fine_tune > vco_power_ref) div_num = div_num - 1; - else if (vco_fine_tune < VCO_POWER_REF) + else if (vco_fine_tune < vco_power_ref) div_num = div_num + 1; rc = r82xx_write_reg_mask(priv, 0x10, div_num << 5, 0xe0); @@ -486,8 +489,8 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq) nint = vco_freq / (2 * pll_ref); vco_fra = (vco_freq - 2 * pll_ref * nint) / 1000; - if (nint > 63) { - fprintf(stderr, "No valid PLL values for %u kHz!\n", freq); + if (nint > ((128 / vco_power_ref) - 1)) { + fprintf(stderr, "[R82XX] No valid PLL values for %u Hz!\n", freq); return -EINVAL; } @@ -545,6 +548,7 @@ static int r82xx_set_pll(struct r82xx_priv *priv, uint32_t freq) } if (!(data[2] & 0x40)) { + printf("[R82XX] PLL not locked!\n"); priv->has_lock = 0; return 0; } @@ -628,17 +632,6 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq, break; } - if (priv->cfg->use_diplexer && - ((priv->cfg->rafael_chip == CHIP_R820T) || - (priv->cfg->rafael_chip == CHIP_R828S) || - (priv->cfg->rafael_chip == CHIP_R820C))) { - if (freq > DIP_FREQ) - air_cable1_in = 0x00; - else - air_cable1_in = 0x60; - cable2_in = 0x00; - } - if (priv->cfg->use_predetect) { rc = r82xx_write_reg_mask(priv, 0x06, pre_dect, 0x40); if (rc < 0) @@ -658,6 +651,8 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq, if (rc < 0) return rc; + priv->input = air_cable1_in; + /* Air-IN only for Astrometa */ rc = r82xx_write_reg_mask(priv, 0x05, air_cable1_in, 0x60); if (rc < 0) @@ -675,11 +670,6 @@ static int r82xx_sysfreq_sel(struct r82xx_priv *priv, uint32_t freq, rc = r82xx_write_reg_mask(priv, 0x0a, filter_cur, 0x60); if (rc < 0) return rc; - /* - * Original driver initializes regs 0x05 and 0x06 with the - * same value again on this point. Probably, it is just an - * error there - */ /* * Set LNA @@ -1088,8 +1078,7 @@ int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq) { int rc = -EINVAL; uint32_t lo_freq = freq + priv->int_freq; - - lo_freq = freq + priv->int_freq; + uint8_t air_cable1_in; rc = r82xx_set_mux(priv, lo_freq); if (rc < 0) @@ -1099,6 +1088,18 @@ int r82xx_set_freq(struct r82xx_priv *priv, uint32_t freq) if (rc < 0 || !priv->has_lock) goto err; + /* switch between 'Cable1' and 'Air-In' inputs on sticks with + * R828D tuner. We switch at 345 MHz, because that's where the + * noise-floor has about the same level with identical LNA + * settings. The original driver used 320 MHz. */ + air_cable1_in = (freq > MHZ(345)) ? 0x00 : 0x60; + + 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); + } + err: if (rc < 0) fprintf(stderr, "%s: failed=%d\n", __func__, rc); @@ -1234,8 +1235,6 @@ int r82xx_init(struct r82xx_priv *priv) goto err; rc = r82xx_sysfreq_sel(priv, 0, TUNER_DIGITAL_TV, SYS_DVBT); - if (rc < 0) - goto err; err: if (rc < 0)