Browse Source

add support for R828D tuner

Signed-off-by: Steve Markgraf <steve@steve-m.de>
Steve Markgraf 11 years ago
parent
commit
e61731d230
4 changed files with 90 additions and 60 deletions
  1. 3 2
      include/rtl-sdr.h
  2. 6 3
      include/tuner_r82xx.h
  3. 54 27
      src/librtlsdr.c
  4. 27 28
      src/tuner_r82xx.c

+ 3 - 2
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 <steve@steve-m.de>
+ * Copyright (C) 2012-2013 by Steve Markgraf <steve@steve-m.de>
  * Copyright (C) 2012 by Dimitri Stolnikov <horiz0n@gmx.net>
  *
  * 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
 };
 
 /*!

+ 6 - 3
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;
 

+ 54 - 27
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);
 

+ 27 - 28
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)