kopia lustrzana https://github.com/keenerd/rtl-sdr
				
				
				
			add support for R828D tuner
Signed-off-by: Steve Markgraf <steve@steve-m.de>pull/5/head
							rodzic
							
								
									230930e975
								
							
						
					
					
						commit
						e61731d230
					
				|  | @ -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 | ||||
| }; | ||||
| 
 | ||||
| /*!
 | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
		Ładowanie…
	
		Reference in New Issue
	
	 Steve Markgraf
						Steve Markgraf