You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							6528 lines
						
					
					
						
							180 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							6528 lines
						
					
					
						
							180 KiB
						
					
					
				| diff -urN a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig | |
| --- a/drivers/media/dvb-frontends/Kconfig	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/dvb-frontends/Kconfig	2013-05-03 17:03:57.000000000 +0800 | |
| @@ -200,6 +200,20 @@ | |
|  	help | |
|  	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend. | |
|   | |
| +config DVB_M88DS3103 | |
| +	tristate "Montage M88DS3103 based" | |
| +	depends on DVB_CORE && I2C | |
| +	default m if !MEDIA_SUBDRV_AUTOSELECT | |
| +	help | |
| +	  A DVB-S/S2 tuner module. Say Y when you want to support this frontend. | |
| + | |
| +config DVB_M88DC2800 | |
| +	tristate "Montage M88DC2800 based" | |
| +	depends on DVB_CORE && I2C | |
| +	default m if !MEDIA_SUBDRV_AUTOSELECT | |
| +	help | |
| +	  A DVB-C tuner module. Say Y when you want to support this frontend. | |
| +	  	   | |
|  config DVB_SI21XX | |
|  	tristate "Silicon Labs SI21XX based" | |
|  	depends on DVB_CORE && I2C | |
| diff -urN a/drivers/media/dvb-frontends/m88dc2800.c b/drivers/media/dvb-frontends/m88dc2800.c | |
| --- a/drivers/media/dvb-frontends/m88dc2800.c	1970-01-01 08:00:00.000000000 +0800 | |
| +++ b/drivers/media/dvb-frontends/m88dc2800.c	2013-01-26 16:03:21.000000000 +0800 | |
| @@ -0,0 +1,2124 @@ | |
| +/* | |
| +    M88DC2800/M88TC2800  - DVB-C demodulator and tuner from Montage | |
| + | |
| +    Copyright (C) 2012 Max nibble<nibble.max@gmail.com> | |
| +    Copyright (C) 2011 Montage Technology / www.montage-tech.com | |
| + | |
| +    This program is free software; you can redistribute it and/or modify | |
| +    it under the terms of the GNU General Public License as published by | |
| +    the Free Software Foundation; either version 2 of the License, or | |
| +    (at your option) any later version. | |
| + | |
| +    This program is distributed in the hope that it will be useful, | |
| +    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| +    GNU General Public License for more details. | |
| + | |
| +    You should have received a copy of the GNU General Public License | |
| +    along with this program; if not, write to the Free Software | |
| +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| +*/ | |
| + | |
| +#include <linux/delay.h> | |
| +#include <linux/errno.h> | |
| +#include <linux/init.h> | |
| +#include <linux/kernel.h> | |
| +#include <linux/module.h> | |
| +#include <linux/string.h> | |
| +#include <linux/slab.h> | |
| +#include <asm/div64.h> | |
| +#include "dvb_frontend.h" | |
| +#include "m88dc2800.h" | |
| + | |
| +struct m88dc2800_state { | |
| +	struct i2c_adapter *i2c; | |
| +	const struct m88dc2800_config *config; | |
| +	struct dvb_frontend frontend; | |
| +	u32 freq; | |
| +	u32 ber; | |
| +	u32 sym; | |
| +	u16 qam; | |
| +	u8 inverted; | |
| +	u32 xtal; | |
| +	/* tuner state */ | |
| +	u8 tuner_init_OK;	/* Tuner initialize status */ | |
| +	u8 tuner_dev_addr;	/* Tuner device address */ | |
| +	u32 tuner_freq;		/* RF frequency to be set, unit: KHz */ | |
| +	u16 tuner_qam;		/* Reserved */ | |
| +	u16 tuner_mode; | |
| +	u8 tuner_bandwidth;	/* Bandwidth of the channel, unit: MHz, 6/7/8 */ | |
| +	u8 tuner_loopthrough;	/* Tuner loop through switch, 0/1 */ | |
| +	u32 tuner_crystal;	/* Tuner crystal frequency, unit: KHz */ | |
| +	u32 tuner_dac;		/* Tuner DAC frequency, unit: KHz */ | |
| +	u16 tuner_mtt;		/* Tuner chip version, D1: 0x0d, E0: 0x0e, E1: 0x8e */ | |
| +	u16 tuner_custom_cfg; | |
| +	u32 tuner_version;	/* Tuner driver version number */ | |
| +	u32 tuner_time; | |
| +}; | |
| + | |
| +static int debug; | |
| +module_param(debug, int, 0644); | |
| +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); | |
| + | |
| +#define dprintk(args...) \ | |
| +	do { \ | |
| +		if (debug) \ | |
| +			printk(KERN_INFO "m88dc2800: " args); \ | |
| +	} while (0) | |
| + | |
| + | |
| +static int m88dc2800_i2c_write(struct m88dc2800_state *state, u8 addr, | |
| +			       u8 * p_data, u8 len) | |
| +{ | |
| +	struct i2c_msg msg = { .flags = 0 }; | |
| + | |
| +	msg.addr = addr; | |
| +	msg.buf = p_data; | |
| +	msg.len = len; | |
| + | |
| +	return i2c_transfer(state->i2c, &msg, 1); | |
| +} | |
| + | |
| +static int m88dc2800_i2c_read(struct m88dc2800_state *state, u8 addr, | |
| +			      u8 * p_data, u8 len) | |
| +{ | |
| +	struct i2c_msg msg = { .flags = I2C_M_RD }; | |
| + | |
| +	msg.addr = addr; | |
| +	msg.buf = p_data; | |
| +	msg.len = len; | |
| + | |
| +	return i2c_transfer(state->i2c, &msg, 1); | |
| +} | |
| + | |
| +/*demod register operations.*/ | |
| +static int WriteReg(struct m88dc2800_state *state, u8 reg, u8 data) | |
| +{ | |
| +	u8 buf[] = { reg, data }; | |
| +	u8 addr = state->config->demod_address; | |
| +	int err; | |
| + | |
| +	dprintk("%s: write reg 0x%02x, value 0x%02x\n", __func__, reg, data); | |
| + | |
| +	err = m88dc2800_i2c_write(state, addr, buf, 2); | |
| + | |
| +	if (err != 1) { | |
| +		printk(KERN_ERR | |
| +		       "%s: writereg error(err == %i, reg == 0x%02x," | |
| +		       " value == 0x%02x)\n", __func__, err, reg, data); | |
| +		return -EIO; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int ReadReg(struct m88dc2800_state *state, u8 reg) | |
| +{ | |
| +	int ret; | |
| +	u8 b0[] = { reg }; | |
| +	u8 b1[] = { 0 }; | |
| +	u8 addr = state->config->demod_address; | |
| + | |
| +	ret = m88dc2800_i2c_write(state, addr, b0, 1); | |
| + | |
| +	if (ret != 1) { | |
| +		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", | |
| +		       __func__, reg, ret); | |
| +		return -EIO; | |
| +	} | |
| + | |
| +	ret = m88dc2800_i2c_read(state, addr, b1, 1); | |
| + | |
| +	dprintk("%s: read reg 0x%02x, value 0x%02x\n", __func__, reg, b1[0]); | |
| +	return b1[0]; | |
| +} | |
| + | |
| +static int _mt_fe_tn_set_reg(struct m88dc2800_state *state, u8 reg, | |
| +			     u8 data) | |
| +{ | |
| +	int ret; | |
| +	u8 buf[2]; | |
| +	u8 addr = state->tuner_dev_addr; | |
| + | |
| +	buf[1] = ReadReg(state, 0x86); | |
| +	buf[1] |= 0x80; | |
| +	ret = WriteReg(state, 0x86, buf[1]); | |
| + | |
| +	buf[0] = reg; | |
| +	buf[1] = data; | |
| + | |
| +	ret = m88dc2800_i2c_write(state, addr, buf, 2); | |
| +	if (ret != 1) | |
| +		return -EIO; | |
| +	return 0; | |
| +} | |
| + | |
| +static int _mt_fe_tn_get_reg(struct m88dc2800_state *state, u8 reg, | |
| +			     u8 * p_data) | |
| +{ | |
| +	int ret; | |
| +	u8 buf[2]; | |
| +	u8 addr = state->tuner_dev_addr; | |
| + | |
| +	buf[1] = ReadReg(state, 0x86); | |
| +	buf[1] |= 0x80; | |
| +	ret = WriteReg(state, 0x86, buf[1]); | |
| + | |
| +	buf[0] = reg; | |
| +	ret = m88dc2800_i2c_write(state, addr, buf, 1); | |
| + | |
| +	msleep(1); | |
| + | |
| +	buf[1] = ReadReg(state, 0x86); | |
| +	buf[1] |= 0x80; | |
| +	ret = WriteReg(state, 0x86, buf[1]); | |
| + | |
| +	return m88dc2800_i2c_read(state, addr, p_data, 1); | |
| +} | |
| + | |
| +/* Tuner operation functions.*/ | |
| +static int _mt_fe_tn_set_RF_front_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	u32 freq_KHz = state->tuner_freq; | |
| +	u8 a, b, c; | |
| +	if (state->tuner_mtt == 0xD1) {	/* D1 */ | |
| +		if (freq_KHz <= 123000) { | |
| +			if (freq_KHz <= 56000) { | |
| +				a = 0x00; b = 0x00; c = 0x00; | |
| +			} else if (freq_KHz <= 64000) { | |
| +				a = 0x10; b = 0x01; c = 0x08; | |
| +			} else if (freq_KHz <= 72000) { | |
| +				a = 0x20; b = 0x02; c = 0x10; | |
| +			} else if (freq_KHz <= 80000) { | |
| +				a = 0x30; b = 0x03; c = 0x18; | |
| +			} else if (freq_KHz <= 88000) { | |
| +				a = 0x40; b = 0x04; c = 0x20; | |
| +			} else if (freq_KHz <= 96000) { | |
| +				a = 0x50; b = 0x05; c = 0x28; | |
| +			} else if (freq_KHz <= 104000) { | |
| +				a = 0x60; b = 0x06; c = 0x30; | |
| +			} else { | |
| +				a = 0x70; b = 0x07; c = 0x38; | |
| +			} | |
| +			_mt_fe_tn_set_reg(state, 0x58, 0x9b); | |
| +			_mt_fe_tn_set_reg(state, 0x59, a); | |
| +			_mt_fe_tn_set_reg(state, 0x5d, b); | |
| +			_mt_fe_tn_set_reg(state, 0x5e, c); | |
| +			_mt_fe_tn_set_reg(state, 0x5a, 0x75); | |
| +			_mt_fe_tn_set_reg(state, 0x73, 0x0c); | |
| +		} else {	/* if (freq_KHz > 112000) */ | |
| +			_mt_fe_tn_set_reg(state, 0x58, 0x7b); | |
| +			if (freq_KHz <= 304000) { | |
| +				if (freq_KHz <= 136000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x40); | |
| +				} else if (freq_KHz <= 160000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x48); | |
| +				} else if (freq_KHz <= 184000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x50); | |
| +				} else if (freq_KHz <= 208000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x58); | |
| +				} else if (freq_KHz <= 232000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x60); | |
| +				} else if (freq_KHz <= 256000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x68); | |
| +				} else if (freq_KHz <= 280000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x70); | |
| +				} else {	/* if (freq_KHz <= 304000) */ | |
| +					_mt_fe_tn_set_reg(state, 0x5e, 0x78); | |
| +				} | |
| +				if (freq_KHz <= 171000) { | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x08); | |
| +				} else if (freq_KHz <= 211000) { | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x0a); | |
| +				} else { | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x0e); | |
| +				} | |
| +			} else {	/* if (freq_KHz > 304000) */ | |
| +				_mt_fe_tn_set_reg(state, 0x5e, 0x88); | |
| +				if (freq_KHz <= 400000) { | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x0c); | |
| +				} else if (freq_KHz <= 450000) { | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x09); | |
| +				} else if (freq_KHz <= 550000) { | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x0e); | |
| +				} else if (freq_KHz <= 650000) { | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x0d); | |
| +				} else {	/*if (freq_KHz > 650000) */ | |
| +					_mt_fe_tn_set_reg(state, 0x73, 0x0e); | |
| +				} | |
| +			} | |
| +		} | |
| +		if (freq_KHz > 800000) | |
| +			_mt_fe_tn_set_reg(state, 0x87, 0x24); | |
| +		else if (freq_KHz > 700000) | |
| +			_mt_fe_tn_set_reg(state, 0x87, 0x34); | |
| +		else if (freq_KHz > 500000) | |
| +			_mt_fe_tn_set_reg(state, 0x87, 0x44); | |
| +		else if (freq_KHz > 300000) | |
| +			_mt_fe_tn_set_reg(state, 0x87, 0x43); | |
| +		else if (freq_KHz > 220000) | |
| +			_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +		else if (freq_KHz > 110000) | |
| +			_mt_fe_tn_set_reg(state, 0x87, 0x14); | |
| +		else | |
| +			_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +		if (freq_KHz > 600000) | |
| +			_mt_fe_tn_set_reg(state, 0x6a, 0x53); | |
| +		else if (freq_KHz > 500000) | |
| +			_mt_fe_tn_set_reg(state, 0x6a, 0x57); | |
| +		else | |
| +			_mt_fe_tn_set_reg(state, 0x6a, 0x59); | |
| +		if (freq_KHz < 200000) { | |
| +			_mt_fe_tn_set_reg(state, 0x20, 0x5d); | |
| +		} else if (freq_KHz < 500000) { | |
| +			_mt_fe_tn_set_reg(state, 0x20, 0x7d); | |
| +		} else { | |
| +			_mt_fe_tn_set_reg(state, 0x20, 0xfd); | |
| +		}		/* end of 0xD1 */ | |
| +	} else if (state->tuner_mtt == 0xE1) {	/* E1 */ | |
| +		if (freq_KHz <= 112000) {	/* 123MHz */ | |
| +			if (freq_KHz <= 56000) { | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x01); | |
| +			} else if (freq_KHz <= 64000) { | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x09); | |
| +			} else if (freq_KHz <= 72000) { | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x11); | |
| +			} else if (freq_KHz <= 80000) { | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x19); | |
| +			} else if (freq_KHz <= 88000) { | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x21); | |
| +			} else if (freq_KHz <= 96000) { | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x29); | |
| +			} else if (freq_KHz <= 104000) { | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x31); | |
| +			} else {	/* if (freq_KHz <= 112000) */ | |
| +				_mt_fe_tn_set_reg(state, 0x5c, 0x39); | |
| +			} | |
| +			_mt_fe_tn_set_reg(state, 0x5b, 0x30); | |
| +		} else {	/* if (freq_KHz > 112000) */ | |
| +			if (freq_KHz <= 304000) { | |
| +				if (freq_KHz <= 136000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x41); | |
| +				} else if (freq_KHz <= 160000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x49); | |
| +				} else if (freq_KHz <= 184000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x51); | |
| +				} else if (freq_KHz <= 208000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x59); | |
| +				} else if (freq_KHz <= 232000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x61); | |
| +				} else if (freq_KHz <= 256000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x69); | |
| +				} else if (freq_KHz <= 280000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x71); | |
| +				} else {	/* if (freq_KHz <= 304000) */ | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x79); | |
| +				} | |
| +				if (freq_KHz <= 150000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5b, 0x28); | |
| +				} else if (freq_KHz <= 256000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5b, 0x29); | |
| +				} else { | |
| +					_mt_fe_tn_set_reg(state, 0x5b, 0x2a); | |
| +				} | |
| +			} else {	/* if (freq_KHz > 304000) */ | |
| +				if (freq_KHz <= 400000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x89); | |
| +				} else if (freq_KHz <= 450000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x91); | |
| +				} else if (freq_KHz <= 650000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0x98); | |
| +				} else if (freq_KHz <= 850000) { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0xa0); | |
| +				} else { | |
| +					_mt_fe_tn_set_reg(state, 0x5c, 0xa8); | |
| +				} | |
| +				_mt_fe_tn_set_reg(state, 0x5b, 0x08); | |
| +			} | |
| +		} | |
| +	}			/* end of 0xE1 */ | |
| +	return 0; | |
| +} | |
| + | |
| +static int _mt_fe_tn_cali_PLL_tc2800(struct m88dc2800_state *state, | |
| +				     u32 freq_KHz, | |
| +				     u32 cali_freq_thres_div2, | |
| +				     u32 cali_freq_thres_div3r, | |
| +				     u32 cali_freq_thres_div3) | |
| +{ | |
| +	s32 N, F, MUL; | |
| +	u8 buf, tmp, tmp2; | |
| +	s32 M; | |
| +	const s32 crystal_KHz = state->tuner_crystal; | |
| +	 if (state->tuner_mtt == 0xD1) { | |
| +		M = state->tuner_crystal / 4000; | |
| +		if (freq_KHz > cali_freq_thres_div2) { | |
| +			MUL = 4; | |
| +			tmp = 2; | |
| +		} else if (freq_KHz > 300000) { | |
| +			MUL = 8; | |
| +			tmp = 3; | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 2)) { | |
| +			MUL = 8; | |
| +			tmp = 4; | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 4)) { | |
| +			MUL = 16; | |
| +			tmp = 5; | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 8)) { | |
| +			MUL = 32; | |
| +			tmp = 6; | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 16)) { | |
| +			MUL = 64; | |
| +			tmp = 7; | |
| +		} else {	/* invalid */ | |
| +			MUL = 0; | |
| +			tmp = 0; | |
| +			return 1; | |
| +		} | |
| +	} else if (state->tuner_mtt == 0xE1) { | |
| +		M = state->tuner_crystal / 1000; | |
| +		_mt_fe_tn_set_reg(state, 0x30, 0xff); | |
| +		_mt_fe_tn_set_reg(state, 0x32, 0xe0); | |
| +		_mt_fe_tn_set_reg(state, 0x33, 0x86); | |
| +		_mt_fe_tn_set_reg(state, 0x37, 0x70); | |
| +		_mt_fe_tn_set_reg(state, 0x38, 0x20); | |
| +		_mt_fe_tn_set_reg(state, 0x39, 0x18); | |
| +		_mt_fe_tn_set_reg(state, 0x89, 0x83); | |
| +		if (freq_KHz > cali_freq_thres_div2) { | |
| +			M = M / 4; | |
| +			MUL = 4; | |
| +			tmp = 2; | |
| +			tmp2 = M + 16;	/* 48 */ | |
| +		} else if (freq_KHz > cali_freq_thres_div3r) { | |
| +			M = M / 3; | |
| +			MUL = 6; | |
| +			tmp = 2; | |
| +			tmp2 = M + 32;	/* 32 */ | |
| +		} else if (freq_KHz > cali_freq_thres_div3) { | |
| +			M = M / 3; | |
| +			MUL = 6; | |
| +			tmp = 2; | |
| +			tmp2 = M;	/* 16 */ | |
| +		} else if (freq_KHz > 304000) { | |
| +			M = M / 4; | |
| +			MUL = 8; | |
| +			tmp = 3; | |
| +			tmp2 = M + 16;	/* 48 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 2)) { | |
| +			M = M / 4; | |
| +			MUL = 8; | |
| +			tmp = 4; | |
| +			tmp2 = M + 16;	/* 48 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3r / 2)) { | |
| +			M = M / 3; | |
| +			MUL = 12; | |
| +			tmp = 4; | |
| +			tmp2 = M + 32;	/* 32 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3 / 2)) { | |
| +			M = M / 3; | |
| +			MUL = 12; | |
| +			tmp = 4; | |
| +			tmp2 = M;	/* 16 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 4)) { | |
| +			M = M / 4; | |
| +			MUL = 16; | |
| +			tmp = 5; | |
| +			tmp2 = M + 16;	/* 48 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3r / 4)) { | |
| +			M = M / 3; | |
| +			MUL = 24; | |
| +			tmp = 5; | |
| +			tmp2 = M + 32;	/* 32 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3 / 4)) { | |
| +			M = M / 3; | |
| +			MUL = 24; | |
| +			tmp = 5; | |
| +			tmp2 = M;	/* 16 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 8)) { | |
| +			M = M / 4; | |
| +			MUL = 32; | |
| +			tmp = 6; | |
| +			tmp2 = M + 16;	/* 48 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3r / 8)) { | |
| +			M = M / 3; | |
| +			MUL = 48; | |
| +			tmp = 6; | |
| +			tmp2 = M + 32;	/* 32 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3 / 8)) { | |
| +			M = M / 3; | |
| +			MUL = 48; | |
| +			tmp = 6; | |
| +			tmp2 = M;	/* 16 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div2 / 16)) { | |
| +			M = M / 4; | |
| +			MUL = 64; | |
| +			tmp = 7; | |
| +			tmp2 = M + 16;	/* 48 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3r / 16)) { | |
| +			M = M / 3; | |
| +			MUL = 96; | |
| +			tmp = 7; | |
| +			tmp2 = M + 32;	/* 32 */ | |
| +		} else if (freq_KHz > (cali_freq_thres_div3 / 16)) { | |
| +			M = M / 3; | |
| +			MUL = 96; | |
| +			tmp = 7; | |
| +			tmp2 = M;	/* 16 */ | |
| +		} else {	/* invalid */ | |
| +			M = M / 4; | |
| +			MUL = 0; | |
| +			tmp = 0; | |
| +			tmp2 = 48; | |
| +			return 1; | |
| +		} | |
| +		if (freq_KHz == 291000) { | |
| +			M = state->tuner_crystal / 1000 / 3; | |
| +			MUL = 12; | |
| +			tmp = 4; | |
| +			tmp2 = M + 32;	/* 32 */ | |
| +		} | |
| +		/* | |
| +		   if (freq_KHz == 578000) { | |
| +		   M = state->tuner_crystal / 1000 / 4; | |
| +		   MUL = 4; | |
| +		   tmp = 2; | |
| +		   tmp2 = M + 16;	// 48 | |
| +		   } | |
| +		 */ | |
| +		if (freq_KHz == 690000) { | |
| +			M = state->tuner_crystal / 1000 / 3; | |
| +			MUL = 4; | |
| +			tmp = 2; | |
| +			tmp2 = M + 16;	/* 48 */ | |
| +		} | |
| +		_mt_fe_tn_get_reg(state, 0x33, &buf); | |
| +		buf &= 0xc0; | |
| +		buf += tmp2; | |
| +		_mt_fe_tn_set_reg(state, 0x33, buf); | |
| +	} else { | |
| +		return 1; | |
| +	} | |
| +	_mt_fe_tn_get_reg(state, 0x39, &buf); | |
| +	buf &= 0xf8; | |
| +	buf += tmp; | |
| +	_mt_fe_tn_set_reg(state, 0x39, buf); | |
| +	N = (freq_KHz * MUL * M / crystal_KHz) / 2 * 2 - 256; | |
| +	buf = (N >> 8) & 0xcf; | |
| +	if (state->tuner_mtt == 0xE1) { | |
| +		buf |= 0x30; | |
| +	} | |
| +	_mt_fe_tn_set_reg(state, 0x34, buf); | |
| +	buf = N & 0xff; | |
| +	_mt_fe_tn_set_reg(state, 0x35, buf); | |
| +	F = ((freq_KHz * MUL * M / (crystal_KHz / 1000) / 2) - | |
| +	     (freq_KHz * MUL * M / crystal_KHz / 2 * 1000)) * 64 / 1000; | |
| +	buf = F & 0xff; | |
| +	_mt_fe_tn_set_reg(state, 0x36, buf); | |
| +	if (F == 0) { | |
| +		if (state->tuner_mtt == 0xD1) { | |
| +			_mt_fe_tn_set_reg(state, 0x3d, 0xca); | |
| +		} else if (state->tuner_mtt == 0xE1) { | |
| +			_mt_fe_tn_set_reg(state, 0x3d, 0xfe); | |
| +		} else { | |
| +			return 1; | |
| +		} | |
| +		_mt_fe_tn_set_reg(state, 0x3e, 0x9c); | |
| +		_mt_fe_tn_set_reg(state, 0x3f, 0x34); | |
| +	} | |
| +	if (F > 0) { | |
| +		if (state->tuner_mtt == 0xD1) { | |
| +			if ((F == 32) || (F == 16) || (F == 48)) { | |
| +				_mt_fe_tn_set_reg(state, 0x3e, 0xa4); | |
| +				_mt_fe_tn_set_reg(state, 0x3d, 0x4a); | |
| +				_mt_fe_tn_set_reg(state, 0x3f, 0x36); | |
| +			} else { | |
| +				_mt_fe_tn_set_reg(state, 0x3e, 0xa4); | |
| +				_mt_fe_tn_set_reg(state, 0x3d, 0x4a); | |
| +				_mt_fe_tn_set_reg(state, 0x3f, 0x36); | |
| +			} | |
| +		} else if (state->tuner_mtt == 0xE1) { | |
| +			_mt_fe_tn_set_reg(state, 0x3e, 0xa4); | |
| +			_mt_fe_tn_set_reg(state, 0x3d, 0x7e); | |
| +			_mt_fe_tn_set_reg(state, 0x3f, 0x36); | |
| +			_mt_fe_tn_set_reg(state, 0x89, 0x84); | |
| +			_mt_fe_tn_get_reg(state, 0x39, &buf); | |
| +			buf = buf & 0x1f; | |
| +			_mt_fe_tn_set_reg(state, 0x39, buf); | |
| +			_mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +			buf = buf | 0x02; | |
| +			_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		} else { | |
| +			return 1; | |
| +		} | |
| +	} | |
| +	_mt_fe_tn_set_reg(state, 0x41, 0x00); | |
| +	if (state->tuner_mtt == 0xD1) { | |
| +		msleep(5); | |
| +	} else if (state->tuner_mtt == 0xE1) { | |
| +		msleep(2); | |
| +	} else { | |
| +		return 1; | |
| +	} | |
| +	_mt_fe_tn_set_reg(state, 0x41, 0x02); | |
| +	_mt_fe_tn_set_reg(state, 0x30, 0x7f); | |
| +	_mt_fe_tn_set_reg(state, 0x30, 0xff); | |
| +	_mt_fe_tn_set_reg(state, 0x31, 0x80); | |
| +	_mt_fe_tn_set_reg(state, 0x31, 0x00); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int _mt_fe_tn_set_PLL_freq_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	u8 buf, buf1; | |
| +	u32 freq_thres_div2_KHz, freq_thres_div3r_KHz, | |
| +	    freq_thres_div3_KHz; | |
| +	const u32 freq_KHz = state->tuner_freq; | |
| +	if (state->tuner_mtt == 0xD1) { | |
| +		_mt_fe_tn_set_reg(state, 0x32, 0xe1); | |
| +		_mt_fe_tn_set_reg(state, 0x33, 0xa6); | |
| +		_mt_fe_tn_set_reg(state, 0x37, 0x7f); | |
| +		_mt_fe_tn_set_reg(state, 0x38, 0x20); | |
| +		_mt_fe_tn_set_reg(state, 0x39, 0x18); | |
| +		_mt_fe_tn_set_reg(state, 0x40, 0x40); | |
| +		 freq_thres_div2_KHz = 520000; | |
| +		_mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, | |
| +					   freq_thres_div2_KHz, 0, 0); | |
| +		 msleep(5); | |
| +		_mt_fe_tn_get_reg(state, 0x3a, &buf); | |
| +		buf1 = buf; | |
| +		buf = buf & 0x03; | |
| +		buf1 = buf1 & 0x01; | |
| +		if ((buf1 == 0) || (buf == 3)) { | |
| +			freq_thres_div2_KHz = 420000; | |
| +			_mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, | |
| +						   freq_thres_div2_KHz, 0, | |
| +						   0); | |
| +			msleep(5); | |
| +			 _mt_fe_tn_get_reg(state, 0x3a, &buf); | |
| +			buf = buf & 0x07; | |
| +			if (buf == 5) { | |
| +				freq_thres_div2_KHz = 520000; | |
| +				_mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, | |
| +							   freq_thres_div2_KHz, | |
| +							   0, 0); | |
| +				msleep(5); | |
| +			} | |
| +		} | |
| +		 _mt_fe_tn_get_reg(state, 0x38, &buf); | |
| +		_mt_fe_tn_set_reg(state, 0x38, buf); | |
| +		 _mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = buf | 0x10; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		 _mt_fe_tn_set_reg(state, 0x30, 0x7f); | |
| +		_mt_fe_tn_set_reg(state, 0x30, 0xff); | |
| +		 _mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = buf & 0xdf; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		_mt_fe_tn_set_reg(state, 0x40, 0x0); | |
| +		 _mt_fe_tn_set_reg(state, 0x30, 0x7f); | |
| +		_mt_fe_tn_set_reg(state, 0x30, 0xff); | |
| +		_mt_fe_tn_set_reg(state, 0x31, 0x80); | |
| +		_mt_fe_tn_set_reg(state, 0x31, 0x00); | |
| +		msleep(5); | |
| +		 _mt_fe_tn_get_reg(state, 0x39, &buf); | |
| +		buf = buf >> 5; | |
| +		if (buf < 5) { | |
| +			_mt_fe_tn_get_reg(state, 0x39, &buf); | |
| +			buf = buf | 0xa0; | |
| +			buf = buf & 0xbf; | |
| +			_mt_fe_tn_set_reg(state, 0x39, buf); | |
| +			 _mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +			buf = buf | 0x02; | |
| +			_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		} | |
| +		 _mt_fe_tn_get_reg(state, 0x37, &buf); | |
| +		if (buf > 0x70) { | |
| +			buf = 0x7f; | |
| +			_mt_fe_tn_set_reg(state, 0x40, 0x40); | |
| +		} | |
| +		_mt_fe_tn_set_reg(state, 0x37, buf); | |
| +		  _mt_fe_tn_get_reg(state, 0x38, &buf); | |
| +		if (buf < 0x0f) { | |
| +			buf = (buf & 0x0f) << 2; | |
| +			buf = buf + 0x0f; | |
| +			_mt_fe_tn_set_reg(state, 0x37, buf); | |
| +		} else if (buf < 0x1f) { | |
| +			buf = buf + 0x0f; | |
| +			_mt_fe_tn_set_reg(state, 0x37, buf); | |
| +		} | |
| +		 _mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = (buf | 0x20) & 0xef; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		 _mt_fe_tn_set_reg(state, 0x41, 0x00); | |
| +		msleep(5); | |
| +		_mt_fe_tn_set_reg(state, 0x41, 0x02); | |
| +	} else if (state->tuner_mtt == 0xE1) { | |
| +		freq_thres_div2_KHz = 580000; | |
| +		freq_thres_div3r_KHz = 500000; | |
| +		freq_thres_div3_KHz = 440000; | |
| +		_mt_fe_tn_cali_PLL_tc2800(state, freq_KHz, | |
| +					   freq_thres_div2_KHz, | |
| +					   freq_thres_div3r_KHz, | |
| +					   freq_thres_div3_KHz); | |
| +		msleep(3); | |
| +		_mt_fe_tn_get_reg(state, 0x38, &buf); | |
| +		_mt_fe_tn_set_reg(state, 0x38, buf); | |
| +		_mt_fe_tn_set_reg(state, 0x30, 0x7f); | |
| +		_mt_fe_tn_set_reg(state, 0x30, 0xff); | |
| +		_mt_fe_tn_set_reg(state, 0x31, 0x80); | |
| +		_mt_fe_tn_set_reg(state, 0x31, 0x00); | |
| +		msleep(3); | |
| +		_mt_fe_tn_get_reg(state, 0x38, &buf); | |
| +		_mt_fe_tn_set_reg(state, 0x38, buf); | |
| +		_mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = buf | 0x10; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		 _mt_fe_tn_set_reg(state, 0x30, 0x7f); | |
| +		_mt_fe_tn_set_reg(state, 0x30, 0xff); | |
| +		_mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = buf & 0xdf; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		_mt_fe_tn_set_reg(state, 0x31, 0x80); | |
| +		_mt_fe_tn_set_reg(state, 0x31, 0x00); | |
| +		msleep(3); | |
| +		_mt_fe_tn_get_reg(state, 0x37, &buf); | |
| +		_mt_fe_tn_set_reg(state, 0x37, buf); | |
| +		/* | |
| +		   if ((freq_KHz == 802000) || (freq_KHz == 826000)) { | |
| +		   _mt_fe_tn_set_reg(state, 0x37, 0x5e); | |
| +		   } | |
| +		 */ | |
| +		_mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = (buf & 0xef) | 0x30; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		 _mt_fe_tn_set_reg(state, 0x41, 0x00); | |
| +		msleep(2); | |
| +		_mt_fe_tn_set_reg(state, 0x41, 0x02); | |
| +	} else { | |
| +		return 1; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int _mt_fe_tn_set_BB_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	return 0; | |
| +} | |
| + | |
| + static int _mt_fe_tn_set_appendix_tc2800(struct m88dc2800_state *state) | |
| + | |
| +{ | |
| +	u8 buf; | |
| +	const u32 freq_KHz = state->tuner_freq; | |
| +	if (state->tuner_mtt == 0xD1) { | |
| +		if ((freq_KHz == 123000) || (freq_KHz == 147000) || | |
| +		    (freq_KHz == 171000) || (freq_KHz == 195000)) { | |
| +			_mt_fe_tn_set_reg(state, 0x20, 0x1b); | |
| +		} | |
| +		if ((freq_KHz == 371000) || (freq_KHz == 419000) || | |
| +		    (freq_KHz == 610000) || (freq_KHz == 730000) || | |
| +		    (freq_KHz == 754000) || (freq_KHz == 826000)) { | |
| +			_mt_fe_tn_get_reg(state, 0x0d, &buf); | |
| +			_mt_fe_tn_set_reg(state, 0x0d, (u8) (buf + 1)); | |
| +		} | |
| +		if ((freq_KHz == 522000) || (freq_KHz == 578000) || | |
| +		    (freq_KHz == 634000) || (freq_KHz == 690000) || | |
| +		    (freq_KHz == 834000)) { | |
| +			_mt_fe_tn_get_reg(state, 0x0d, &buf); | |
| +			_mt_fe_tn_set_reg(state, 0x0d, (u8) (buf - 1)); | |
| +		} | |
| +	} else if (state->tuner_mtt == 0xE1) { | |
| +		_mt_fe_tn_set_reg(state, 0x20, 0xfc); | |
| +		if (freq_KHz == 123000 || freq_KHz == 147000 || | |
| +		    freq_KHz == 171000 || freq_KHz == 195000 || | |
| +		    freq_KHz == 219000 || freq_KHz == 267000 || | |
| +		    freq_KHz == 291000 || freq_KHz == 339000 || | |
| +		    freq_KHz == 387000 || freq_KHz == 435000 || | |
| +		    freq_KHz == 482000 || freq_KHz == 530000 || | |
| +		    freq_KHz == 722000 || | |
| +		    (state->tuner_custom_cfg == 1 && freq_KHz == 315000)) { | |
| +			_mt_fe_tn_set_reg(state, 0x20, 0x5c); | |
| +		} | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| + static int _mt_fe_tn_set_DAC_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	u8 buf, tempnumber; | |
| +	s32 N; | |
| +	s32 f1f2number, f1, f2, delta1, Totalnum1; | |
| +	s32 cntT, cntin, NCOI, z0, z1, z2, tmp; | |
| +	u32 fc, fadc, fsd, f2d; | |
| +	u32 FreqTrue108_Hz; | |
| +	s32 M = state->tuner_crystal / 4000; | |
| +	/* const u8 bandwidth = state->tuner_bandwidth; */ | |
| +	const u16 DAC_fre = 108; | |
| +	const u32 crystal_KHz = state->tuner_crystal; | |
| +	const u32 DACFreq_KHz = state->tuner_dac; | |
| +	const u32 freq_KHz = state->tuner_freq; | |
| + | |
| +	if (state->tuner_mtt == 0xE1) { | |
| +		_mt_fe_tn_get_reg(state, 0x33, &buf); | |
| +		M = buf & 0x0f; | |
| +		if (M == 0) | |
| +			M = 6; | |
| +	} | |
| +	_mt_fe_tn_get_reg(state, 0x34, &buf); | |
| +	N = buf & 0x07; | |
| +	_mt_fe_tn_get_reg(state, 0x35, &buf); | |
| +	N = (N << 8) + buf; | |
| +	buf = ((N + 256) * crystal_KHz / M / DAC_fre + 500) / 1000; | |
| +	if (state->tuner_mtt == 0xE1) { | |
| +		_mt_fe_tn_set_appendix_tc2800(state); | |
| +		if (freq_KHz == 187000 || freq_KHz == 195000 || | |
| +		    freq_KHz == 131000 || freq_KHz == 211000 || | |
| +		    freq_KHz == 219000 || freq_KHz == 227000 || | |
| +		    freq_KHz == 267000 || freq_KHz == 299000 || | |
| +		    freq_KHz == 347000 || freq_KHz == 363000 || | |
| +		    freq_KHz == 395000 || freq_KHz == 403000 || | |
| +		    freq_KHz == 435000 || freq_KHz == 482000 || | |
| +		    freq_KHz == 474000 || freq_KHz == 490000 || | |
| +		    freq_KHz == 610000 || freq_KHz == 642000 || | |
| +		    freq_KHz == 666000 || freq_KHz == 722000 || | |
| +		    freq_KHz == 754000 || | |
| +		    ((freq_KHz == 379000 || freq_KHz == 467000 || | |
| +		      freq_KHz == 762000) && state->tuner_custom_cfg != 1)) { | |
| +			buf = buf + 1; | |
| +		} | |
| +		if (freq_KHz == 123000 || freq_KHz == 139000 || | |
| +		    freq_KHz == 147000 || freq_KHz == 171000 || | |
| +		    freq_KHz == 179000 || freq_KHz == 203000 || | |
| +		    freq_KHz == 235000 || freq_KHz == 251000 || | |
| +		    freq_KHz == 259000 || freq_KHz == 283000 || | |
| +		    freq_KHz == 331000 || freq_KHz == 363000 || | |
| +		    freq_KHz == 371000 || freq_KHz == 387000 || | |
| +		    freq_KHz == 411000 || freq_KHz == 427000 || | |
| +		    freq_KHz == 443000 || freq_KHz == 451000 || | |
| +		    freq_KHz == 459000 || freq_KHz == 506000 || | |
| +		    freq_KHz == 514000 || freq_KHz == 538000 || | |
| +		    freq_KHz == 546000 || freq_KHz == 554000 || | |
| +		    freq_KHz == 562000 || freq_KHz == 570000 || | |
| +		    freq_KHz == 578000 || freq_KHz == 602000 || | |
| +		    freq_KHz == 626000 || freq_KHz == 658000 || | |
| +		    freq_KHz == 690000 || freq_KHz == 714000 || | |
| +		    freq_KHz == 746000 || freq_KHz == 522000 || | |
| +		    freq_KHz == 826000 || freq_KHz == 155000 || | |
| +		    freq_KHz == 530000 || | |
| +		    ((freq_KHz == 275000 || freq_KHz == 355000) && | |
| +		     state->tuner_custom_cfg != 1) || | |
| +		    ((freq_KHz == 467000 || freq_KHz == 762000 || | |
| +		      freq_KHz == 778000 || freq_KHz == 818000) && | |
| +		     state->tuner_custom_cfg == 1)) { | |
| +			buf = buf - 1; | |
| +		} | |
| +	} | |
| +	 _mt_fe_tn_set_reg(state, 0x0e, buf); | |
| +	_mt_fe_tn_set_reg(state, 0x0d, buf); | |
| +	f1f2number = | |
| +	    (((DACFreq_KHz * M * buf) / crystal_KHz) << 16) / (N + 256) + | |
| +	    (((DACFreq_KHz * M * buf) % crystal_KHz) << 16) / ((N + 256) * | |
| +								crystal_KHz); | |
| +	_mt_fe_tn_set_reg(state, 0xf1, (f1f2number & 0xff00) >> 8); | |
| +	_mt_fe_tn_set_reg(state, 0xf2, f1f2number & 0x00ff); | |
| +	 FreqTrue108_Hz = | |
| +	    (N + 256) * crystal_KHz / (M * buf) * 1000 + | |
| +	    (((N + 256) * crystal_KHz) % (M * buf)) * 1000 / (M * buf); | |
| +	f1 = 4096; | |
| +	fc = FreqTrue108_Hz; | |
| +	fadc = fc / 4; | |
| +	fsd = 27000000; | |
| +	f2d = state->tuner_bandwidth * 1000 / 2 - 150; | |
| +	f2 = (fsd / 250) * f2d / ((fc + 500) / 1000); | |
| +	delta1 = ((f1 - f2) << 15) / f2; | |
| +	Totalnum1 = ((f1 - f2) << 15) - delta1 * f2; | |
| +	cntT = f2; | |
| +	cntin = Totalnum1; | |
| +	NCOI = delta1; | |
| +	 z0 = cntin; | |
| +	z1 = cntT; | |
| +	z2 = NCOI; | |
| +	tempnumber = (z0 & 0xff00) >> 8; | |
| +	_mt_fe_tn_set_reg(state, 0xc9, (u8) (tempnumber & 0x0f)); | |
| +	tempnumber = (z0 & 0xff); | |
| +	_mt_fe_tn_set_reg(state, 0xca, tempnumber); | |
| +	 tempnumber = (z1 & 0xff00) >> 8; | |
| +	_mt_fe_tn_set_reg(state, 0xcb, tempnumber); | |
| +	tempnumber = (z1 & 0xff); | |
| +	_mt_fe_tn_set_reg(state, 0xcc, tempnumber); | |
| +	 tempnumber = (z2 & 0xff00) >> 8; | |
| +	_mt_fe_tn_set_reg(state, 0xcd, tempnumber); | |
| +	tempnumber = (z2 & 0xff); | |
| +	_mt_fe_tn_set_reg(state, 0xce, tempnumber); | |
| +	 tmp = f1; | |
| +	f1 = f2; | |
| +	f2 = tmp / 2; | |
| +	delta1 = ((f1 - f2) << 15) / f2; | |
| +	Totalnum1 = ((f1 - f2) << 15) - delta1 * f2; | |
| +	NCOI = (f1 << 15) / f2 - (1 << 15); | |
| +	cntT = f2; | |
| +	cntin = Totalnum1; | |
| +	z0 = cntin; | |
| +	z1 = cntT; | |
| +	z2 = NCOI; | |
| +	tempnumber = (z0 & 0xff00) >> 8; | |
| +	_mt_fe_tn_set_reg(state, 0xd9, (u8) (tempnumber & 0x0f)); | |
| +	tempnumber = (z0 & 0xff); | |
| +	_mt_fe_tn_set_reg(state, 0xda, tempnumber); | |
| +	 tempnumber = (z1 & 0xff00) >> 8; | |
| +	_mt_fe_tn_set_reg(state, 0xdb, tempnumber); | |
| +	tempnumber = (z1 & 0xff); | |
| +	_mt_fe_tn_set_reg(state, 0xdc, tempnumber); | |
| +	 tempnumber = (z2 & 0xff00) >> 8; | |
| +	_mt_fe_tn_set_reg(state, 0xdd, tempnumber); | |
| +	tempnumber = (z2 & 0xff); | |
| +	_mt_fe_tn_set_reg(state, 0xde, tempnumber); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int _mt_fe_tn_preset_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	if (state->tuner_mtt == 0xD1) { | |
| +		_mt_fe_tn_set_reg(state, 0x19, 0x4a); | |
| +		_mt_fe_tn_set_reg(state, 0x1b, 0x4b); | |
| +		 _mt_fe_tn_set_reg(state, 0x04, 0x04); | |
| +		_mt_fe_tn_set_reg(state, 0x17, 0x0d); | |
| +		_mt_fe_tn_set_reg(state, 0x62, 0x6c); | |
| +		_mt_fe_tn_set_reg(state, 0x63, 0xf4); | |
| +		_mt_fe_tn_set_reg(state, 0x1f, 0x0e); | |
| +		_mt_fe_tn_set_reg(state, 0x6b, 0xf4); | |
| +		_mt_fe_tn_set_reg(state, 0x14, 0x01); | |
| +		_mt_fe_tn_set_reg(state, 0x5a, 0x75); | |
| +		_mt_fe_tn_set_reg(state, 0x66, 0x74); | |
| +		_mt_fe_tn_set_reg(state, 0x72, 0xe0); | |
| +		_mt_fe_tn_set_reg(state, 0x70, 0x07); | |
| +		_mt_fe_tn_set_reg(state, 0x15, 0x7b); | |
| +		_mt_fe_tn_set_reg(state, 0x55, 0x71); | |
| +		 _mt_fe_tn_set_reg(state, 0x75, 0x55); | |
| +		_mt_fe_tn_set_reg(state, 0x76, 0xac); | |
| +		_mt_fe_tn_set_reg(state, 0x77, 0x6c); | |
| +		_mt_fe_tn_set_reg(state, 0x78, 0x8b); | |
| +		_mt_fe_tn_set_reg(state, 0x79, 0x42); | |
| +		_mt_fe_tn_set_reg(state, 0x7a, 0xd2); | |
| +		 _mt_fe_tn_set_reg(state, 0x81, 0x01); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x00); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x02); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x04); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x06); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x08); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x09); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x29); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x49); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x58); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x59); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x98); | |
| +		_mt_fe_tn_set_reg(state, 0x82, 0x99); | |
| +		_mt_fe_tn_set_reg(state, 0x10, 0x05); | |
| +		_mt_fe_tn_set_reg(state, 0x10, 0x0d); | |
| +		_mt_fe_tn_set_reg(state, 0x11, 0x95); | |
| +		_mt_fe_tn_set_reg(state, 0x11, 0x9d); | |
| +		if (state->tuner_loopthrough != 0) { | |
| +			_mt_fe_tn_set_reg(state, 0x67, 0x25); | |
| +		} else { | |
| +			_mt_fe_tn_set_reg(state, 0x67, 0x05); | |
| +		} | |
| +	} else if (state->tuner_mtt == 0xE1) { | |
| +		_mt_fe_tn_set_reg(state, 0x1b, 0x47); | |
| +		if (state->tuner_mode == 0) {	/* DVB-C */ | |
| +			_mt_fe_tn_set_reg(state, 0x66, 0x74); | |
| +			_mt_fe_tn_set_reg(state, 0x62, 0x2c); | |
| +			_mt_fe_tn_set_reg(state, 0x63, 0x54); | |
| +			_mt_fe_tn_set_reg(state, 0x68, 0x0b); | |
| +			_mt_fe_tn_set_reg(state, 0x14, 0x00); | |
| +		} else {			/* CTTB */ | |
| +			_mt_fe_tn_set_reg(state, 0x66, 0x74); | |
| +			_mt_fe_tn_set_reg(state, 0x62, 0x0c); | |
| +			_mt_fe_tn_set_reg(state, 0x63, 0x54); | |
| +			_mt_fe_tn_set_reg(state, 0x68, 0x0b); | |
| +			_mt_fe_tn_set_reg(state, 0x14, 0x05); | |
| +		} | |
| +		_mt_fe_tn_set_reg(state, 0x6f, 0x00); | |
| +		_mt_fe_tn_set_reg(state, 0x84, 0x04); | |
| +		_mt_fe_tn_set_reg(state, 0x5e, 0xbe); | |
| +		_mt_fe_tn_set_reg(state, 0x87, 0x07); | |
| +		_mt_fe_tn_set_reg(state, 0x8a, 0x1f); | |
| +		_mt_fe_tn_set_reg(state, 0x8b, 0x1f); | |
| +		_mt_fe_tn_set_reg(state, 0x88, 0x30); | |
| +		_mt_fe_tn_set_reg(state, 0x58, 0x34); | |
| +		_mt_fe_tn_set_reg(state, 0x61, 0x8c); | |
| +		_mt_fe_tn_set_reg(state, 0x6a, 0x42); | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int mt_fe_tn_wakeup_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	_mt_fe_tn_set_reg(state, 0x16, 0xb1); | |
| +	_mt_fe_tn_set_reg(state, 0x09, 0x7d); | |
| +	return 0; | |
| +} | |
| + | |
| +  static int mt_fe_tn_sleep_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	_mt_fe_tn_set_reg(state, 0x16, 0xb0); | |
| +	_mt_fe_tn_set_reg(state, 0x09, 0x6d); | |
| +	return 0; | |
| +} | |
| + | |
| + static int mt_fe_tn_init_tc2800(struct m88dc2800_state *state) | |
| +{ | |
| +	if (state->tuner_init_OK != 1) { | |
| +		state->tuner_dev_addr = 0x61;	/* TUNER_I2C_ADDR_TC2800 */ | |
| +		state->tuner_freq = 650000; | |
| +		state->tuner_qam = 0; | |
| +		state->tuner_mode = 0;	// 0: DVB-C, 1: CTTB | |
| +		state->tuner_bandwidth = 8; | |
| +		state->tuner_loopthrough = 0; | |
| +		state->tuner_crystal = 24000; | |
| +		state->tuner_dac = 7200; | |
| +		state->tuner_mtt = 0x00; | |
| +		state->tuner_custom_cfg = 0; | |
| +		state->tuner_version = 30022;	/* Driver version number */ | |
| +		state->tuner_time = 12092611; | |
| +		state->tuner_init_OK = 1; | |
| +	} | |
| +	_mt_fe_tn_set_reg(state, 0x2b, 0x46); | |
| +	_mt_fe_tn_set_reg(state, 0x2c, 0x75); | |
| +	if (state->tuner_mtt == 0x00) { | |
| +		u8 tmp = 0; | |
| +		_mt_fe_tn_get_reg(state, 0x01, &tmp); | |
| +		printk(KERN_INFO "m88dc2800: tuner id = 0x%02x ", tmp); | |
| +		switch (tmp) { | |
| +		case 0x0d: | |
| +			state->tuner_mtt = 0xD1; | |
| +			break; | |
| +		case 0x8e: | |
| +		default: | |
| +			state->tuner_mtt = 0xE1; | |
| +			break; | |
| +		} | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| + static int mt_fe_tn_set_freq_tc2800(struct m88dc2800_state *state, | |
| +				       u32 freq_KHz) | |
| +{ | |
| +	u8 buf; | |
| +	u8 buf1; | |
| + | |
| +	mt_fe_tn_init_tc2800(state); | |
| +	state->tuner_freq = freq_KHz; | |
| +	_mt_fe_tn_set_reg(state, 0x21, freq_KHz > 500000 ? 0xb9 : 0x99); | |
| +	mt_fe_tn_wakeup_tc2800(state); | |
| +	 _mt_fe_tn_set_reg(state, 0x05, 0x7f); | |
| +	_mt_fe_tn_set_reg(state, 0x06, 0xf8); | |
| +	 _mt_fe_tn_set_RF_front_tc2800(state); | |
| +	_mt_fe_tn_set_PLL_freq_tc2800(state); | |
| +	_mt_fe_tn_set_DAC_tc2800(state); | |
| +	_mt_fe_tn_set_BB_tc2800(state); | |
| +	_mt_fe_tn_preset_tc2800(state); | |
| +	 _mt_fe_tn_set_reg(state, 0x05, 0x00); | |
| +	_mt_fe_tn_set_reg(state, 0x06, 0x00); | |
| +	 if (state->tuner_mtt == 0xD1) { | |
| +		_mt_fe_tn_set_reg(state, 0x00, 0x01); | |
| +		_mt_fe_tn_set_reg(state, 0x00, 0x00); | |
| +		 msleep(5); | |
| +		_mt_fe_tn_set_reg(state, 0x41, 0x00); | |
| +		msleep(5); | |
| +		_mt_fe_tn_set_reg(state, 0x41, 0x02); | |
| + | |
| +		_mt_fe_tn_get_reg(state, 0x69, &buf1); | |
| +		buf1 = buf1 & 0x0f; | |
| +		_mt_fe_tn_get_reg(state, 0x61, &buf); | |
| +		buf = buf & 0x0f; | |
| +		if (buf == 0x0c) | |
| +			_mt_fe_tn_set_reg(state, 0x6a, 0x59); | |
| +		if (buf1 > 0x02) { | |
| +			if (freq_KHz > 600000) | |
| +				_mt_fe_tn_set_reg(state, 0x66, 0x44); | |
| +			else if (freq_KHz > 500000) | |
| +				_mt_fe_tn_set_reg(state, 0x66, 0x64); | |
| +			else | |
| +				_mt_fe_tn_set_reg(state, 0x66, 0x74); | |
| +		}		 | |
| +		if (buf1 < 0x03) { | |
| +			if (freq_KHz > 800000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x64); | |
| +			else if (freq_KHz > 600000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +			else if (freq_KHz > 500000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +			else if (freq_KHz > 300000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x43); | |
| +			else if (freq_KHz > 220000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +			else if (freq_KHz > 110000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x14); | |
| +			else | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +			msleep(5); | |
| +		} else if (buf < 0x0c) { | |
| +			if (freq_KHz > 800000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x14); | |
| +			else if (freq_KHz > 600000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x14); | |
| +			else if (freq_KHz > 500000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x34); | |
| +			else if (freq_KHz > 300000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x43); | |
| +			else if (freq_KHz > 220000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +			else if (freq_KHz > 110000) | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x14); | |
| +			else | |
| +				_mt_fe_tn_set_reg(state, 0x87, 0x54); | |
| +			msleep(5); | |
| +		} | |
| +	} else if ((state->tuner_mtt == 0xE1)) { | |
| +		_mt_fe_tn_set_reg(state, 0x00, 0x01); | |
| +		_mt_fe_tn_set_reg(state, 0x00, 0x00); | |
| +		 msleep(20); | |
| +		 _mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = (buf & 0xef) | 0x28; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		 msleep(50); | |
| +		_mt_fe_tn_get_reg(state, 0x38, &buf); | |
| +		_mt_fe_tn_set_reg(state, 0x38, buf); | |
| +		_mt_fe_tn_get_reg(state, 0x32, &buf); | |
| +		buf = (buf & 0xf7) | 0x10; | |
| +		_mt_fe_tn_set_reg(state, 0x32, buf); | |
| +		 msleep(10); | |
| +		 _mt_fe_tn_get_reg(state, 0x69, &buf); | |
| +		buf = buf & 0x03; | |
| +		_mt_fe_tn_set_reg(state, 0x2a, buf); | |
| +		if (buf > 0) { | |
| +			msleep(20); | |
| +			_mt_fe_tn_get_reg(state, 0x84, &buf); | |
| +			buf = buf & 0x1f; | |
| +			_mt_fe_tn_set_reg(state, 0x68, 0x0a); | |
| +			_mt_fe_tn_get_reg(state, 0x88, &buf1); | |
| +			buf1 = buf1 & 0x1f; | |
| +			if (buf <= buf1) | |
| +				_mt_fe_tn_set_reg(state, 0x66, 0x44); | |
| +			else | |
| +				_mt_fe_tn_set_reg(state, 0x66, 0x74); | |
| +		} else { | |
| +			if (freq_KHz <= 600000) | |
| +				_mt_fe_tn_set_reg(state, 0x68, 0x0c); | |
| +			else | |
| +				_mt_fe_tn_set_reg(state, 0x68, 0x0e); | |
| +			_mt_fe_tn_set_reg(state, 0x30, 0xfb); | |
| +			_mt_fe_tn_set_reg(state, 0x30, 0xff); | |
| +			_mt_fe_tn_set_reg(state, 0x31, 0x04); | |
| +			_mt_fe_tn_set_reg(state, 0x31, 0x00); | |
| +		} | |
| +		if (state->tuner_loopthrough != 0) { | |
| +			_mt_fe_tn_get_reg(state, 0x28, &buf); | |
| +			if (buf == 0) { | |
| +				_mt_fe_tn_set_reg(state, 0x28, 0xff); | |
| +				_mt_fe_tn_get_reg(state, 0x61, &buf); | |
| +				buf = buf & 0x0f; | |
| +				if (buf > 9) | |
| +					_mt_fe_tn_set_reg(state, 0x67, 0x74); | |
| +				else if (buf > 6) | |
| +					_mt_fe_tn_set_reg(state, 0x67, 0x64); | |
| +				else if (buf > 3) | |
| +					_mt_fe_tn_set_reg(state, 0x67, 0x54); | |
| +				else | |
| +					_mt_fe_tn_set_reg(state, 0x67, 0x44); | |
| +			} | |
| +		} else { | |
| +			_mt_fe_tn_set_reg(state, 0x67, 0x34); | |
| +		} | |
| +	} else { | |
| +		return 1; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| + | |
| +/* | |
| +static int mt_fe_tn_set_BB_filter_band_tc2800(struct m88dc2800_state *state, | |
| +					      u8 bandwidth) | |
| +{ | |
| +	u8 buf, tmp; | |
| + | |
| +	_mt_fe_tn_get_reg(state, 0x53, &tmp); | |
| + | |
| +	if (bandwidth == 6) | |
| +		buf = 0x01 << 1; | |
| +	else if (bandwidth == 7) | |
| +		buf = 0x02 << 1; | |
| +	else if (bandwidth == 8) | |
| +		buf = 0x04 << 1; | |
| +	else | |
| +		buf = 0x04 << 1; | |
| + | |
| +	tmp &= 0xf1; | |
| +	tmp |= buf; | |
| +	_mt_fe_tn_set_reg(state, 0x53, tmp); | |
| +	state->tuner_bandwidth = bandwidth; | |
| +	return 0; | |
| +} | |
| +*/ | |
| + | |
| +static s32 mt_fe_tn_get_signal_strength_tc2800(struct m88dc2800_state | |
| +					       *state) | |
| +{ | |
| +	s32 level = -107; | |
| +	s32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6; | |
| +	s32 val1, val2, val; | |
| +	s32 result2, result3, result4, result5, result6; | |
| +	s32 append; | |
| +	u8 tmp; | |
| +	s32 freq_KHz = (s32) state->tuner_freq; | |
| +	if (state->tuner_mtt == 0xD1) { | |
| +		_mt_fe_tn_get_reg(state, 0x61, &tmp); | |
| +		tmp1 = tmp & 0x0f; | |
| +		 _mt_fe_tn_get_reg(state, 0x69, &tmp); | |
| +		tmp2 = tmp & 0x0f; | |
| +		 _mt_fe_tn_get_reg(state, 0x73, &tmp); | |
| +		tmp3 = tmp & 0x07; | |
| +		 _mt_fe_tn_get_reg(state, 0x7c, &tmp); | |
| +		tmp4 = (tmp >> 4) & 0x0f; | |
| +		 _mt_fe_tn_get_reg(state, 0x7b, &tmp); | |
| +		tmp5 = tmp & 0x0f; | |
| +		 _mt_fe_tn_get_reg(state, 0x7f, &tmp); | |
| +		tmp6 = (tmp >> 5) & 0x01; | |
| +		if (tmp1 > 6) { | |
| +			val1 = 0; | |
| +			if (freq_KHz <= 200000) { | |
| +				val2 = (tmp1 - 6) * 267; | |
| +			} else if (freq_KHz <= 600000) { | |
| +				val2 = (tmp1 - 6) * 280; | |
| +			} else { | |
| +				val2 = (tmp1 - 6) * 290; | |
| +			} | |
| +			val = val1 + val2; | |
| +		} else { | |
| +			if (tmp1 == 0) { | |
| +				val1 = -550; | |
| +			} else { | |
| +				val1 = 0; | |
| +			} | |
| +			if ((tmp1 < 4) && (freq_KHz >= 506000)) { | |
| +				val1 = -850; | |
| +			} | |
| +			val2 = 0; | |
| +			val = val1 + val2; | |
| +		} | |
| +		if (freq_KHz <= 95000) { | |
| +			result2 = tmp2 * 289; | |
| +		} else if (freq_KHz <= 155000) { | |
| +			result2 = tmp2 * 278; | |
| +		} else if (freq_KHz <= 245000) { | |
| +			result2 = tmp2 * 267; | |
| +		} else if (freq_KHz <= 305000) { | |
| +			result2 = tmp2 * 256; | |
| +		} else if (freq_KHz <= 335000) { | |
| +			result2 = tmp2 * 244; | |
| +		} else if (freq_KHz <= 425000) { | |
| +			result2 = tmp2 * 233; | |
| +		} else if (freq_KHz <= 575000) { | |
| +			result2 = tmp2 * 222; | |
| +		} else if (freq_KHz <= 665000) { | |
| +			result2 = tmp2 * 211; | |
| +		} else { | |
| +			result2 = tmp2 * 200; | |
| +		} | |
| +		result3 = (6 - tmp3) * 100; | |
| +		result4 = 300 * tmp4; | |
| +		result5 = 50 * tmp5; | |
| +		result6 = 300 * tmp6; | |
| +		if (freq_KHz < 105000) { | |
| +			append = -450; | |
| +		} else if (freq_KHz <= 227000) { | |
| +			append = -4 * (freq_KHz / 1000 - 100) + 150; | |
| +		} else if (freq_KHz <= 305000) { | |
| +			append = -4 * (freq_KHz / 1000 - 100); | |
| +		} else if (freq_KHz <= 419000) { | |
| +			append = 500 - 40 * (freq_KHz / 1000 - 300) / 17 + 130; | |
| +		} else if (freq_KHz <= 640000) { | |
| +			append = 500 - 40 * (freq_KHz / 1000 - 300) / 17; | |
| +		} else { | |
| +			append = -500; | |
| +		} | |
| +		level = append - (val + result2 + result3 + result4 + | |
| +				  result5 + result6); | |
| +		level /= 100; | |
| +	} else if (state->tuner_mtt == 0xE1) { | |
| +		_mt_fe_tn_get_reg(state, 0x61, &tmp); | |
| +		tmp1 = tmp & 0x0f; | |
| +		 _mt_fe_tn_get_reg(state, 0x84, &tmp); | |
| +		tmp2 = tmp & 0x1f; | |
| +		 _mt_fe_tn_get_reg(state, 0x69, &tmp); | |
| +		tmp3 = tmp & 0x03; | |
| +		 _mt_fe_tn_get_reg(state, 0x73, &tmp); | |
| +		tmp4 = tmp & 0x0f; | |
| +		 _mt_fe_tn_get_reg(state, 0x7c, &tmp); | |
| +		tmp5 = (tmp >> 4) & 0x0f; | |
| +		 _mt_fe_tn_get_reg(state, 0x7b, &tmp); | |
| +		tmp6 = tmp & 0x0f; | |
| +		if (freq_KHz < 151000) { | |
| +			result2 = (1150 - freq_KHz / 100) * 163 / 33 + 4230; | |
| +			result3 = (1150 - freq_KHz / 100) * 115 / 33 + 1850; | |
| +			result4 = -3676 * (freq_KHz / 1000) / 100 + 6115; | |
| +		} else if (freq_KHz < 257000) { | |
| +			result2 = (1540 - freq_KHz / 100) * 11 / 4 + 3870; | |
| +			result3 = (1540 - freq_KHz / 100) * 205 / 96 + 2100; | |
| +			result4 = -21 * freq_KHz / 1000 + 5084; | |
| +		} else if (freq_KHz < 305000) { | |
| +			result2 = (2620 - freq_KHz / 100) * 5 / 3 + 2770; | |
| +			result3 = (2620 - freq_KHz / 100) * 10 / 7 + 1700; | |
| +			result4 = 650; | |
| +		} else if (freq_KHz < 449000) { | |
| +			result2 = (307 - freq_KHz / 1000) * 82 / 27 + 11270; | |
| +			result3 = (3100 - freq_KHz / 100) * 5 / 3 + 10000; | |
| +			result4 = 134 * freq_KHz / 10000 + 11875; | |
| +		} else { | |
| +			result2 = (307 - freq_KHz / 1000) * 82 / 27 + 11270; | |
| +			result3 = 8400; | |
| +			result4 = 5300; | |
| +		} | |
| +		if (tmp1 > 6) { | |
| +			val1 = result2; | |
| +			val2 = 2900; | |
| +			val = 500; | |
| +		} else if (tmp1 > 0) { | |
| +			val1 = result3; | |
| +			val2 = 2700; | |
| +			val = 500; | |
| +		} else { | |
| +			val1 = result4; | |
| +			val2 = 2700; | |
| +			val = 400; | |
| +		} | |
| +		level = val1 - (val2 * tmp1 + 500 * tmp2 + 3000 * tmp3 - | |
| +			    500 * tmp4 + 3000 * tmp5 + val * tmp6) - 1000; | |
| +		level /= 1000; | |
| +	} | |
| +	return level; | |
| +} | |
| + | |
| + | |
| +/* m88dc2800 operation functions */ | |
| +u8 M88DC2000GetLock(struct m88dc2800_state * state) | |
| +{ | |
| +	u8 u8ret = 0; | |
| +	if (ReadReg(state, 0x80) < 0x06) { | |
| +		if ((ReadReg(state, 0xdf) & 0x80) == 0x80 | |
| +		     &&(ReadReg(state, 0x91) & 0x23) == 0x03 | |
| +		     &&(ReadReg(state, 0x43) & 0x08) == 0x08) | |
| +			u8ret = 1; | |
| +		else | |
| +			u8ret = 0; | |
| +	} else { | |
| +		if ((ReadReg(state, 0x85) & 0x08) == 0x08) | |
| +			u8ret = 1; | |
| +		else | |
| +			u8ret = 0; | |
| +	} | |
| +	dprintk("%s, lock=%d\n", __func__, u8ret); | |
| +	return u8ret; | |
| +} | |
| + | |
| +static int M88DC2000SetTsType(struct m88dc2800_state *state, u8 type) | |
| +{ | |
| +	u8 regC2H; | |
| + | |
| +	if (type == 3) { | |
| +		WriteReg(state, 0x84, 0x6A); | |
| +		WriteReg(state, 0xC0, 0x43); | |
| +		WriteReg(state, 0xE2, 0x06); | |
| +		regC2H = ReadReg(state, 0xC2); | |
| +		regC2H &= 0xC0; | |
| +		regC2H |= 0x1B; | |
| +		WriteReg(state, 0xC2, regC2H); | |
| +		WriteReg(state, 0xC1, 0x60);	/* common interface */ | |
| +	} else if (type == 1) { | |
| +		WriteReg(state, 0x84, 0x6A); | |
| +		WriteReg(state, 0xC0, 0x47);	/* serial format */ | |
| +		WriteReg(state, 0xE2, 0x02); | |
| +		regC2H = ReadReg(state, 0xC2); | |
| +		regC2H &= 0xC7; | |
| +		WriteReg(state, 0xC2, regC2H); | |
| +		WriteReg(state, 0xC1, 0x00); | |
| +	} else { | |
| +		WriteReg(state, 0x84, 0x6C); | |
| +		WriteReg(state, 0xC0, 0x43);	/* parallel format */ | |
| +		WriteReg(state, 0xE2, 0x06); | |
| +		regC2H = ReadReg(state, 0xC2); | |
| +		regC2H &= 0xC7; | |
| +		WriteReg(state, 0xC2, regC2H); | |
| +		WriteReg(state, 0xC1, 0x00); | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000RegInitial_TC2800(struct m88dc2800_state *state) | |
| +{ | |
| +	u8 RegE3H, RegE4H; | |
| + | |
| +	WriteReg(state, 0x00, 0x48); | |
| +	WriteReg(state, 0x01, 0x09); | |
| +	WriteReg(state, 0xFB, 0x0A); | |
| +	WriteReg(state, 0xFC, 0x0B); | |
| +	WriteReg(state, 0x02, 0x0B); | |
| +	WriteReg(state, 0x03, 0x18); | |
| +	WriteReg(state, 0x05, 0x0D); | |
| +	WriteReg(state, 0x36, 0x80); | |
| +	WriteReg(state, 0x43, 0x40); | |
| +	WriteReg(state, 0x55, 0x7A); | |
| +	WriteReg(state, 0x56, 0xD9); | |
| +	WriteReg(state, 0x57, 0xDF); | |
| +	WriteReg(state, 0x58, 0x39); | |
| +	WriteReg(state, 0x5A, 0x00); | |
| +	WriteReg(state, 0x5C, 0x71); | |
| +	WriteReg(state, 0x5D, 0x23); | |
| +	WriteReg(state, 0x86, 0x40); | |
| +	WriteReg(state, 0xF9, 0x08); | |
| +	WriteReg(state, 0x61, 0x40); | |
| +	WriteReg(state, 0x62, 0x0A); | |
| +	WriteReg(state, 0x90, 0x06); | |
| +	WriteReg(state, 0xDE, 0x00); | |
| +	WriteReg(state, 0xA0, 0x03); | |
| +	WriteReg(state, 0xDF, 0x81); | |
| +	WriteReg(state, 0xFA, 0x40); | |
| +	WriteReg(state, 0x37, 0x10); | |
| +	WriteReg(state, 0xF0, 0x40); | |
| +	WriteReg(state, 0xF2, 0x9C); | |
| +	WriteReg(state, 0xF3, 0x40); | |
| +	RegE3H = ReadReg(state, 0xE3); | |
| +	RegE4H = ReadReg(state, 0xE4); | |
| +	if (((RegE3H & 0xC0) == 0x00) && ((RegE4H & 0xC0) == 0x00)) { | |
| +		WriteReg(state, 0x30, 0xFF); | |
| +		WriteReg(state, 0x31, 0x00); | |
| +		WriteReg(state, 0x32, 0x00); | |
| +		WriteReg(state, 0x33, 0x00); | |
| +		WriteReg(state, 0x35, 0x32); | |
| +		WriteReg(state, 0x40, 0x00); | |
| +		WriteReg(state, 0x41, 0x10); | |
| +		WriteReg(state, 0xF1, 0x02); | |
| +		WriteReg(state, 0xF4, 0x04); | |
| +		WriteReg(state, 0xF5, 0x00); | |
| +		WriteReg(state, 0x42, 0x14); | |
| +		WriteReg(state, 0xE1, 0x25); | |
| +	} else if (((RegE3H & 0xC0) == 0x80) && ((RegE4H & 0xC0) == 0x40)) { | |
| +		WriteReg(state, 0x30, 0xFF); | |
| +		WriteReg(state, 0x31, 0x00); | |
| +		WriteReg(state, 0x32, 0x00); | |
| +		WriteReg(state, 0x33, 0x00); | |
| +		WriteReg(state, 0x35, 0x32); | |
| +		WriteReg(state, 0x39, 0x00); | |
| +		WriteReg(state, 0x3A, 0x00); | |
| +		WriteReg(state, 0x40, 0x00); | |
| +		WriteReg(state, 0x41, 0x10); | |
| +		WriteReg(state, 0xF1, 0x00); | |
| +		WriteReg(state, 0xF4, 0x00); | |
| +		WriteReg(state, 0xF5, 0x40); | |
| +		WriteReg(state, 0x42, 0x14); | |
| +		WriteReg(state, 0xE1, 0x25); | |
| +	} else if ((RegE3H == 0x80 || RegE3H == 0x81) | |
| +		    && (RegE4H == 0x80 || RegE4H == 0x81)) { | |
| +		WriteReg(state, 0x30, 0xFF); | |
| +		WriteReg(state, 0x31, 0x00); | |
| +		WriteReg(state, 0x32, 0x00); | |
| +		WriteReg(state, 0x33, 0x00); | |
| +		WriteReg(state, 0x35, 0x32); | |
| +		WriteReg(state, 0x39, 0x00); | |
| +		WriteReg(state, 0x3A, 0x00); | |
| +		WriteReg(state, 0xF1, 0x00); | |
| +		WriteReg(state, 0xF4, 0x00); | |
| +		WriteReg(state, 0xF5, 0x40); | |
| +		WriteReg(state, 0x42, 0x24); | |
| +		WriteReg(state, 0xE1, 0x25); | |
| +		WriteReg(state, 0x92, 0x7F); | |
| +		WriteReg(state, 0x93, 0x91); | |
| +		WriteReg(state, 0x95, 0x00); | |
| +		WriteReg(state, 0x2B, 0x33); | |
| +		WriteReg(state, 0x2A, 0x2A); | |
| +		WriteReg(state, 0x2E, 0x80); | |
| +		WriteReg(state, 0x25, 0x25); | |
| +		WriteReg(state, 0x2D, 0xFF); | |
| +		WriteReg(state, 0x26, 0xFF); | |
| +		WriteReg(state, 0x27, 0x00); | |
| +		WriteReg(state, 0x24, 0x25); | |
| +		WriteReg(state, 0xA4, 0xFF); | |
| +		WriteReg(state, 0xA3, 0x0D); | |
| +	} else { | |
| +		WriteReg(state, 0x30, 0xFF); | |
| +		WriteReg(state, 0x31, 0x00); | |
| +		WriteReg(state, 0x32, 0x00); | |
| +		WriteReg(state, 0x33, 0x00); | |
| +		WriteReg(state, 0x35, 0x32); | |
| +		WriteReg(state, 0x39, 0x00); | |
| +		WriteReg(state, 0x3A, 0x00); | |
| +		WriteReg(state, 0xF1, 0x00); | |
| +		WriteReg(state, 0xF4, 0x00); | |
| +		WriteReg(state, 0xF5, 0x40); | |
| +		WriteReg(state, 0x42, 0x24); | |
| +		WriteReg(state, 0xE1, 0x27); | |
| +		WriteReg(state, 0x92, 0x7F); | |
| +		WriteReg(state, 0x93, 0x91); | |
| +		WriteReg(state, 0x95, 0x00); | |
| +		WriteReg(state, 0x2B, 0x33); | |
| +		WriteReg(state, 0x2A, 0x2A); | |
| +		WriteReg(state, 0x2E, 0x80); | |
| +		WriteReg(state, 0x25, 0x25); | |
| +		WriteReg(state, 0x2D, 0xFF); | |
| +		WriteReg(state, 0x26, 0xFF); | |
| +		WriteReg(state, 0x27, 0x00); | |
| +		WriteReg(state, 0x24, 0x25); | |
| +		WriteReg(state, 0xA4, 0xFF); | |
| +		WriteReg(state, 0xA3, 0x10); | |
| +	} | |
| +	WriteReg(state, 0xF6, 0x4E); | |
| +	WriteReg(state, 0xF7, 0x20); | |
| +	WriteReg(state, 0x89, 0x02); | |
| +	WriteReg(state, 0x14, 0x08); | |
| +	WriteReg(state, 0x6F, 0x0D); | |
| +	WriteReg(state, 0x10, 0xFF); | |
| +	WriteReg(state, 0x11, 0x00); | |
| +	WriteReg(state, 0x12, 0x30); | |
| +	WriteReg(state, 0x13, 0x23); | |
| +	WriteReg(state, 0x60, 0x00); | |
| +	WriteReg(state, 0x69, 0x00); | |
| +	WriteReg(state, 0x6A, 0x03); | |
| +	WriteReg(state, 0xE0, 0x75); | |
| +	WriteReg(state, 0x8D, 0x29); | |
| +	WriteReg(state, 0x4E, 0xD8); | |
| +	WriteReg(state, 0x88, 0x80); | |
| +	WriteReg(state, 0x52, 0x79); | |
| +	WriteReg(state, 0x53, 0x03); | |
| +	WriteReg(state, 0x59, 0x30); | |
| +	WriteReg(state, 0x5E, 0x02); | |
| +	WriteReg(state, 0x5F, 0x0F); | |
| +	WriteReg(state, 0x71, 0x03); | |
| +	WriteReg(state, 0x72, 0x12); | |
| +	WriteReg(state, 0x73, 0x12); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000AutoTSClock_P(struct m88dc2800_state *state, u32 sym, | |
| +				  u16 qam) | |
| +{ | |
| +	u32 dataRate; | |
| +	u8 clk_div, value; | |
| +	printk(KERN_INFO | |
| +	       "m88dc2800: M88DC2000AutoTSClock_P, symrate=%d qam=%d\n", | |
| +	       sym, qam); | |
| +	switch (qam) { | |
| +	case 16: | |
| +		dataRate = 4; | |
| +		break; | |
| +	case 32: | |
| +		dataRate = 5; | |
| +		break; | |
| +	case 128: | |
| +		dataRate = 7; | |
| +		break; | |
| +	case 256: | |
| +		dataRate = 8; | |
| +		break; | |
| +	case 64: | |
| +	default: | |
| +		dataRate = 6; | |
| +		break; | |
| +	} | |
| +	dataRate *= sym * 105; | |
| +	dataRate /= 800; | |
| +	if (dataRate <= 4115) | |
| +		clk_div = 0x05; | |
| +	else if (dataRate <= 4800) | |
| +		clk_div = 0x04; | |
| +	else if (dataRate <= 5760) | |
| +		clk_div = 0x03; | |
| +	else if (dataRate <= 7200) | |
| +		clk_div = 0x02; | |
| +	else if (dataRate <= 9600) | |
| +		clk_div = 0x01; | |
| +	else | |
| +		clk_div = 0x00; | |
| +	value = ReadReg(state, 0xC2); | |
| +	value &= 0xc0; | |
| +	value |= clk_div; | |
| +	WriteReg(state, 0xC2, value); | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000AutoTSClock_C(struct m88dc2800_state *state, u32 sym, | |
| +				  u16 qam) | |
| +{ | |
| +	u32 dataRate; | |
| +	u8 clk_div, value; | |
| +	printk(KERN_INFO | |
| +	       "m88dc2800: M88DC2000AutoTSClock_C, symrate=%d qam=%d\n", | |
| +	       sym, qam); | |
| +	switch (qam) { | |
| +	case 16: | |
| +		dataRate = 4; | |
| +		break; | |
| +	case 32: | |
| +		dataRate = 5; | |
| +		break; | |
| +	case 128: | |
| +		dataRate = 7; | |
| +		break; | |
| +	case 256: | |
| +		dataRate = 8; | |
| +		break; | |
| +	case 64: | |
| +	default: | |
| +		dataRate = 6; | |
| +		break; | |
| +	} | |
| +	dataRate *= sym * 105; | |
| +	dataRate /= 800; | |
| +	if (dataRate <= 4115) | |
| +		clk_div = 0x3F; | |
| +	else if (dataRate <= 4800) | |
| +		clk_div = 0x36; | |
| +	else if (dataRate <= 5760) | |
| +		clk_div = 0x2D; | |
| +	else if (dataRate <= 7200) | |
| +		clk_div = 0x24; | |
| +	else if (dataRate <= 9600) | |
| +		clk_div = 0x1B; | |
| +	else | |
| +		clk_div = 0x12; | |
| +	value = ReadReg(state, 0xC2); | |
| +	value &= 0xc0; | |
| +	value |= clk_div; | |
| +	WriteReg(state, 0xC2, value); | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000SetTxMode(struct m88dc2800_state *state, u8 inverted, | |
| +			      u8 j83) | |
| +{ | |
| +	u8 value = 0; | |
| +	if (inverted) | |
| +		value |= 0x08;	/*	spectrum inverted	*/ | |
| +	if (j83) | |
| +		value |= 0x01;	/*	J83C			*/ | |
| +	WriteReg(state, 0x83, value); | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000SoftReset(struct m88dc2800_state *state) | |
| +{ | |
| +	WriteReg(state, 0x80, 0x01); | |
| +	WriteReg(state, 0x82, 0x00); | |
| +	msleep(1); | |
| +	WriteReg(state, 0x80, 0x00); | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000SetSym(struct m88dc2800_state *state, u32 sym, u32 xtal) | |
| +{ | |
| +	u8 value; | |
| +	u8 reg6FH, reg12H; | |
| +	u64 fValue; | |
| +	u32 dwValue; | |
| + | |
| +	printk(KERN_INFO "%s, sym=%d, xtal=%d\n", __func__, sym, xtal); | |
| +	fValue = 4294967296 * (sym + 10); | |
| +	do_div(fValue, xtal); | |
| + | |
| +	/* fValue  = 4294967296 * (sym + 10) / xtal; */ | |
| +	dwValue = (u32) fValue; | |
| +	printk(KERN_INFO "%s, fvalue1=%x\n", __func__, dwValue); | |
| +	WriteReg(state, 0x58, (u8) ((dwValue >> 24) & 0xff)); | |
| +	WriteReg(state, 0x57, (u8) ((dwValue >> 16) & 0xff)); | |
| +	WriteReg(state, 0x56, (u8) ((dwValue >> 8) & 0xff)); | |
| +	WriteReg(state, 0x55, (u8) ((dwValue >> 0) & 0xff)); | |
| + | |
| +	/* fValue = 2048 * xtal / sym; */ | |
| +	fValue = 2048 * xtal; | |
| +	do_div(fValue, sym); | |
| +	dwValue = (u32) fValue; | |
| +	printk(KERN_INFO "%s, fvalue2=%x\n", __func__, dwValue); | |
| +	WriteReg(state, 0x5D, (u8) ((dwValue >> 8) & 0xff)); | |
| +	WriteReg(state, 0x5C, (u8) ((dwValue >> 0) & 0xff)); | |
| +	value = ReadReg(state, 0x5A); | |
| +	if (((dwValue >> 16) & 0x0001) == 0) | |
| +		value &= 0x7F; | |
| +	else | |
| +		value |= 0x80; | |
| +	WriteReg(state, 0x5A, value); | |
| +	value = ReadReg(state, 0x89); | |
| +	if (sym <= 1800) | |
| +		value |= 0x01; | |
| +	else | |
| +		value &= 0xFE; | |
| +	WriteReg(state, 0x89, value); | |
| +	if (sym >= 6700) { | |
| +		reg6FH = 0x0D; | |
| +		reg12H = 0x30; | |
| +	} else if (sym >= 4000) { | |
| +		fValue = 22 * 4096 / sym; | |
| +		reg6FH = (u8) fValue; | |
| +		reg12H = 0x30; | |
| +	} else if (sym >= 2000) { | |
| +		fValue = 14 * 4096 / sym; | |
| +		reg6FH = (u8) fValue; | |
| +		reg12H = 0x20; | |
| +	} else { | |
| +		fValue = 7 * 4096 / sym; | |
| +		reg6FH = (u8) fValue; | |
| +		reg12H = 0x10; | |
| +	} | |
| +	WriteReg(state, 0x6F, reg6FH); | |
| +	WriteReg(state, 0x12, reg12H); | |
| +	if (((ReadReg(state, 0xE3) & 0x80) == 0x80) | |
| +	       && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { | |
| +		if (sym < 3000) { | |
| +			WriteReg(state, 0x6C, 0x16); | |
| +			WriteReg(state, 0x6D, 0x10); | |
| +			WriteReg(state, 0x6E, 0x18); | |
| +		} else { | |
| +			WriteReg(state, 0x6C, 0x14); | |
| +			WriteReg(state, 0x6D, 0x0E); | |
| +			WriteReg(state, 0x6E, 0x36); | |
| +		} | |
| +	} else { | |
| +		WriteReg(state, 0x6C, 0x16); | |
| +		WriteReg(state, 0x6D, 0x10); | |
| +		WriteReg(state, 0x6E, 0x18); | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000SetQAM(struct m88dc2800_state *state, u16 qam) | |
| +{ | |
| +	u8 reg00H, reg4AH, regC2H, reg44H, reg4CH, reg4DH, reg74H, value; | |
| +	u8 reg8BH, reg8EH; | |
| +	printk(KERN_INFO "%s, qam=%d\n", __func__, qam); | |
| +	regC2H = ReadReg(state, 0xC2); | |
| +	regC2H &= 0xF8; | |
| +	switch (qam) { | |
| +	case 16:		/* 16 QAM */ | |
| +		reg00H = 0x08; | |
| +		reg4AH = 0x0F; | |
| +		regC2H |= 0x02; | |
| +		reg44H = 0xAA; | |
| +		reg4CH = 0x0C; | |
| +		reg4DH = 0xF7; | |
| +		reg74H = 0x0E; | |
| +		if (((ReadReg(state, 0xE3) & 0x80) == 0x80) | |
| +		     && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { | |
| +			reg8BH = 0x5A; | |
| +			reg8EH = 0xBD; | |
| +		} else { | |
| +			reg8BH = 0x5B; | |
| +			reg8EH = 0x9D; | |
| +		} | |
| +		WriteReg(state, 0x6E, 0x18); | |
| +		break; | |
| +	case 32:		/* 32 QAM */ | |
| +		reg00H = 0x18; | |
| +		reg4AH = 0xFB; | |
| +		regC2H |= 0x02; | |
| +		reg44H = 0xAA; | |
| +		reg4CH = 0x0C; | |
| +		reg4DH = 0xF7; | |
| +		reg74H = 0x0E; | |
| +		if (((ReadReg(state, 0xE3) & 0x80) == 0x80) | |
| +		     && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { | |
| +			reg8BH = 0x5A; | |
| +			reg8EH = 0xBD; | |
| +		} else { | |
| +			reg8BH = 0x5B; | |
| +			reg8EH = 0x9D; | |
| +		} | |
| +		WriteReg(state, 0x6E, 0x18); | |
| +		break; | |
| +	case 64:		/* 64 QAM */ | |
| +		reg00H = 0x48; | |
| +		reg4AH = 0xCD; | |
| +		regC2H |= 0x02; | |
| +		reg44H = 0xAA; | |
| +		reg4CH = 0x0C; | |
| +		reg4DH = 0xF7; | |
| +		reg74H = 0x0E; | |
| +		if (((ReadReg(state, 0xE3) & 0x80) == 0x80) | |
| +		     && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { | |
| +			reg8BH = 0x5A; | |
| +			reg8EH = 0xBD; | |
| +		} else { | |
| +			reg8BH = 0x5B; | |
| +			reg8EH = 0x9D; | |
| +		} | |
| +		break; | |
| +	case 128:		/* 128 QAM */ | |
| +		reg00H = 0x28; | |
| +		reg4AH = 0xFF; | |
| +		regC2H |= 0x02; | |
| +		reg44H = 0xA9; | |
| +		reg4CH = 0x08; | |
| +		reg4DH = 0xF5; | |
| +		reg74H = 0x0E; | |
| +		reg8BH = 0x5B; | |
| +		reg8EH = 0x9D; | |
| +		break; | |
| +	case 256:		/* 256 QAM */ | |
| +		reg00H = 0x38; | |
| +		reg4AH = 0xCD; | |
| +		if (((ReadReg(state, 0xE3) & 0x80) == 0x80) | |
| +		     && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { | |
| +			regC2H |= 0x02; | |
| +		} else { | |
| +			regC2H |= 0x01; | |
| +		} | |
| +		reg44H = 0xA9; | |
| +		reg4CH = 0x08; | |
| +		reg4DH = 0xF5; | |
| +		reg74H = 0x0E; | |
| +		reg8BH = 0x5B; | |
| +		reg8EH = 0x9D; | |
| +		break; | |
| +	default:		/* 64 QAM */ | |
| +		reg00H = 0x48; | |
| +		reg4AH = 0xCD; | |
| +		regC2H |= 0x02; | |
| +		reg44H = 0xAA; | |
| +		reg4CH = 0x0C; | |
| +		reg4DH = 0xF7; | |
| +		reg74H = 0x0E; | |
| +		if (((ReadReg(state, 0xE3) & 0x80) == 0x80) | |
| +		     && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) { | |
| +			reg8BH = 0x5A; | |
| +			reg8EH = 0xBD; | |
| +		} else { | |
| +			reg8BH = 0x5B; | |
| +			reg8EH = 0x9D; | |
| +		} | |
| +		break; | |
| +	} | |
| +	WriteReg(state, 0x00, reg00H); | |
| +	value = ReadReg(state, 0x88); | |
| +	value |= 0x08; | |
| +	WriteReg(state, 0x88, value); | |
| +	WriteReg(state, 0x4B, 0xFF); | |
| +	WriteReg(state, 0x4A, reg4AH); | |
| +	value &= 0xF7; | |
| +	WriteReg(state, 0x88, value); | |
| +	WriteReg(state, 0xC2, regC2H); | |
| +	WriteReg(state, 0x44, reg44H); | |
| +	WriteReg(state, 0x4C, reg4CH); | |
| +	WriteReg(state, 0x4D, reg4DH); | |
| +	WriteReg(state, 0x74, reg74H); | |
| +	WriteReg(state, 0x8B, reg8BH); | |
| +	WriteReg(state, 0x8E, reg8EH); | |
| +	return 0; | |
| +} | |
| + | |
| +static int M88DC2000WriteTuner_TC2800(struct m88dc2800_state *state, | |
| +				      u32 freq_KHz) | |
| +{ | |
| +	printk(KERN_INFO "%s, freq=%d KHz\n", __func__, freq_KHz); | |
| +	return mt_fe_tn_set_freq_tc2800(state, freq_KHz); | |
| +} | |
| + | |
| +static int m88dc2800_init(struct dvb_frontend *fe) | |
| +{ | |
| +	dprintk("%s()\n", __func__); | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88dc2800_set_parameters(struct dvb_frontend *fe) | |
| +{ | |
| +	struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
| +	u8 is_annex_c, is_update; | |
| +	u16 temp_qam; | |
| +	s32 waiting_time; | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| + | |
| +	is_annex_c = c->delivery_system == SYS_DVBC_ANNEX_C ? 1 : 0; | |
| + | |
| +	switch (c->modulation) { | |
| +	case QAM_16: | |
| +		temp_qam = 16; | |
| +		break; | |
| +	case QAM_32: | |
| +		temp_qam = 32; | |
| +		break; | |
| +	case QAM_128: | |
| +		temp_qam = 128; | |
| +		break; | |
| +	case QAM_256: | |
| +		temp_qam = 256; | |
| +		break; | |
| +	default:		/* QAM_64 */ | |
| +		temp_qam = 64; | |
| +		break; | |
| +	} | |
| + | |
| +	state->inverted = c->inversion == INVERSION_ON ? 1 : 0; | |
| + | |
| +	printk(KERN_INFO | |
| +	     "m88dc2800: state, freq=%d qam=%d sym=%d inverted=%d xtal=%d\n", | |
| +	     state->freq, state->qam, state->sym, state->inverted, | |
| +	     state->xtal); | |
| +	printk(KERN_INFO | |
| +	     "m88dc2800: set frequency to %d qam=%d symrate=%d annex-c=%d\n", | |
| +	     c->frequency, temp_qam, c->symbol_rate, is_annex_c); | |
| + | |
| +	is_update = 0; | |
| +	WriteReg(state, 0x80, 0x01); | |
| +	if (c->frequency != state->freq) { | |
| +		M88DC2000WriteTuner_TC2800(state, c->frequency / 1000); | |
| +		state->freq = c->frequency; | |
| +	} | |
| +	if (c->symbol_rate != state->sym) { | |
| +		M88DC2000SetSym(state, c->symbol_rate / 1000, state->xtal); | |
| +		state->sym = c->symbol_rate; | |
| +		is_update = 1; | |
| +	} | |
| +	if (temp_qam != state->qam) { | |
| +		M88DC2000SetQAM(state, temp_qam); | |
| +		state->qam = temp_qam; | |
| +		is_update = 1; | |
| +	} | |
| + | |
| +	if (is_update != 0) { | |
| +		if (state->config->ts_mode == 3) | |
| +			M88DC2000AutoTSClock_C(state, state->sym / 1000, | |
| +					       temp_qam); | |
| +		else | |
| +			M88DC2000AutoTSClock_P(state, state->sym / 1000, | |
| +					       temp_qam); | |
| +	} | |
| + | |
| +	M88DC2000SetTxMode(state, state->inverted, is_annex_c); | |
| +	M88DC2000SoftReset(state); | |
| +	if (((ReadReg(state, 0xE3) & 0x80) == 0x80) | |
| +	    && ((ReadReg(state, 0xE4) & 0x80) == 0x80)) | |
| +		waiting_time = 800; | |
| +	else | |
| +		waiting_time = 500; | |
| +	while (waiting_time > 0) { | |
| +		msleep(50); | |
| +		waiting_time -= 50; | |
| +		if (M88DC2000GetLock(state)) | |
| +			return 0; | |
| +	} | |
| + | |
| +	state->inverted = (state->inverted != 0) ? 0 : 1; | |
| +	M88DC2000SetTxMode(state, state->inverted, is_annex_c); | |
| +	M88DC2000SoftReset(state); | |
| +	if (((ReadReg(state, 0xE3) & 0x80) == 0x80) && | |
| +	    ((ReadReg(state, 0xE4) & 0x80) == 0x80)) | |
| +		waiting_time = 800; | |
| +	else | |
| +		waiting_time = 500; | |
| +	while (waiting_time > 0) { | |
| +		msleep(50); | |
| +		waiting_time -= 50; | |
| +		if (M88DC2000GetLock(state)) | |
| +			return 0; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88dc2800_read_status(struct dvb_frontend *fe, | |
| +				 fe_status_t * status) | |
| +{ | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| +	*status = 0; | |
| + | |
| +	if (M88DC2000GetLock(state)) { | |
| +		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | |
| +		    |FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88dc2800_read_ber(struct dvb_frontend *fe, u32 * ber) | |
| +{ | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| +	u16 tmp; | |
| + | |
| +	if (M88DC2000GetLock(state) == 0) { | |
| +		state->ber = 0; | |
| +	} else if ((ReadReg(state, 0xA0) & 0x80) != 0x80) { | |
| +		tmp = ReadReg(state, 0xA2) << 8; | |
| +		tmp += ReadReg(state, 0xA1); | |
| +		state->ber = tmp; | |
| +		WriteReg(state, 0xA0, 0x05); | |
| +		WriteReg(state, 0xA0, 0x85); | |
| +	} | |
| +	*ber = state->ber; | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88dc2800_read_signal_strength(struct dvb_frontend *fe, | |
| +					  u16 * strength) | |
| +{ | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| +	s16 tuner_strength; | |
| + | |
| +	tuner_strength = mt_fe_tn_get_signal_strength_tc2800(state); | |
| +	*strength = tuner_strength < -107 ? 0 : tuner_strength + 107; | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88dc2800_read_snr(struct dvb_frontend *fe, u16 * snr) | |
| +{ | |
| +	static const u32 mes_log[] = { | |
| +		0, 3010, 4771, 6021, 6990, 7781, 8451, 9031, 9542, 10000, | |
| +		10414, 10792, 11139, 11461, 11761, 12041, 12304, 12553, 12788, | |
| +		13010, 13222, 13424, 13617, 13802, 13979, 14150, 14314, 14472, | |
| +		14624, 14771, 14914, 15052, 15185, 15315, 15441, 15563, 15682, | |
| +		15798, 15911, 16021, 16128, 16232, 16335, 16435, 16532, 16628, | |
| +		16721, 16812, 16902, 16990, 17076, 17160, 17243, 17324, 17404, | |
| +		17482, 17559, 17634, 17709, 17782, 17853, 17924, 17993, 18062, | |
| +		18129, 18195, 18261, 18325, 18388, 18451, 18513, 18573, 18633, | |
| +		18692, 18751, 18808, 18865, 18921, 18976, 19031 | |
| +	}; | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| +	u8 i; | |
| +	u32 _snr, mse; | |
| + | |
| +	if ((ReadReg(state, 0x91) & 0x23) != 0x03) { | |
| +		*snr = 0; | |
| +		return 0; | |
| +	} | |
| +	mse = 0; | |
| +	for (i = 0; i < 30; i++) { | |
| +		mse += (ReadReg(state, 0x08) << 8) + ReadReg(state, 0x07); | |
| +	} | |
| +	mse /= 30; | |
| +	if (mse > 80) | |
| +		mse = 80; | |
| +	switch (state->qam) { | |
| +	case 16: | |
| +		_snr = 34080; | |
| +		break;		/*      16QAM                           */ | |
| +	case 32: | |
| +		_snr = 37600; | |
| +		break;		/*      32QAM                           */ | |
| +	case 64: | |
| +		_snr = 40310; | |
| +		break;		/*      64QAM                           */ | |
| +	case 128: | |
| +		_snr = 43720; | |
| +		break;		/*      128QAM                          */ | |
| +	case 256: | |
| +		_snr = 46390; | |
| +		break;		/*      256QAM                          */ | |
| +	default: | |
| +		_snr = 40310; | |
| +		break; | |
| +	} | |
| +	_snr -= mes_log[mse - 1];	/*      C - 10*log10(MSE)       */ | |
| +	_snr /= 1000; | |
| +	if (_snr > 0xff) | |
| +		_snr = 0xff; | |
| +	*snr = _snr; | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88dc2800_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) | |
| +{ | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| +	u8 u8Value; | |
| + | |
| +	u8Value = ReadReg(state, 0xdf); | |
| +	u8Value |= 0x02;	/* Hold */ | |
| +	WriteReg(state, 0xdf, u8Value); | |
| + | |
| +	*ucblocks = ReadReg(state, 0xd5); | |
| +	*ucblocks = (*ucblocks << 8) | ReadReg(state, 0xd4); | |
| + | |
| +	u8Value &= 0xfe;	/* Clear */ | |
| +	WriteReg(state, 0xdf, u8Value); | |
| +	u8Value &= 0xfc;	/* Update */ | |
| +	u8Value |= 0x01; | |
| +	WriteReg(state, 0xdf, u8Value); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88dc2800_sleep(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| + | |
| +	mt_fe_tn_sleep_tc2800(state); | |
| +	state->freq = 0; | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static void m88dc2800_release(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88dc2800_state *state = fe->demodulator_priv; | |
| +	kfree(state); | |
| +} | |
| + | |
| +static struct dvb_frontend_ops m88dc2800_ops; | |
| + | |
| +struct dvb_frontend *m88dc2800_attach(const struct m88dc2800_config | |
| +				      *config, struct i2c_adapter *i2c) | |
| +{ | |
| +	struct m88dc2800_state *state = NULL; | |
| + | |
| +	/* allocate memory for the internal state */ | |
| +	state = kzalloc(sizeof(struct m88dc2800_state), GFP_KERNEL); | |
| +	if (state == NULL) | |
| +		goto error; | |
| + | |
| +	/* setup the state */ | |
| +	state->config = config; | |
| +	state->i2c = i2c; | |
| +	state->xtal = 28800; | |
| + | |
| +	WriteReg(state, 0x80, 0x01); | |
| +	M88DC2000RegInitial_TC2800(state); | |
| +	M88DC2000SetTsType(state, state->config->ts_mode); | |
| +	mt_fe_tn_init_tc2800(state); | |
| + | |
| +	/* create dvb_frontend */ | |
| +	memcpy(&state->frontend.ops, &m88dc2800_ops, | |
| +	       sizeof(struct dvb_frontend_ops)); | |
| +	state->frontend.demodulator_priv = state; | |
| +	return &state->frontend; | |
| + | |
| +      error: | |
| +	kfree(state); | |
| +	return NULL; | |
| +} | |
| + | |
| +EXPORT_SYMBOL(m88dc2800_attach); | |
| + | |
| +static struct dvb_frontend_ops m88dc2800_ops = { | |
| +	.delsys = {SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C}, | |
| +	.info = { | |
| +		 .name = "Montage M88DC2800 DVB-C", | |
| +		 .frequency_stepsize = 62500, | |
| +		 .frequency_min = 48000000, | |
| +		 .frequency_max = 870000000, | |
| +		 .symbol_rate_min = 870000, | |
| +		 .symbol_rate_max = 9000000, | |
| +		 .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | | |
| +			 FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_FEC_AUTO | |
| +	}, | |
| +	.release = m88dc2800_release, | |
| +	.init = m88dc2800_init, | |
| +	.sleep = m88dc2800_sleep, | |
| +	.set_frontend = m88dc2800_set_parameters, | |
| +	.read_status = m88dc2800_read_status, | |
| +	.read_ber = m88dc2800_read_ber, | |
| +	.read_signal_strength = m88dc2800_read_signal_strength, | |
| +	.read_snr = m88dc2800_read_snr, | |
| +	.read_ucblocks = m88dc2800_read_ucblocks, | |
| +}; | |
| + | |
| +MODULE_DESCRIPTION("Montage DVB-C demodulator driver"); | |
| +MODULE_AUTHOR("Max Nibble <nibble.max@gmail.com>"); | |
| +MODULE_LICENSE("GPL"); | |
| +MODULE_VERSION("1.00"); | |
| diff -urN a/drivers/media/dvb-frontends/m88dc2800.h b/drivers/media/dvb-frontends/m88dc2800.h | |
| --- a/drivers/media/dvb-frontends/m88dc2800.h	1970-01-01 08:00:00.000000000 +0800 | |
| +++ b/drivers/media/dvb-frontends/m88dc2800.h	2013-01-26 14:57:32.000000000 +0800 | |
| @@ -0,0 +1,43 @@ | |
| +/* | |
| +    M88DC2800/M88TC2800  - DVB-C demodulator and tuner from Montage | |
| + | |
| +    Copyright (C) 2012 Max Nibble <nibble.max@gmail.com> | |
| +    Copyright (C) 2011 Montage Technology - www.montage-tech.com | |
| + | |
| +    This program is free software; you can redistribute it and/or modify | |
| +    it under the terms of the GNU General Public License as published by | |
| +    the Free Software Foundation; either version 2 of the License, or | |
| +    (at your option) any later version. | |
| + | |
| +    This program is distributed in the hope that it will be useful, | |
| +    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| +    GNU General Public License for more details. | |
| + | |
| +    You should have received a copy of the GNU General Public License | |
| +    along with this program; if not, write to the Free Software | |
| +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| +*/ | |
| + | |
| +#ifndef M88DC2800_H | |
| +#define M88DC2800_H | |
| + | |
| +#include <linux/dvb/frontend.h> | |
| + | |
| +struct m88dc2800_config { | |
| +	u8 demod_address; | |
| +	u8 ts_mode; | |
| +}; | |
| + | |
| +#if defined(CONFIG_DVB_M88DC2800) || (defined(CONFIG_DVB_M88DC2800_MODULE) && defined(MODULE)) | |
| +extern struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config, | |
| +					    struct i2c_adapter* i2c); | |
| +#else | |
| +static inline struct dvb_frontend* m88dc2800_attach(const struct m88dc2800_config* config, | |
| +					    struct i2c_adapter* i2c) | |
| +{ | |
| +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | |
| +	return NULL; | |
| +} | |
| +#endif /* CONFIG_DVB_M88DC2800 */ | |
| +#endif /* M88DC2800_H */ | |
| diff -urN a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c | |
| --- a/drivers/media/dvb-frontends/m88ds3103.c	1970-01-01 08:00:00.000000000 +0800 | |
| +++ b/drivers/media/dvb-frontends/m88ds3103.c	2013-01-30 12:33:47.000000000 +0800 | |
| @@ -0,0 +1,1710 @@ | |
| +/* | |
| +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver | |
| + | |
| +    Copyright (C) 2011 Max nibble<nibble.max@gmail.com> | |
| +    Copyright (C) 2010 Montage Technology<www.montage-tech.com> | |
| +    Copyright (C) 2009 Konstantin Dimitrov. | |
| + | |
| +    This program is free software; you can redistribute it and/or modify | |
| +    it under the terms of the GNU General Public License as published by | |
| +    the Free Software Foundation; either version 2 of the License, or | |
| +    (at your option) any later version. | |
| + | |
| +    This program is distributed in the hope that it will be useful, | |
| +    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| +    GNU General Public License for more details. | |
| + | |
| +    You should have received a copy of the GNU General Public License | |
| +    along with this program; if not, write to the Free Software | |
| +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| + */ | |
| + | |
| +#include <linux/slab.h> | |
| +#include <linux/kernel.h> | |
| +#include <linux/module.h> | |
| +#include <linux/moduleparam.h> | |
| +#include <linux/init.h> | |
| +#include <linux/firmware.h> | |
| + | |
| +#include "dvb_frontend.h" | |
| +#include "m88ds3103.h" | |
| +#include "m88ds3103_priv.h" | |
| + | |
| +static int debug; | |
| +module_param(debug, int, 0644); | |
| +MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); | |
| + | |
| +#define dprintk(args...) \ | |
| +	do { \ | |
| +		if (debug) \ | |
| +			printk(KERN_INFO "m88ds3103: " args); \ | |
| +	} while (0) | |
| + | |
| +/*demod register operations.*/ | |
| +static int m88ds3103_writereg(struct m88ds3103_state *state, int reg, int data) | |
| +{ | |
| +	u8 buf[] = { reg, data }; | |
| +	struct i2c_msg msg = { .addr = state->config->demod_address, | |
| +		.flags = 0, .buf = buf, .len = 2 }; | |
| +	int err; | |
| + | |
| +	if (debug > 1) | |
| +		printk("m88ds3103: %s: write reg 0x%02x, value 0x%02x\n", | |
| +			__func__, reg, data); | |
| + | |
| +	err = i2c_transfer(state->i2c, &msg, 1); | |
| +	if (err != 1) { | |
| +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," | |
| +			 " value == 0x%02x)\n", __func__, err, reg, data); | |
| +		return -EREMOTEIO; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_readreg(struct m88ds3103_state *state, u8 reg) | |
| +{ | |
| +	int ret; | |
| +	u8 b0[] = { reg }; | |
| +	u8 b1[] = { 0 }; | |
| +	struct i2c_msg msg[] = { | |
| +		{ .addr = state->config->demod_address, .flags = 0, | |
| +			.buf = b0, .len = 1 }, | |
| +		{ .addr = state->config->demod_address, .flags = I2C_M_RD, | |
| +			.buf = b1, .len = 1 } | |
| +	}; | |
| +	ret = i2c_transfer(state->i2c, msg, 2); | |
| + | |
| +	if (ret != 2) { | |
| +		printk(KERN_ERR "%s: reg=0x%x (error=%d)\n", | |
| +			__func__, reg, ret); | |
| +		return ret; | |
| +	} | |
| + | |
| +	if (debug > 1) | |
| +		printk(KERN_INFO "m88ds3103: read reg 0x%02x, value 0x%02x\n", | |
| +			reg, b1[0]); | |
| + | |
| +	return b1[0]; | |
| +} | |
| + | |
| +/*tuner register operations.*/ | |
| +static int m88ds3103_tuner_writereg(struct m88ds3103_state *state, int reg, int data) | |
| +{ | |
| +	u8 buf[] = { reg, data }; | |
| +	struct i2c_msg msg = { .addr = 0x60, | |
| +		.flags = 0, .buf = buf, .len = 2 }; | |
| +	int err; | |
| + | |
| +	m88ds3103_writereg(state, 0x03, 0x11); | |
| +	err = i2c_transfer(state->i2c, &msg, 1); | |
| +	 | |
| +	if (err != 1) { | |
| +		printk("%s: writereg error(err == %i, reg == 0x%02x," | |
| +			 " value == 0x%02x)\n", __func__, err, reg, data); | |
| +		return -EREMOTEIO; | |
| +	} | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_tuner_readreg(struct m88ds3103_state *state, u8 reg) | |
| +{ | |
| +	int ret; | |
| +	u8 b0[] = { reg }; | |
| +	u8 b1[] = { 0 }; | |
| +	struct i2c_msg msg[] = { | |
| +		{ .addr = 0x60, .flags = 0, | |
| +			.buf = b0, .len = 1 }, | |
| +		{ .addr = 0x60, .flags = I2C_M_RD, | |
| +			.buf = b1, .len = 1 } | |
| +	}; | |
| + | |
| +	m88ds3103_writereg(state, 0x03, 0x11);	 | |
| +	ret = i2c_transfer(state->i2c, msg, 2); | |
| + | |
| +	if (ret != 2) { | |
| +		printk(KERN_ERR "%s: reg=0x%x(error=%d)\n", __func__, reg, ret); | |
| +		return ret; | |
| +	} | |
| + | |
| +	return b1[0]; | |
| +} | |
| + | |
| +/* Bulk demod I2C write, for firmware download. */ | |
| +static int m88ds3103_writeregN(struct m88ds3103_state *state, int reg, | |
| +				const u8 *data, u16 len) | |
| +{ | |
| +	int ret = -EREMOTEIO; | |
| +	struct i2c_msg msg; | |
| +	u8 *buf; | |
| + | |
| +	buf = kmalloc(len + 1, GFP_KERNEL); | |
| +	if (buf == NULL) { | |
| +		printk("Unable to kmalloc\n"); | |
| +		ret = -ENOMEM; | |
| +		goto error; | |
| +	} | |
| + | |
| +	*(buf) = reg; | |
| +	memcpy(buf + 1, data, len); | |
| + | |
| +	msg.addr = state->config->demod_address; | |
| +	msg.flags = 0; | |
| +	msg.buf = buf; | |
| +	msg.len = len + 1; | |
| + | |
| +	if (debug > 1) | |
| +		printk(KERN_INFO "m88ds3103: %s:  write regN 0x%02x, len = %d\n", | |
| +			__func__, reg, len); | |
| + | |
| +	ret = i2c_transfer(state->i2c, &msg, 1); | |
| +	if (ret != 1) { | |
| +		printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x\n", | |
| +			 __func__, ret, reg); | |
| +		ret = -EREMOTEIO; | |
| +	} | |
| +	 | |
| +error: | |
| +	kfree(buf); | |
| + | |
| +	return ret; | |
| +} | |
| + | |
| +static int m88ds3103_load_firmware(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	const struct firmware *fw; | |
| +	int i, ret = 0; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| +		 | |
| +	if (state->skip_fw_load) | |
| +		return 0; | |
| +	/* Load firmware */ | |
| +	/* request the firmware, this will block until someone uploads it */	 | |
| +	if(state->demod_id == DS3000_ID){ | |
| +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, | |
| +				DS3000_DEFAULT_FIRMWARE);		 | |
| +		ret = request_firmware(&fw, DS3000_DEFAULT_FIRMWARE, | |
| +					state->i2c->dev.parent); | |
| +	}else if(state->demod_id == DS3103_ID){ | |
| +		printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, | |
| +				DS3103_DEFAULT_FIRMWARE); | |
| +		ret = request_firmware(&fw, DS3103_DEFAULT_FIRMWARE, | |
| +					state->i2c->dev.parent); | |
| +	} | |
| +	 | |
| +	printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); | |
| +	if (ret) { | |
| +		printk(KERN_ERR "%s: No firmware uploaded (timeout or file not " | |
| +				"found?)\n", __func__); | |
| +		return ret; | |
| +	} | |
| + | |
| +	/* Make sure we don't recurse back through here during loading */ | |
| +	state->skip_fw_load = 1; | |
| + | |
| +	dprintk("Firmware is %zu bytes (%02x %02x .. %02x %02x)\n", | |
| +			fw->size, | |
| +			fw->data[0], | |
| +			fw->data[1], | |
| +			fw->data[fw->size - 2], | |
| +			fw->data[fw->size - 1]); | |
| +			 | |
| +	/* stop internal mcu. */ | |
| +	m88ds3103_writereg(state, 0xb2, 0x01); | |
| +	/* split firmware to download.*/ | |
| +	for(i = 0; i < FW_DOWN_LOOP; i++){ | |
| +		ret = m88ds3103_writeregN(state, 0xb0, &(fw->data[FW_DOWN_SIZE*i]), FW_DOWN_SIZE); | |
| +		if(ret != 1) break;		 | |
| +	} | |
| +	/* start internal mcu. */ | |
| +	if(ret == 1) | |
| +		m88ds3103_writereg(state, 0xb2, 0x00); | |
| +		 | |
| +	release_firmware(fw); | |
| + | |
| +	dprintk("%s: Firmware upload %s\n", __func__, | |
| +			ret == 1 ? "complete" : "failed"); | |
| + | |
| +	if(ret == 1) ret = 0; | |
| +	 | |
| +	/* Ensure firmware is always loaded if required */ | |
| +	state->skip_fw_load = 0; | |
| + | |
| +	return ret; | |
| +} | |
| + | |
| + | |
| +static int m88ds3103_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8 data; | |
| + | |
| +	dprintk("%s(%d)\n", __func__, voltage); | |
| + | |
| +	dprintk("m88ds3103:pin_ctrl = (%02x)\n", state->config->pin_ctrl); | |
| +	 | |
| +	if(state->config->set_voltage) | |
| +		state->config->set_voltage(fe, voltage); | |
| +	 | |
| +	data = m88ds3103_readreg(state, 0xa2); | |
| +	 | |
| +        if(state->config->pin_ctrl & 0x80){ /*If control pin is assigned.*/ | |
| +	        data &= ~0x03; /* bit0 V/H, bit1 off/on */ | |
| +	        if(state->config->pin_ctrl & 0x02) | |
| +		     data |= 0x02; | |
| + | |
| +	        switch (voltage) { | |
| +	        case SEC_VOLTAGE_18: | |
| +		     if((state->config->pin_ctrl & 0x01) == 0) | |
| +			  data |= 0x01; | |
| +		     break; | |
| +	        case SEC_VOLTAGE_13: | |
| +		     if(state->config->pin_ctrl & 0x01) | |
| +			  data |= 0x01; | |
| +		     break; | |
| +	        case SEC_VOLTAGE_OFF: | |
| +		     if(state->config->pin_ctrl & 0x02) | |
| +			   data &= ~0x02;			 | |
| +		     else | |
| +			   data |= 0x02; | |
| +		     break; | |
| +	         } | |
| +        } | |
| + | |
| +	m88ds3103_writereg(state, 0xa2, data); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t* status) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	int lock = 0; | |
| +	 | |
| +	*status = 0; | |
| +	 | |
| +	switch (state->delivery_system){ | |
| +	case SYS_DVBS: | |
| +		lock = m88ds3103_readreg(state, 0xd1); | |
| +		dprintk("%s: SYS_DVBS status=%x.\n", __func__, lock); | |
| +		 | |
| +		if ((lock & 0x07) == 0x07){ | |
| +			/*if((m88ds3103_readreg(state, 0x0d) & 0x07) == 0x07)*/ | |
| +				*status = FE_HAS_SIGNAL | FE_HAS_CARRIER  | |
| +					| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | |
| +			 | |
| +		} | |
| +		break; | |
| +	case SYS_DVBS2: | |
| +		lock = m88ds3103_readreg(state, 0x0d); | |
| +		dprintk("%s: SYS_DVBS2 status=%x.\n", __func__, lock); | |
| + | |
| +		if ((lock & 0x8f) == 0x8f) | |
| +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER  | |
| +				| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | |
| +			 | |
| +		break; | |
| +	default: | |
| +		break; | |
| +	} | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_read_ber(struct dvb_frontend *fe, u32* ber) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8 tmp1, tmp2, tmp3; | |
| +	u32 ldpc_frame_cnt, pre_err_packags, code_rate_fac = 0; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| + | |
| +	switch (state->delivery_system) { | |
| +	case SYS_DVBS: | |
| +		m88ds3103_writereg(state, 0xf9, 0x04); | |
| +		tmp3 = m88ds3103_readreg(state, 0xf8); | |
| +		if ((tmp3&0x10) == 0){ | |
| +			tmp1 = m88ds3103_readreg(state, 0xf7); | |
| +			tmp2 = m88ds3103_readreg(state, 0xf6); | |
| +			tmp3 |= 0x10; | |
| +			m88ds3103_writereg(state, 0xf8, tmp3); | |
| +			state->preBer = (tmp1<<8) | tmp2; | |
| +		} | |
| +		break; | |
| +	case SYS_DVBS2: | |
| +		tmp1 = m88ds3103_readreg(state, 0x7e) & 0x0f; | |
| +		switch(tmp1){ | |
| +		case 0:	code_rate_fac = 16008 - 80; break; | |
| +		case 1:	code_rate_fac = 21408 - 80; break; | |
| +		case 2:	code_rate_fac = 25728 - 80; break; | |
| +		case 3:	code_rate_fac = 32208 - 80; break; | |
| +		case 4:	code_rate_fac = 38688 - 80; break; | |
| +		case 5:	code_rate_fac = 43040 - 80; break; | |
| +		case 6:	code_rate_fac = 48408 - 80; break; | |
| +		case 7:	code_rate_fac = 51648 - 80; break; | |
| +		case 8:	code_rate_fac = 53840 - 80; break; | |
| +		case 9:	code_rate_fac = 57472 - 80; break; | |
| +		case 10: code_rate_fac = 58192 - 80; break; | |
| +		} | |
| +		 | |
| +		tmp1 = m88ds3103_readreg(state, 0xd7) & 0xff; | |
| +		tmp2 = m88ds3103_readreg(state, 0xd6) & 0xff; | |
| +		tmp3 = m88ds3103_readreg(state, 0xd5) & 0xff;		 | |
| +		ldpc_frame_cnt = (tmp1 << 16) | (tmp2 << 8) | tmp3; | |
| + | |
| +		tmp1 = m88ds3103_readreg(state, 0xf8) & 0xff; | |
| +		tmp2 = m88ds3103_readreg(state, 0xf7) & 0xff; | |
| +		pre_err_packags = tmp1<<8 | tmp2; | |
| +		 | |
| +		if (ldpc_frame_cnt > 1000){ | |
| +			m88ds3103_writereg(state, 0xd1, 0x01); | |
| +			m88ds3103_writereg(state, 0xf9, 0x01); | |
| +			m88ds3103_writereg(state, 0xf9, 0x00); | |
| +			m88ds3103_writereg(state, 0xd1, 0x00); | |
| +			state->preBer = pre_err_packags; | |
| +		} 				 | |
| +		break; | |
| +	default: | |
| +		break; | |
| +	} | |
| +	*ber = state->preBer; | |
| +	 | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_read_signal_strength(struct dvb_frontend *fe, | |
| +						u16 *signal_strength) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u16 gain; | |
| +	u8 gain1, gain2, gain3 = 0; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| + | |
| +	gain1 = m88ds3103_tuner_readreg(state, 0x3d) & 0x1f; | |
| +	dprintk("%s: gain1 = 0x%02x \n", __func__, gain1); | |
| +	 | |
| +	if (gain1 > 15) gain1 = 15; | |
| +	gain2 = m88ds3103_tuner_readreg(state, 0x21) & 0x1f; | |
| +	dprintk("%s: gain2 = 0x%02x \n", __func__, gain2); | |
| +	 | |
| +	if(state->tuner_id == TS2022_ID){ | |
| +		gain3 = (m88ds3103_tuner_readreg(state, 0x66)>>3) & 0x07; | |
| +		dprintk("%s: gain3 = 0x%02x \n", __func__, gain3); | |
| +		 | |
| +		if (gain2 > 16) gain2 = 16; | |
| +		if (gain2 < 2) gain2 = 2;			 | |
| +		if (gain3 > 6) gain3 = 6; | |
| +	}else{ | |
| +		if (gain2 > 13) gain2 = 13; | |
| +		gain3 = 0; | |
| +	} | |
| + | |
| +	gain = gain1*23 + gain2*35 + gain3*29; | |
| +	*signal_strength = 60000 - gain*55; | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| + | |
| +static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *p_snr) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8 val, npow1, npow2, spow1, cnt; | |
| +	u16 tmp, snr; | |
| +	u32 npow, spow, snr_total;	 | |
| +	static const u16 mes_log10[] ={ | |
| +		0,	3010,	4771,	6021, 	6990,	7781,	8451,	9031,	9542,	10000, | |
| +		10414,	10792,	11139,	11461,	11761,	12041,	12304,	12553,	12788,	13010, | |
| +		13222,	13424,	13617,	13802,	13979,	14150,	14314,	14472,	14624,	14771, | |
| +		14914,	15052,	15185,	15315,	15441,	15563,	15682,	15798,	15911,	16021, | |
| +		16128,	16232,	16335,	16435,	16532,	16628,	16721,	16812,	16902,	16990, | |
| +		17076,	17160,	17243,	17324,	17404,	17482,	17559,	17634,	17709,	17782, | |
| +		17853,	17924,	17993,	18062,	18129,	18195,	18261,	18325,	18388,	18451, | |
| +		18513,	18573,	18633,	18692,	18751,	18808,	18865,	18921,	18976,	19031 | |
| +	}; | |
| +	static const u16 mes_loge[] ={ | |
| +		0,	6931,	10986,	13863, 	16094,	17918,	19459,	20794,	21972,	23026, | |
| +		23979,	24849,	25649,	26391,	27081,	27726,	28332,	28904,	29444,	29957, | |
| +		30445,	30910,	31355,	31781,	32189,	32581,	32958,	33322,	33673,	34012, | |
| +		34340,	34657, | |
| +	}; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| + | |
| +	snr = 0; | |
| +	 | |
| +	switch (state->delivery_system){ | |
| +	case SYS_DVBS: | |
| +		cnt = 10; snr_total = 0; | |
| +		while(cnt > 0){ | |
| +			val = m88ds3103_readreg(state, 0xff); | |
| +			snr_total += val; | |
| +			cnt--; | |
| +		} | |
| +		tmp = (u16)(snr_total/80); | |
| +		if(tmp > 0){ | |
| +			if (tmp > 32) tmp = 32; | |
| +			snr = (mes_loge[tmp - 1] * 100) / 45; | |
| +		}else{ | |
| +			snr = 0; | |
| +		} | |
| +		break; | |
| +	case SYS_DVBS2: | |
| +		cnt  = 10; npow = 0; spow = 0; | |
| +		while(cnt >0){ | |
| +			npow1 = m88ds3103_readreg(state, 0x8c) & 0xff; | |
| +			npow2 = m88ds3103_readreg(state, 0x8d) & 0xff; | |
| +			npow += (((npow1 & 0x3f) + (u16)(npow2 << 6)) >> 2); | |
| + | |
| +			spow1 = m88ds3103_readreg(state, 0x8e) & 0xff; | |
| +			spow += ((spow1 * spow1) >> 1); | |
| +			cnt--; | |
| +		} | |
| +		npow /= 10; spow /= 10; | |
| +		if(spow == 0){ | |
| +			snr = 0; | |
| +		}else if(npow == 0){ | |
| +			snr = 19; | |
| +		}else{ | |
| +			if(spow > npow){ | |
| +				tmp = (u16)(spow / npow); | |
| +				if (tmp > 80) tmp = 80; | |
| +				snr = mes_log10[tmp - 1]*3; | |
| +			}else{ | |
| +				tmp = (u16)(npow / spow); | |
| +				if (tmp > 80) tmp = 80; | |
| +				snr = -(mes_log10[tmp - 1] / 1000); | |
| +			} | |
| +		}			 | |
| +		break; | |
| +	default: | |
| +		break; | |
| +	} | |
| +	*p_snr = snr; | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| + | |
| +static int m88ds3103_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8 tmp1, tmp2, tmp3, data; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| + | |
| +	switch (state->delivery_system) { | |
| +	case SYS_DVBS: | |
| +		data = m88ds3103_readreg(state, 0xf8); | |
| +		data |= 0x40; | |
| +		m88ds3103_writereg(state, 0xf8, data);		 | |
| +		tmp1 = m88ds3103_readreg(state, 0xf5); | |
| +		tmp2 = m88ds3103_readreg(state, 0xf4); | |
| +		*ucblocks = (tmp1 <<8) | tmp2;		 | |
| +		data &= ~0x20; | |
| +		m88ds3103_writereg(state, 0xf8, data); | |
| +		data |= 0x20; | |
| +		m88ds3103_writereg(state, 0xf8, data); | |
| +		data &= ~0x40; | |
| +		m88ds3103_writereg(state, 0xf8, data); | |
| +		break; | |
| +	case SYS_DVBS2: | |
| +		tmp1 = m88ds3103_readreg(state, 0xda); | |
| +		tmp2 = m88ds3103_readreg(state, 0xd9); | |
| +		tmp3 = m88ds3103_readreg(state, 0xd8); | |
| +		*ucblocks = (tmp1 <<16)|(tmp2 <<8)|tmp3; | |
| +		data = m88ds3103_readreg(state, 0xd1); | |
| +		data |= 0x01; | |
| +		m88ds3103_writereg(state, 0xd1, data); | |
| +		data &= ~0x01; | |
| +		m88ds3103_writereg(state, 0xd1, data); | |
| +		break; | |
| +	default: | |
| +		break; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8 data_a1, data_a2; | |
| + | |
| +	dprintk("%s(%d)\n", __func__, tone); | |
| +	if ((tone != SEC_TONE_ON) && (tone != SEC_TONE_OFF)) { | |
| +		printk(KERN_ERR "%s: Invalid, tone=%d\n", __func__, tone); | |
| +		return -EINVAL; | |
| +	} | |
| + | |
| +	data_a1 = m88ds3103_readreg(state, 0xa1); | |
| +	data_a2 = m88ds3103_readreg(state, 0xa2); | |
| +	if(state->demod_id == DS3103_ID) | |
| +		data_a2 &= 0xdf; /* Normal mode */ | |
| +	switch (tone) { | |
| +	case SEC_TONE_ON: | |
| +		dprintk("%s: SEC_TONE_ON\n", __func__); | |
| +		data_a1 |= 0x04; | |
| +		data_a1 &= ~0x03; | |
| +		data_a1 &= ~0x40; | |
| +		data_a2 &= ~0xc0; | |
| +		break; | |
| +	case SEC_TONE_OFF: | |
| +		dprintk("%s: SEC_TONE_OFF\n", __func__); | |
| +		data_a2 &= ~0xc0; | |
| +		data_a2 |= 0x80; | |
| +		break; | |
| +	} | |
| +	m88ds3103_writereg(state, 0xa2, data_a2); | |
| +	m88ds3103_writereg(state, 0xa1, data_a1); | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_send_diseqc_msg(struct dvb_frontend *fe, | |
| +				struct dvb_diseqc_master_cmd *d) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	int i, ret = 0; | |
| +	u8 tmp, time_out; | |
| + | |
| +	/* Dump DiSEqC message */ | |
| +	if (debug) { | |
| +		printk(KERN_INFO "m88ds3103: %s(", __func__); | |
| +		for (i = 0 ; i < d->msg_len ;) { | |
| +			printk(KERN_INFO "0x%02x", d->msg[i]); | |
| +			if (++i < d->msg_len) | |
| +				printk(KERN_INFO ", "); | |
| +		} | |
| +	} | |
| + | |
| +	tmp = m88ds3103_readreg(state, 0xa2); | |
| +	tmp &= ~0xc0; | |
| +	if(state->demod_id == DS3103_ID) | |
| +		tmp &= ~0x20; | |
| +	m88ds3103_writereg(state, 0xa2, tmp); | |
| +	 | |
| +	for (i = 0; i < d->msg_len; i ++) | |
| +		m88ds3103_writereg(state, (0xa3+i), d->msg[i]); | |
| + | |
| +	tmp = m88ds3103_readreg(state, 0xa1);	 | |
| +	tmp &= ~0x38; | |
| +	tmp &= ~0x40; | |
| +	tmp |= ((d->msg_len-1) << 3) | 0x07; | |
| +	tmp &= ~0x80; | |
| +	m88ds3103_writereg(state, 0xa1, tmp); | |
| +	/*	1.5 * 9 * 8	= 108ms	*/ | |
| +	time_out = 150; | |
| +	while (time_out > 0){ | |
| +		msleep(10); | |
| +		time_out -= 10; | |
| +		tmp = m88ds3103_readreg(state, 0xa1);		 | |
| +		if ((tmp & 0x40) == 0) | |
| +			break; | |
| +	} | |
| +	if (time_out == 0){ | |
| +		tmp = m88ds3103_readreg(state, 0xa1); | |
| +		tmp &= ~0x80; | |
| +		tmp |= 0x40; | |
| +		m88ds3103_writereg(state, 0xa1, tmp); | |
| +		ret = 1; | |
| +	} | |
| +	tmp = m88ds3103_readreg(state, 0xa2); | |
| +	tmp &= ~0xc0; | |
| +	tmp |= 0x80; | |
| +	m88ds3103_writereg(state, 0xa2, tmp);	 | |
| +	return ret; | |
| +} | |
| + | |
| + | |
| +static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, | |
| +					fe_sec_mini_cmd_t burst) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8	val, time_out; | |
| +	 | |
| +	dprintk("%s()\n", __func__); | |
| + | |
| +	val = m88ds3103_readreg(state, 0xa2); | |
| +	val &= ~0xc0; | |
| +	if(state->demod_id == DS3103_ID) | |
| +		val &= 0xdf; /* Normal mode */ | |
| +	m88ds3103_writereg(state, 0xa2, val); | |
| +	/* DiSEqC burst */ | |
| +	if (burst == SEC_MINI_B) | |
| +		m88ds3103_writereg(state, 0xa1, 0x01); | |
| +	else | |
| +		m88ds3103_writereg(state, 0xa1, 0x02); | |
| + | |
| +	msleep(13); | |
| + | |
| +	time_out = 5; | |
| +	do{ | |
| +		val = m88ds3103_readreg(state, 0xa1); | |
| +		if ((val & 0x40) == 0) | |
| +			break; | |
| +		msleep(1); | |
| +		time_out --; | |
| +	} while (time_out > 0); | |
| + | |
| +	val = m88ds3103_readreg(state, 0xa2); | |
| +	val &= ~0xc0; | |
| +	val |= 0x80; | |
| +	m88ds3103_writereg(state, 0xa2, val); | |
| +	 | |
| +	return 0; | |
| +} | |
| + | |
| +static void m88ds3103_release(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| + | |
| +	dprintk("%s\n", __func__); | |
| +	kfree(state); | |
| +} | |
| + | |
| +static int m88ds3103_check_id(struct m88ds3103_state *state) | |
| +{ | |
| +	int val_00, val_01; | |
| +	 | |
| +	/*check demod id*/ | |
| +	val_01 = m88ds3103_readreg(state, 0x01); | |
| +	printk(KERN_INFO "DS3000 chip version: %x attached.\n", val_01); | |
| +			 | |
| +	if(val_01 == 0xD0) | |
| +		state->demod_id = DS3103_ID; | |
| +	else if(val_01 == 0xC0) | |
| +		state->demod_id = DS3000_ID; | |
| +	else | |
| +		state->demod_id = UNKNOW_ID; | |
| +		 | |
| +	/*check tuner id*/ | |
| +	val_00 = m88ds3103_tuner_readreg(state, 0x00); | |
| +	printk(KERN_INFO "TS202x chip version[1]: %x attached.\n", val_00); | |
| +	val_00 &= 0x03; | |
| +	if(val_00 == 0) | |
| +	{ | |
| +		m88ds3103_tuner_writereg(state, 0x00, 0x01); | |
| +		msleep(3);		 | |
| +	} | |
| +	m88ds3103_tuner_writereg(state, 0x00, 0x03); | |
| +	msleep(5); | |
| +	 | |
| +	val_00 = m88ds3103_tuner_readreg(state, 0x00); | |
| +	printk(KERN_INFO "TS202x chip version[2]: %x attached.\n", val_00); | |
| +	val_00 &= 0xff; | |
| +	if((val_00 == 0x01) || (val_00 == 0x41) || (val_00 == 0x81)) | |
| +		state->tuner_id = TS2020_ID; | |
| +	else if(((val_00 & 0xc0)== 0xc0) || (val_00 == 0x83)) | |
| +		state->tuner_id = TS2022_ID; | |
| +	else | |
| +		state->tuner_id = UNKNOW_ID; | |
| +			 | |
| +	return state->demod_id;	 | |
| +} | |
| + | |
| +static struct dvb_frontend_ops m88ds3103_ops; | |
| +static int m88ds3103_initilaze(struct dvb_frontend *fe); | |
| + | |
| +struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *config, | |
| +				    struct i2c_adapter *i2c) | |
| +{ | |
| +	struct m88ds3103_state *state = NULL; | |
| + | |
| +	dprintk("%s\n", __func__); | |
| + | |
| +	/* allocate memory for the internal state */ | |
| +	state = kzalloc(sizeof(struct m88ds3103_state), GFP_KERNEL); | |
| +	if (state == NULL) { | |
| +		printk(KERN_ERR "Unable to kmalloc\n"); | |
| +		goto error2; | |
| +	} | |
| + | |
| +	state->config = config; | |
| +	state->i2c = i2c; | |
| +	state->preBer = 0xffff; | |
| +	state->delivery_system = SYS_DVBS; /*Default to DVB-S.*/ | |
| +	 | |
| +	/* check demod id */ | |
| +	if(m88ds3103_check_id(state) == UNKNOW_ID){ | |
| +		printk(KERN_ERR "Unable to find Montage chip\n"); | |
| +		goto error3; | |
| +	} | |
| + | |
| +	memcpy(&state->frontend.ops, &m88ds3103_ops, | |
| +			sizeof(struct dvb_frontend_ops)); | |
| +	state->frontend.demodulator_priv = state; | |
| +	 | |
| +	m88ds3103_initilaze(&state->frontend); | |
| +	 | |
| +	return &state->frontend; | |
| + | |
| +error3: | |
| +	kfree(state); | |
| +error2: | |
| +	return NULL; | |
| +} | |
| +EXPORT_SYMBOL(m88ds3103_attach); | |
| + | |
| +static int m88ds3103_set_carrier_offset(struct dvb_frontend *fe, | |
| +					s32 carrier_offset_khz) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	s32 tmp; | |
| + | |
| +	tmp = carrier_offset_khz; | |
| +	tmp *= 65536; | |
| +	 | |
| +	tmp = (2*tmp + MT_FE_MCLK_KHZ) / (2*MT_FE_MCLK_KHZ); | |
| + | |
| +	if (tmp < 0) | |
| +		tmp += 65536; | |
| + | |
| +	m88ds3103_writereg(state, 0x5f, tmp >> 8); | |
| +	m88ds3103_writereg(state, 0x5e, tmp & 0xff); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_set_symrate(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
| +	u16 value; | |
| +	 | |
| +	value = (((c->symbol_rate / 1000) << 15) + (MT_FE_MCLK_KHZ / 4)) / (MT_FE_MCLK_KHZ / 2); | |
| +	m88ds3103_writereg(state, 0x61, value & 0x00ff); | |
| +	m88ds3103_writereg(state, 0x62, (value & 0xff00) >> 8); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_set_CCI(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8 tmp; | |
| + | |
| +	tmp = m88ds3103_readreg(state, 0x56); | |
| +	tmp &= ~0x01; | |
| +	m88ds3103_writereg(state, 0x56, tmp); | |
| + | |
| +	tmp = m88ds3103_readreg(state, 0x76); | |
| +	tmp &= ~0x80; | |
| +	m88ds3103_writereg(state, 0x76, tmp); | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_init_reg(struct m88ds3103_state *state, const u8 *p_reg_tab, u32 size) | |
| +{ | |
| +	u32 i; | |
| +	 | |
| +	for(i = 0; i < size; i+=2) | |
| +		m88ds3103_writereg(state, p_reg_tab[i], p_reg_tab[i+1]); | |
| +		 | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_get_locked_sym_rate(struct m88ds3103_state *state, u32 *sym_rate_KSs) | |
| +{ | |
| +	u16	tmp; | |
| +	u32	sym_rate_tmp; | |
| +	u8	val_0x6d, val_0x6e; | |
| + | |
| +	val_0x6d = m88ds3103_readreg(state, 0x6d); | |
| +	val_0x6e = m88ds3103_readreg(state, 0x6e); | |
| + | |
| +	tmp = (u16)((val_0x6e<<8) | val_0x6d); | |
| + | |
| +	sym_rate_tmp = (u32)(tmp * MT_FE_MCLK_KHZ); | |
| +	sym_rate_tmp = (u32)(sym_rate_tmp / (1<<16)); | |
| +	*sym_rate_KSs = sym_rate_tmp; | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_get_channel_info(struct m88ds3103_state *state, u8 *p_mode, u8 *p_coderate) | |
| +{ | |
| +	u8	tmp, val_0x7E; | |
| + | |
| +	if(state->delivery_system == SYS_DVBS2){ | |
| +		val_0x7E = m88ds3103_readreg(state, 0x7e); | |
| +		tmp = (u8)((val_0x7E&0xC0) >> 6); | |
| +		*p_mode = tmp; | |
| +		tmp = (u8)(val_0x7E & 0x0f); | |
| +		*p_coderate = tmp; | |
| +	} else { | |
| +		*p_mode = 0; | |
| +		tmp = m88ds3103_readreg(state, 0xe6);		 | |
| +		tmp = (u8)(tmp >> 5); | |
| +		*p_coderate = tmp; | |
| +	} | |
| +	 | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_set_clock_ratio(struct m88ds3103_state *state) | |
| +{ | |
| +	u8	val, mod_fac, tmp1, tmp2; | |
| +	u32	input_datarate, locked_sym_rate_KSs; | |
| +	u32 MClk_KHz = 96000; | |
| +	u8 mod_mode, code_rate, divid_ratio = 0; | |
| + | |
| +	locked_sym_rate_KSs = 0; | |
| +	m88ds3103_get_locked_sym_rate(state, &locked_sym_rate_KSs); | |
| +	if(locked_sym_rate_KSs == 0) | |
| +		return 0; | |
| + | |
| +	m88ds3103_get_channel_info(state, &mod_mode, &code_rate); | |
| + | |
| +	if (state->delivery_system == SYS_DVBS2) | |
| +	{ | |
| +		switch(mod_mode) { | |
| +			case 1: mod_fac = 3; break; | |
| +			case 2:	mod_fac = 4; break; | |
| +			case 3:	mod_fac = 5; break; | |
| +			default: mod_fac = 2; break; | |
| +		} | |
| + | |
| +		switch(code_rate) { | |
| +			case 0: input_datarate = locked_sym_rate_KSs*mod_fac/8/4; break; | |
| +			case 1: input_datarate = locked_sym_rate_KSs*mod_fac/8/3;  	break; | |
| +			case 2: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/5;	break; | |
| +			case 3:	input_datarate = locked_sym_rate_KSs*mod_fac/8/2;	break; | |
| +			case 4:	input_datarate = locked_sym_rate_KSs*mod_fac*3/8/5;	break; | |
| +			case 5:	input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3;	break; | |
| +			case 6:	input_datarate = locked_sym_rate_KSs*mod_fac*3/8/4;	break; | |
| +			case 7:	input_datarate = locked_sym_rate_KSs*mod_fac*4/8/5;	break; | |
| +			case 8:	input_datarate = locked_sym_rate_KSs*mod_fac*5/8/6;	break; | |
| +			case 9:	input_datarate = locked_sym_rate_KSs*mod_fac*8/8/9;	break; | |
| +			case 10: input_datarate = locked_sym_rate_KSs*mod_fac*9/8/10; break; | |
| +			default: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break; | |
| +		} | |
| + | |
| +		if(state->demod_id == DS3000_ID) | |
| +			input_datarate = input_datarate * 115 / 100; | |
| + | |
| +		if(input_datarate < 4800)  {tmp1 = 15;tmp2 = 15;} //4.8MHz         TS clock | |
| +		else if(input_datarate < 4966)  {tmp1 = 14;tmp2 = 15;} //4.966MHz  TS clock | |
| +		else if(input_datarate < 5143)  {tmp1 = 14;tmp2 = 14;} //5.143MHz  TS clock | |
| +		else if(input_datarate < 5333)  {tmp1 = 13;tmp2 = 14;} //5.333MHz  TS clock | |
| +		else if(input_datarate < 5538)  {tmp1 = 13;tmp2 = 13;} //5.538MHz  TS clock | |
| +		else if(input_datarate < 5760)  {tmp1 = 12;tmp2 = 13;} //5.76MHz   TS clock       allan 0809 | |
| +		else if(input_datarate < 6000)  {tmp1 = 12;tmp2 = 12;} //6MHz      TS clock | |
| +		else if(input_datarate < 6260)  {tmp1 = 11;tmp2 = 12;} //6.26MHz   TS clock | |
| +		else if(input_datarate < 6545)  {tmp1 = 11;tmp2 = 11;} //6.545MHz  TS clock | |
| +		else if(input_datarate < 6857)  {tmp1 = 10;tmp2 = 11;} //6.857MHz  TS clock | |
| +		else if(input_datarate < 7200)  {tmp1 = 10;tmp2 = 10;} //7.2MHz    TS clock | |
| +		else if(input_datarate < 7578)  {tmp1 = 9;tmp2 = 10;}  //7.578MHz  TS clock | |
| +		else if(input_datarate < 8000)	{tmp1 = 9;tmp2 = 9;}   //8MHz      TS clock | |
| +		else if(input_datarate < 8470)	{tmp1 = 8;tmp2 = 9;}   //8.47MHz   TS clock | |
| +		else if(input_datarate < 9000)	{tmp1 = 8;tmp2 = 8;}   //9MHz      TS clock | |
| +		else if(input_datarate < 9600)	{tmp1 = 7;tmp2 = 8;}   //9.6MHz    TS clock | |
| +		else if(input_datarate < 10285)	{tmp1 = 7;tmp2 = 7;}   //10.285MHz TS clock | |
| +		else if(input_datarate < 12000)	{tmp1 = 6;tmp2 = 6;}   //12MHz     TS clock | |
| +		else if(input_datarate < 14400)	{tmp1 = 5;tmp2 = 5;}   //14.4MHz   TS clock | |
| +		else if(input_datarate < 18000)	{tmp1 = 4;tmp2 = 4;}   //18MHz     TS clock | |
| +		else							{tmp1 = 3;tmp2 = 3;}   //24MHz     TS clock | |
| + | |
| +		if(state->demod_id == DS3000_ID) { | |
| +			val = (u8)((tmp1<<4) + tmp2); | |
| +			m88ds3103_writereg(state, 0xfe, val); | |
| +		} else { | |
| +			tmp1 = m88ds3103_readreg(state, 0x22); | |
| +			tmp2 = m88ds3103_readreg(state, 0x24); | |
| + | |
| +			tmp1 >>= 6; | |
| +			tmp1 &= 0x03; | |
| +			tmp2 >>= 6; | |
| +			tmp2 &= 0x03; | |
| + | |
| +			if((tmp1 == 0x00) && (tmp2 == 0x01)) | |
| +				MClk_KHz = 144000; | |
| +			else if((tmp1 == 0x00) && (tmp2 == 0x03)) | |
| +				MClk_KHz = 72000; | |
| +			else if((tmp1 == 0x01) && (tmp2 == 0x01)) | |
| +				MClk_KHz = 115200; | |
| +			else if((tmp1 == 0x02) && (tmp2 == 0x01)) | |
| +				MClk_KHz = 96000; | |
| +			else if((tmp1 == 0x03) && (tmp2 == 0x00)) | |
| +				MClk_KHz = 192000; | |
| +			else | |
| +				return 0; | |
| + | |
| +			if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/ | |
| +				input_datarate = 5200; | |
| +				 | |
| +			if(input_datarate != 0) | |
| +				divid_ratio = (u8)(MClk_KHz / input_datarate); | |
| +			else | |
| +				divid_ratio = 0xFF; | |
| + | |
| +			if(divid_ratio > 128) | |
| +				divid_ratio = 128; | |
| + | |
| +			if(divid_ratio < 2) | |
| +				divid_ratio = 2; | |
| + | |
| +			tmp1 = (u8)(divid_ratio / 2); | |
| +			tmp2 = (u8)(divid_ratio / 2); | |
| + | |
| +			if((divid_ratio % 2) != 0) | |
| +				tmp2 += 1; | |
| + | |
| +			tmp1 -= 1; | |
| +			tmp2 -= 1; | |
| + | |
| +			tmp1 &= 0x3f; | |
| +			tmp2 &= 0x3f; | |
| + | |
| +			val = m88ds3103_readreg(state, 0xfe); | |
| +			val &= 0xF0; | |
| +			val |= (tmp2 >> 2) & 0x0f; | |
| +			m88ds3103_writereg(state, 0xfe, val); | |
| + | |
| +			val = (u8)((tmp2 & 0x03) << 6);	 | |
| +			val |= tmp1; | |
| +			m88ds3103_writereg(state, 0xea, val); | |
| +		} | |
| +	} else { | |
| +		mod_fac = 2; | |
| + | |
| +		switch(code_rate) { | |
| +			case 4:	input_datarate = locked_sym_rate_KSs*mod_fac/2/8;	break; | |
| +			case 3:	input_datarate = locked_sym_rate_KSs*mod_fac*2/3/8;	break; | |
| +			case 2:	input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8;	break; | |
| +			case 1:	input_datarate = locked_sym_rate_KSs*mod_fac*5/6/8;	break; | |
| +			case 0:	input_datarate = locked_sym_rate_KSs*mod_fac*7/8/8;	break; | |
| +			default: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8;	break; | |
| +		} | |
| + | |
| +		if(state->demod_id == DS3000_ID) | |
| +			input_datarate = input_datarate * 115 / 100; | |
| + | |
| +		if(input_datarate < 6857)		{tmp1 = 7;tmp2 = 7;} //6.857MHz     TS clock | |
| +		else if(input_datarate < 7384)	{tmp1 = 6;tmp2 = 7;} //7.384MHz     TS clock | |
| +		else if(input_datarate < 8000)	{tmp1 = 6;tmp2 = 6;} //8MHz     	TS clock | |
| +		else if(input_datarate < 8727)	{tmp1 = 5;tmp2 = 6;} //8.727MHz 	TS clock | |
| +		else if(input_datarate < 9600)	{tmp1 = 5;tmp2 = 5;} //9.6MHz    	TS clock | |
| +		else if(input_datarate < 10666)	{tmp1 = 4;tmp2 = 5;} //10.666MHz 	TS clock | |
| +		else if(input_datarate < 12000)	{tmp1 = 4;tmp2 = 4;} //12MHz 	 	TS clock | |
| +		else if(input_datarate < 13714)	{tmp1 = 3;tmp2 = 4;} //13.714MHz 	TS clock | |
| +		else if(input_datarate < 16000)	{tmp1 = 3;tmp2 = 3;} //16MHz     	TS clock | |
| +		else if(input_datarate < 19200)	{tmp1 = 2;tmp2 = 3;} //19.2MHz   	TS clock | |
| +		else 							{tmp1 = 2;tmp2 = 2;} //24MHz     	TS clock | |
| + | |
| +		if(state->demod_id == DS3000_ID) { | |
| +			val = m88ds3103_readreg(state, 0xfe); | |
| +			val &= 0xc0; | |
| +			val |= ((u8)((tmp1<<3) + tmp2)); | |
| +			m88ds3103_writereg(state, 0xfe, val); | |
| +		} else { | |
| +			if(input_datarate < 5200) /*Max. 2011-12-23 11:55*/ | |
| +				input_datarate = 5200; | |
| +			 | |
| +			if(input_datarate != 0) | |
| +				divid_ratio = (u8)(MClk_KHz / input_datarate); | |
| +			else | |
| +				divid_ratio = 0xFF; | |
| + | |
| +			if(divid_ratio > 128) | |
| +				divid_ratio = 128; | |
| + | |
| +			if(divid_ratio < 2) | |
| +				divid_ratio = 2; | |
| + | |
| +			tmp1 = (u8)(divid_ratio / 2); | |
| +			tmp2 = (u8)(divid_ratio / 2); | |
| + | |
| +			if((divid_ratio % 2) != 0) | |
| +				tmp2 += 1; | |
| + | |
| +			tmp1 -= 1; | |
| +			tmp2 -= 1; | |
| + | |
| +			tmp1 &= 0x3f; | |
| +			tmp2 &= 0x3f; | |
| + | |
| +			val = m88ds3103_readreg(state, 0xfe); | |
| +			val &= 0xF0; | |
| +			val |= (tmp2 >> 2) & 0x0f; | |
| +			m88ds3103_writereg(state, 0xfe, val); | |
| +			 | |
| +			val = (u8)((tmp2 & 0x03) << 6); | |
| +			val |= tmp1; | |
| +			m88ds3103_writereg(state, 0xea, val); | |
| +		} | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_demod_connect(struct dvb_frontend *fe, s32 carrier_offset_khz)  | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
| +	u16 value; | |
| +	u8 val1,val2,data; | |
| +	 | |
| +	dprintk("connect delivery system = %d\n", state->delivery_system); | |
| +	 | |
| +	/* ds3000 global reset */ | |
| +	m88ds3103_writereg(state, 0x07, 0x80); | |
| +	m88ds3103_writereg(state, 0x07, 0x00); | |
| +	/* ds3000 build-in uC reset */ | |
| +	m88ds3103_writereg(state, 0xb2, 0x01); | |
| +	/* ds3000 software reset */ | |
| +	m88ds3103_writereg(state, 0x00, 0x01); | |
| + | |
| +	switch (state->delivery_system) { | |
| +	case SYS_DVBS: | |
| +		/* initialise the demod in DVB-S mode */ | |
| +		if(state->demod_id == DS3000_ID){ | |
| +			m88ds3103_init_reg(state, ds3000_dvbs_init_tab, sizeof(ds3000_dvbs_init_tab)); | |
| +			 | |
| +			value = m88ds3103_readreg(state, 0xfe); | |
| +			value &= 0xc0; | |
| +			value |= 0x1b; | |
| +			m88ds3103_writereg(state, 0xfe, value); | |
| +			 | |
| +			if(state->config->ci_mode) | |
| +				val1 = 0x80; | |
| +			else if(state->config->ts_mode) | |
| +				val1 = 0x60; | |
| +			else | |
| +				val1 = 0x20; | |
| +			m88ds3103_writereg(state, 0xfd, val1); | |
| +			 | |
| +		}else if(state->demod_id == DS3103_ID){ | |
| +			m88ds3103_init_reg(state, ds3103_dvbs_init_tab, sizeof(ds3103_dvbs_init_tab)); | |
| +			 | |
| +			/* set ts clock */ | |
| +			if(state->config->ci_mode == 2){ | |
| +				val1 = 6; val2 = 6; | |
| +			}else if(state->config->ts_mode == 0)	{ | |
| +				val1 = 3; val2 = 3; | |
| +			}else{ | |
| +				val1 = 0; val2 = 0; | |
| +			} | |
| +			val1 -= 1; val2 -= 1; | |
| +			val1 &= 0x3f; val2 &= 0x3f; | |
| +			data = m88ds3103_readreg(state, 0xfe); | |
| +			data &= 0xf0; | |
| +			data |= (val2 >> 2) & 0x0f; | |
| +			m88ds3103_writereg(state, 0xfe, data); | |
| +			data = (val2 & 0x03) << 6; | |
| +			data |= val1; | |
| +			m88ds3103_writereg(state, 0xea, data); | |
| +			 | |
| +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d)); | |
| +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30)); | |
| +			 | |
| +			/* set master clock */ | |
| +			val1 = m88ds3103_readreg(state, 0x22); | |
| +			val2 = m88ds3103_readreg(state, 0x24); | |
| +			 | |
| +			val1 &= 0x3f; | |
| +			val2 &= 0x3f; | |
| +			val1 |= 0x80; | |
| +			val2 |= 0x40; | |
| + | |
| +			m88ds3103_writereg(state, 0x22, val1); | |
| +			m88ds3103_writereg(state, 0x24, val2);	 | |
| +			 | |
| +			if(state->config->ci_mode) | |
| +				val1 = 0x03; | |
| +			else if(state->config->ts_mode) | |
| +				val1 = 0x06; | |
| +			else | |
| +				val1 = 0x42; | |
| +			m88ds3103_writereg(state, 0xfd, val1);		 | |
| +		} | |
| +		break; | |
| +	case SYS_DVBS2: | |
| +		/* initialise the demod in DVB-S2 mode */ | |
| +		if(state->demod_id == DS3000_ID){ | |
| +			m88ds3103_init_reg(state, ds3000_dvbs2_init_tab, sizeof(ds3000_dvbs2_init_tab)); | |
| +		 | |
| +			if (c->symbol_rate >= 30000000) | |
| +				m88ds3103_writereg(state, 0xfe, 0x54); | |
| +			else | |
| +				m88ds3103_writereg(state, 0xfe, 0x98); | |
| +								 | |
| +		}else if(state->demod_id == DS3103_ID){ | |
| +			m88ds3103_init_reg(state, ds3103_dvbs2_init_tab, sizeof(ds3103_dvbs2_init_tab)); | |
| + | |
| +			/* set ts clock */ | |
| +			if(state->config->ci_mode == 2){ | |
| +				val1 = 6; val2 = 6; | |
| +			}else if(state->config->ts_mode == 0){ | |
| +				val1 = 5; val2 = 4; | |
| +			}else{ | |
| +				val1 = 0; val2 = 0; | |
| +			} | |
| +			val1 -= 1; val2 -= 1; | |
| +			val1 &= 0x3f; val2 &= 0x3f; | |
| +			data = m88ds3103_readreg(state, 0xfe); | |
| +			data &= 0xf0; | |
| +			data |= (val2 >> 2) & 0x0f; | |
| +			m88ds3103_writereg(state, 0xfe, data); | |
| +			data = (val2 & 0x03) << 6; | |
| +			data |= val1; | |
| +			m88ds3103_writereg(state, 0xea, data); | |
| +			 | |
| +			m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d)); | |
| +			m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30)); | |
| +			 | |
| +			/* set master clock */ | |
| +			val1 = m88ds3103_readreg(state, 0x22); | |
| +			val2 = m88ds3103_readreg(state, 0x24); | |
| +			 | |
| +			val1 &= 0x3f; | |
| +			val2 &= 0x3f; | |
| +			if((state->config->ci_mode == 2) || (state->config->ts_mode == 1)){ | |
| +				val1 |= 0x80; | |
| +				val2 |= 0x40; | |
| +			}else{ | |
| +				if (c->symbol_rate >= 28000000){ | |
| +					val1 |= 0xc0; | |
| +				}else if (c->symbol_rate >= 18000000){ | |
| +					val2 |= 0x40; | |
| +				}else{ | |
| +					val1 |= 0x80; | |
| +					val2 |= 0x40; | |
| +				}				 | |
| +			} | |
| +			m88ds3103_writereg(state, 0x22, val1); | |
| +			m88ds3103_writereg(state, 0x24, val2);					 | |
| +		} | |
| +		 | |
| +		if(state->config->ci_mode) | |
| +			val1 = 0x03; | |
| +		else if(state->config->ts_mode) | |
| +			val1 = 0x06; | |
| +		else | |
| +			val1 = 0x42; | |
| +		m88ds3103_writereg(state, 0xfd, val1); | |
| +		 | |
| +		break; | |
| +	default: | |
| +		return 1; | |
| +	} | |
| +	/* disable 27MHz clock output */ | |
| +	m88ds3103_writereg(state, 0x29, 0x80); | |
| +	/* enable ac coupling */ | |
| +	m88ds3103_writereg(state, 0x25, 0x8a); | |
| + | |
| +	if ((c->symbol_rate / 1000) <= 3000){ | |
| +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 32 * 100 / 64 = 400*/ | |
| +		m88ds3103_writereg(state, 0xc8, 0x20); | |
| +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/ | |
| +		m88ds3103_writereg(state, 0xc7, 0x00); | |
| +	}else if((c->symbol_rate / 1000) <= 10000){ | |
| +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 16 * 100 / 64 = 200*/ | |
| +		m88ds3103_writereg(state, 0xc8, 0x10); | |
| +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/ | |
| +		m88ds3103_writereg(state, 0xc7, 0x00); | |
| +	}else{ | |
| +		m88ds3103_writereg(state, 0xc3, 0x08); /* 8 * 6 * 100 / 64 = 75*/ | |
| +		m88ds3103_writereg(state, 0xc8, 0x06); | |
| +		m88ds3103_writereg(state, 0xc4, 0x08); /* 8 * 0 * 100 / 128 = 0*/ | |
| +		m88ds3103_writereg(state, 0xc7, 0x00); | |
| +	} | |
| + | |
| +	m88ds3103_set_symrate(fe); | |
| +	 | |
| +	m88ds3103_set_CCI(fe); | |
| + | |
| +	m88ds3103_set_carrier_offset(fe, carrier_offset_khz); | |
| +		 | |
| +	/* ds3000 out of software reset */ | |
| +	m88ds3103_writereg(state, 0x00, 0x00); | |
| +	/* start ds3000 build-in uC */ | |
| +	m88ds3103_writereg(state, 0xb2, 0x00);	 | |
| +	 | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_set_frontend(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
| + | |
| +	int i; | |
| +	fe_status_t status; | |
| +	u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf, div4, capCode, changePLL; | |
| +	s32 offset_khz, lpf_offset_KHz; | |
| +	u16 value, ndiv, lpf_coeff; | |
| +	u32 f3db, gdiv28, realFreq; | |
| +	u8 RFgain; | |
| + | |
| +	dprintk("%s() ", __func__); | |
| +	dprintk("c frequency = %d\n", c->frequency); | |
| +	dprintk("symbol rate = %d\n", c->symbol_rate); | |
| +	dprintk("delivery system = %d\n", c->delivery_system); | |
| +	 | |
| +	realFreq = c->frequency; | |
| +	lpf_offset_KHz = 0; | |
| +	if(c->symbol_rate < 5000000){ | |
| +		lpf_offset_KHz = FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz; | |
| +		realFreq += FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz; | |
| +	} | |
| +	 | |
| +	if (state->config->set_ts_params) | |
| +		state->config->set_ts_params(fe, 0); | |
| + | |
| +	div4 = 0; | |
| +	RFgain = 0; | |
| +	if(state->tuner_id == TS2022_ID){ | |
| +		m88ds3103_tuner_writereg(state, 0x10, 0x0a); | |
| +		m88ds3103_tuner_writereg(state, 0x11, 0x40); | |
| +		if (realFreq < 1103000) { | |
| +			m88ds3103_tuner_writereg(state, 0x10, 0x1b); | |
| +			div4 = 1; | |
| +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ;				 | |
| +		}else { | |
| +			ndiv = (realFreq * (6 + 8) * 2)/MT_FE_CRYSTAL_KHZ; | |
| +		} | |
| +		ndiv = ndiv + ndiv%2; | |
| +		if(ndiv < 4095) | |
| +			ndiv = ndiv - 1024; | |
| +		else if (ndiv < 6143) | |
| +			ndiv = ndiv + 1024; | |
| +		else | |
| +			ndiv = ndiv + 3072;	 | |
| +		 | |
| +		m88ds3103_tuner_writereg(state, 0x01, (ndiv & 0x3f00) >> 8);											 | |
| +	}else{ | |
| +		m88ds3103_tuner_writereg(state, 0x10, 0x00);			 | |
| +		if (realFreq < 1146000){ | |
| +			m88ds3103_tuner_writereg(state, 0x10, 0x11); | |
| +			div4 = 1; | |
| +			ndiv = (realFreq * (6 + 8) * 4) / MT_FE_CRYSTAL_KHZ; | |
| +		}else{ | |
| +			m88ds3103_tuner_writereg(state, 0x10, 0x01); | |
| +			ndiv = (realFreq * (6 + 8) * 2) / MT_FE_CRYSTAL_KHZ; | |
| +		} | |
| +		ndiv = ndiv + ndiv%2; | |
| +		ndiv = ndiv - 1024; | |
| +		m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8)&0x0f); | |
| +	} | |
| +	/* set pll */ | |
| +	m88ds3103_tuner_writereg(state, 0x02, ndiv & 0x00ff); | |
| +	m88ds3103_tuner_writereg(state, 0x03, 0x06); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x0f); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x10); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x00);	 | |
| + | |
| +	if(state->tuner_id == TS2022_ID){ | |
| +		if(( realFreq >= 1650000 ) && (realFreq <= 1850000)){ | |
| +			msleep(5); | |
| +			value = m88ds3103_tuner_readreg(state, 0x14); | |
| +			value &= 0x7f; | |
| +			if(value < 64){ | |
| +				m88ds3103_tuner_writereg(state, 0x10, 0x82); | |
| +				m88ds3103_tuner_writereg(state, 0x11, 0x6f); | |
| + | |
| +				m88ds3103_tuner_writereg(state, 0x51, 0x0f); | |
| +				m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +				m88ds3103_tuner_writereg(state, 0x50, 0x10); | |
| +				m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +			} | |
| +		} | |
| +		msleep(5); | |
| +		value = m88ds3103_tuner_readreg(state, 0x14); | |
| +		value &= 0x1f; | |
| + | |
| +		if(value > 19){ | |
| +			value = m88ds3103_tuner_readreg(state, 0x10); | |
| +			value &= 0x1d; | |
| +			m88ds3103_tuner_writereg(state, 0x10, value); | |
| +		}				 | |
| +	}else{ | |
| +		msleep(5); | |
| +		value = m88ds3103_tuner_readreg(state, 0x66); | |
| +		changePLL = (((value & 0x80) >> 7) != div4); | |
| + | |
| +		if(changePLL){ | |
| +			m88ds3103_tuner_writereg(state, 0x10, 0x11); | |
| +			div4 = 1; | |
| +			ndiv = (realFreq * (6 + 8) * 4)/MT_FE_CRYSTAL_KHZ; | |
| +			ndiv = ndiv + ndiv%2; | |
| +			ndiv = ndiv - 1024; | |
| +					 | |
| +			m88ds3103_tuner_writereg(state, 0x01, (ndiv>>8) & 0x0f); | |
| +			m88ds3103_tuner_writereg(state, 0x02, ndiv & 0xff); | |
| +			 | |
| +			m88ds3103_tuner_writereg(state, 0x51, 0x0f); | |
| +			m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +			m88ds3103_tuner_writereg(state, 0x50, 0x10); | |
| +			m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +		}		 | |
| +	} | |
| +	/*set the RF gain*/ | |
| +	if(state->tuner_id == TS2020_ID) | |
| +		m88ds3103_tuner_writereg(state, 0x60, 0x79); | |
| +			 | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x17); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x08); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +	msleep(5); | |
| + | |
| +	if(state->tuner_id == TS2020_ID){ | |
| +		RFgain = m88ds3103_tuner_readreg(state, 0x3d); | |
| +		RFgain &= 0x0f; | |
| +		if(RFgain < 15){ | |
| +			if(RFgain < 4)  | |
| +				RFgain = 0; | |
| +			else | |
| +				RFgain = RFgain -3; | |
| +			value = ((RFgain << 3) | 0x01) & 0x79; | |
| +			m88ds3103_tuner_writereg(state, 0x60, value); | |
| +			m88ds3103_tuner_writereg(state, 0x51, 0x17); | |
| +			m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +			m88ds3103_tuner_writereg(state, 0x50, 0x08); | |
| +			m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +		} | |
| +	} | |
| +	 | |
| +	/* set the LPF */ | |
| +	if(state->tuner_id == TS2022_ID){ | |
| +		m88ds3103_tuner_writereg(state, 0x25, 0x00); | |
| +		m88ds3103_tuner_writereg(state, 0x27, 0x70); | |
| +		m88ds3103_tuner_writereg(state, 0x41, 0x09); | |
| +		m88ds3103_tuner_writereg(state, 0x08, 0x0b); | |
| +	} | |
| + | |
| +	f3db = ((c->symbol_rate / 1000) *135) / 200 + 2000; | |
| +	f3db += lpf_offset_KHz; | |
| +	if (f3db < 7000) | |
| +		f3db = 7000; | |
| +	if (f3db > 40000) | |
| +		f3db = 40000; | |
| +			 | |
| +	gdiv28 = (MT_FE_CRYSTAL_KHZ / 1000 * 1694 + 500) / 1000; | |
| +	m88ds3103_tuner_writereg(state, 0x04, gdiv28 & 0xff); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1b); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x04); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +	msleep(5); | |
| + | |
| +	value = m88ds3103_tuner_readreg(state, 0x26); | |
| +	capCode = value & 0x3f; | |
| +	if(state->tuner_id == TS2022_ID){ | |
| +		m88ds3103_tuner_writereg(state, 0x41, 0x0d); | |
| + | |
| +		m88ds3103_tuner_writereg(state, 0x51, 0x1b); | |
| +		m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +		m88ds3103_tuner_writereg(state, 0x50, 0x04); | |
| +		m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| + | |
| +		msleep(2); | |
| + | |
| +		value = m88ds3103_tuner_readreg(state, 0x26); | |
| +		value &= 0x3f; | |
| +		value = (capCode + value) / 2;		 | |
| +	} | |
| +	else | |
| +		value = capCode; | |
| +		 | |
| +	gdiv28 = gdiv28 * 207 / (value * 2 + 151);	 | |
| +	mlpf_max = gdiv28 * 135 / 100; | |
| +	mlpf_min = gdiv28 * 78 / 100; | |
| +	if (mlpf_max > 63) | |
| +		mlpf_max = 63; | |
| + | |
| +	if(state->tuner_id == TS2022_ID) | |
| +		lpf_coeff = 3200; | |
| +	else | |
| +		lpf_coeff = 2766; | |
| +		 | |
| +	nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (MT_FE_CRYSTAL_KHZ / 1000)  + 1) / 2 ;	 | |
| +	if (nlpf > 23) nlpf = 23; | |
| +	if (nlpf < 1) nlpf = 1; | |
| + | |
| +	lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2 / f3db + 1) / 2; | |
| + | |
| +	if (lpf_mxdiv < mlpf_min){ | |
| +		nlpf++; | |
| +		lpf_mxdiv = (nlpf * (MT_FE_CRYSTAL_KHZ / 1000) * lpf_coeff * 2  / f3db + 1) / 2; | |
| +	} | |
| + | |
| +	if (lpf_mxdiv > mlpf_max) | |
| +		lpf_mxdiv = mlpf_max; | |
| + | |
| +	m88ds3103_tuner_writereg(state, 0x04, lpf_mxdiv); | |
| +	m88ds3103_tuner_writereg(state, 0x06, nlpf); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1b); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x04); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +	msleep(5); | |
| +	 | |
| +	if(state->tuner_id == TS2022_ID){ | |
| +		msleep(2); | |
| +		value = m88ds3103_tuner_readreg(state, 0x26); | |
| +		capCode = value & 0x3f; | |
| + | |
| +		m88ds3103_tuner_writereg(state, 0x41, 0x09); | |
| + | |
| +		m88ds3103_tuner_writereg(state, 0x51, 0x1b); | |
| +		m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +		m88ds3103_tuner_writereg(state, 0x50, 0x04); | |
| +		m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| + | |
| +		msleep(2); | |
| +		value = m88ds3103_tuner_readreg(state, 0x26); | |
| +		value &= 0x3f; | |
| +		value = (capCode + value) / 2; | |
| + | |
| +		value = value | 0x80; | |
| +		m88ds3103_tuner_writereg(state, 0x25, value); | |
| +		m88ds3103_tuner_writereg(state, 0x27, 0x30); | |
| + | |
| +		m88ds3103_tuner_writereg(state, 0x08, 0x09);		 | |
| +	} | |
| + | |
| +	/* Set the BB gain */ | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1e); | |
| +	m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x01); | |
| +	m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +	if(state->tuner_id == TS2020_ID){ | |
| +		if(RFgain == 15){ | |
| +			msleep(40); | |
| +			value = m88ds3103_tuner_readreg(state, 0x21); | |
| +			value &= 0x0f; | |
| +			if(value < 3){ | |
| +				m88ds3103_tuner_writereg(state, 0x60, 0x61); | |
| +				m88ds3103_tuner_writereg(state, 0x51, 0x17); | |
| +				m88ds3103_tuner_writereg(state, 0x51, 0x1f); | |
| +				m88ds3103_tuner_writereg(state, 0x50, 0x08); | |
| +				m88ds3103_tuner_writereg(state, 0x50, 0x00); | |
| +			}			 | |
| +		} | |
| +	} | |
| +	msleep(60); | |
| +	 | |
| +	offset_khz = (ndiv - ndiv % 2 + 1024) * MT_FE_CRYSTAL_KHZ | |
| +		/ (6 + 8) / (div4 + 1) / 2 - realFreq; | |
| + | |
| +	m88ds3103_demod_connect(fe, offset_khz+lpf_offset_KHz); | |
| + | |
| +	for (i = 0; i < 30 ; i++) { | |
| +		m88ds3103_read_status(fe, &status); | |
| +		if (status & FE_HAS_LOCK){ | |
| +			break; | |
| +                } | |
| +		msleep(20); | |
| +	} | |
| +	 | |
| +	if((status & FE_HAS_LOCK) == 0){ | |
| +		state->delivery_system = (state->delivery_system == SYS_DVBS) ? SYS_DVBS2 : SYS_DVBS; | |
| +		m88ds3103_demod_connect(fe, offset_khz); | |
| +	 | |
| +		for (i = 0; i < 30 ; i++) { | |
| +			m88ds3103_read_status(fe, &status); | |
| +			if (status & FE_HAS_LOCK){ | |
| +				break; | |
| +                	} | |
| +			msleep(20); | |
| +		} | |
| +	} | |
| +	 | |
| +	if (status & FE_HAS_LOCK){ | |
| +		if(state->config->ci_mode == 2) | |
| +			m88ds3103_set_clock_ratio(state); | |
| +		if(state->config->start_ctrl){ | |
| +			if(state->first_lock == 0){ | |
| +				state->config->start_ctrl(fe); | |
| +				state->first_lock = 1;	 | |
| +			} | |
| +		}		 | |
| +	} | |
| +		 | |
| +	return 0; | |
| +} | |
| + | |
| +static int m88ds3103_tune(struct dvb_frontend *fe, | |
| +			bool re_tune, | |
| +			unsigned int mode_flags, | |
| +			unsigned int *delay, | |
| +			fe_status_t *status) | |
| +{	 | |
| +	*delay = HZ / 5; | |
| +	 | |
| +	dprintk("%s() ", __func__); | |
| +	dprintk("re_tune = %d\n", re_tune); | |
| +	 | |
| +	if (re_tune) { | |
| +		int ret = m88ds3103_set_frontend(fe); | |
| +		if (ret) | |
| +			return ret; | |
| +	} | |
| +	 | |
| +	return m88ds3103_read_status(fe, status); | |
| +} | |
| + | |
| +static enum dvbfe_algo m88ds3103_get_algo(struct dvb_frontend *fe) | |
| +{ | |
| +	return DVBFE_ALGO_HW; | |
| +} | |
| +  | |
| + /* | |
| + * Power config will reset and load initial firmware if required | |
| + */ | |
| +static int m88ds3103_initilaze(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	int ret; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| +	/* hard reset */ | |
| +	m88ds3103_writereg(state, 0x07, 0x80); | |
| +	m88ds3103_writereg(state, 0x07, 0x00); | |
| +	msleep(1); | |
| +	 | |
| +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08)); | |
| +	msleep(1); | |
| + | |
| +	if(state->tuner_id == TS2020_ID){ | |
| +		/* TS2020 init */ | |
| +		m88ds3103_tuner_writereg(state, 0x42, 0x73); | |
| +		msleep(2); | |
| +		m88ds3103_tuner_writereg(state, 0x05, 0x01); | |
| +		m88ds3103_tuner_writereg(state, 0x62, 0xb5); | |
| +		m88ds3103_tuner_writereg(state, 0x07, 0x02); | |
| +		m88ds3103_tuner_writereg(state, 0x08, 0x01); | |
| +	} | |
| +	else if(state->tuner_id == TS2022_ID){ | |
| +		/* TS2022 init */ | |
| +		m88ds3103_tuner_writereg(state, 0x62, 0x6c); | |
| +		msleep(2); | |
| +		m88ds3103_tuner_writereg(state, 0x42, 0x6c); | |
| +		msleep(2); | |
| +		m88ds3103_tuner_writereg(state, 0x7d, 0x9d); | |
| +		m88ds3103_tuner_writereg(state, 0x7c, 0x9a); | |
| +		m88ds3103_tuner_writereg(state, 0x7a, 0x76); | |
| + | |
| +		m88ds3103_tuner_writereg(state, 0x3b, 0x01); | |
| +		m88ds3103_tuner_writereg(state, 0x63, 0x88); | |
| + | |
| +		m88ds3103_tuner_writereg(state, 0x61, 0x85); | |
| +		m88ds3103_tuner_writereg(state, 0x22, 0x30); | |
| +		m88ds3103_tuner_writereg(state, 0x30, 0x40); | |
| +		m88ds3103_tuner_writereg(state, 0x20, 0x23); | |
| +		m88ds3103_tuner_writereg(state, 0x24, 0x02); | |
| +		m88ds3103_tuner_writereg(state, 0x12, 0xa0);	 | |
| +	} | |
| +		 | |
| +	if(state->demod_id == DS3103_ID){ | |
| +		m88ds3103_writereg(state, 0x07, 0xe0); | |
| +		m88ds3103_writereg(state, 0x07, 0x00); | |
| +		msleep(1);		 | |
| +	} | |
| +	m88ds3103_writereg(state, 0xb2, 0x01); | |
| +	 | |
| +	/* Load the firmware if required */ | |
| +	ret = m88ds3103_load_firmware(fe); | |
| +	if (ret != 0){ | |
| +		printk(KERN_ERR "%s: Unable initialize firmware\n", __func__); | |
| +		return ret; | |
| +	} | |
| +	if(state->demod_id == DS3103_ID){ | |
| +		m88ds3103_writereg(state, 0x4d, 0xfd & m88ds3103_readreg(state, 0x4d)); | |
| +		m88ds3103_writereg(state, 0x30, 0xef & m88ds3103_readreg(state, 0x30));		 | |
| +	} | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +/* | |
| + * Initialise or wake up device | |
| + */ | |
| +static int m88ds3103_initfe(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| +	u8 val; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| + | |
| +	/* 1st step to wake up demod */ | |
| +	m88ds3103_writereg(state, 0x08, 0x01 | m88ds3103_readreg(state, 0x08)); | |
| +	m88ds3103_writereg(state, 0x04, 0xfe & m88ds3103_readreg(state, 0x04)); | |
| +	m88ds3103_writereg(state, 0x23, 0xef & m88ds3103_readreg(state, 0x23)); | |
| +	 | |
| +	/* 2nd step to wake up tuner */ | |
| +	val = m88ds3103_tuner_readreg(state, 0x00) & 0xff; | |
| +	if((val & 0x01) == 0){ | |
| +		m88ds3103_tuner_writereg(state, 0x00, 0x01); | |
| +		msleep(50); | |
| +	} | |
| +	m88ds3103_tuner_writereg(state, 0x00, 0x03); | |
| +	msleep(50); | |
| +	 | |
| +	return 0;	 | |
| +} | |
| + | |
| +/* Put device to sleep */ | |
| +static int m88ds3103_sleep(struct dvb_frontend *fe) | |
| +{ | |
| +	struct m88ds3103_state *state = fe->demodulator_priv; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| +	 | |
| +	/* 1st step to sleep tuner */ | |
| +	m88ds3103_tuner_writereg(state, 0x00, 0x00); | |
| +	 | |
| +	/* 2nd step to sleep demod */ | |
| +	m88ds3103_writereg(state, 0x08, 0xfe & m88ds3103_readreg(state, 0x08)); | |
| +	m88ds3103_writereg(state, 0x04, 0x01 | m88ds3103_readreg(state, 0x04)); | |
| +	m88ds3103_writereg(state, 0x23, 0x10 | m88ds3103_readreg(state, 0x23)); | |
| +	 | |
| + | |
| +	return 0; | |
| +} | |
| + | |
| +static struct dvb_frontend_ops m88ds3103_ops = { | |
| +	.delsys = { SYS_DVBS, SYS_DVBS2}, | |
| +	.info = { | |
| +		.name = "Montage DS3103/TS2022", | |
| +		.type = FE_QPSK, | |
| +		.frequency_min = 950000, | |
| +		.frequency_max = 2150000, | |
| +		.frequency_stepsize = 1011, /* kHz for QPSK frontends */ | |
| +		.frequency_tolerance = 5000, | |
| +		.symbol_rate_min = 1000000, | |
| +		.symbol_rate_max = 45000000, | |
| +		.caps = FE_CAN_INVERSION_AUTO | | |
| +			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | |
| +			FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | | |
| +			FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | |
| +			FE_CAN_2G_MODULATION | | |
| +			FE_CAN_QPSK | FE_CAN_RECOVER | |
| +	}, | |
| + | |
| +	.release = m88ds3103_release, | |
| + | |
| +	.init = m88ds3103_initfe, | |
| +	.sleep = m88ds3103_sleep, | |
| +	.read_status = m88ds3103_read_status, | |
| +	.read_ber = m88ds3103_read_ber, | |
| +	.read_signal_strength = m88ds3103_read_signal_strength, | |
| +	.read_snr = m88ds3103_read_snr, | |
| +	.read_ucblocks = m88ds3103_read_ucblocks, | |
| +	.set_tone = m88ds3103_set_tone, | |
| +	.set_voltage = m88ds3103_set_voltage, | |
| +	.diseqc_send_master_cmd = m88ds3103_send_diseqc_msg, | |
| +	.diseqc_send_burst = m88ds3103_diseqc_send_burst, | |
| +	.get_frontend_algo = m88ds3103_get_algo, | |
| +	.tune = m88ds3103_tune, | |
| +	.set_frontend = m88ds3103_set_frontend, | |
| +}; | |
| + | |
| +MODULE_DESCRIPTION("DVB Frontend module for Montage DS3103/TS2022 hardware"); | |
| +MODULE_AUTHOR("Max nibble"); | |
| +MODULE_LICENSE("GPL"); | |
| diff -urN a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h | |
| --- a/drivers/media/dvb-frontends/m88ds3103.h	1970-01-01 08:00:00.000000000 +0800 | |
| +++ b/drivers/media/dvb-frontends/m88ds3103.h	2013-01-30 12:33:51.000000000 +0800 | |
| @@ -0,0 +1,53 @@ | |
| +/* | |
| +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver | |
| + | |
| +    This program is free software; you can redistribute it and/or modify | |
| +    it under the terms of the GNU General Public License as published by | |
| +    the Free Software Foundation; either version 2 of the License, or | |
| +    (at your option) any later version. | |
| + | |
| +    This program is distributed in the hope that it will be useful, | |
| +    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| +    GNU General Public License for more details. | |
| + | |
| +    You should have received a copy of the GNU General Public License | |
| +    along with this program; if not, write to the Free Software | |
| +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| + */ | |
| + | |
| +#ifndef M88DS3103_H | |
| +#define M88DS3103_H | |
| + | |
| +#include <linux/dvb/frontend.h> | |
| + | |
| +struct m88ds3103_config { | |
| +	/* the demodulator's i2c address */ | |
| +	u8 demod_address; | |
| +	u8 ci_mode; | |
| +	u8 pin_ctrl; | |
| +	u8 ts_mode; /* 0: Parallel, 1: Serial */ | |
| + | |
| +	/* Set device param to start dma */ | |
| +	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); | |
| +    /* Start to transfer data */ | |
| +    int (*start_ctrl)(struct dvb_frontend *fe); | |
| +    /* Set LNB voltage */ | |
| +    int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); | |
| +}; | |
| + | |
| +#if defined(CONFIG_DVB_M88DS3103) || \ | |
| +	(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE)) | |
| +extern struct dvb_frontend *m88ds3103_attach( | |
| +       const struct m88ds3103_config *config, | |
| +       struct i2c_adapter *i2c); | |
| +#else | |
| +static inline struct dvb_frontend *m88ds3103_attach( | |
| +       const struct m88ds3103_config *config, | |
| +       struct i2c_adapter *i2c) | |
| +{ | |
| +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | |
| +	return NULL; | |
| +} | |
| +#endif /* CONFIG_DVB_M88DS3103 */ | |
| +#endif /* M88DS3103_H */ | |
| diff -urN a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h | |
| --- a/drivers/media/dvb-frontends/m88ds3103_priv.h	1970-01-01 08:00:00.000000000 +0800 | |
| +++ b/drivers/media/dvb-frontends/m88ds3103_priv.h	2013-01-30 12:33:56.000000000 +0800 | |
| @@ -0,0 +1,403 @@ | |
| +/* | |
| +    Montage Technology M88DS3103/M88TS2022 - DVBS/S2 Satellite demod/tuner driver | |
| + | |
| +    This program is free software; you can redistribute it and/or modify | |
| +    it under the terms of the GNU General Public License as published by | |
| +    the Free Software Foundation; either version 2 of the License, or | |
| +    (at your option) any later version. | |
| + | |
| +    This program is distributed in the hope that it will be useful, | |
| +    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| +    GNU General Public License for more details. | |
| + | |
| +    You should have received a copy of the GNU General Public License | |
| +    along with this program; if not, write to the Free Software | |
| +    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| + */ | |
| + | |
| +#ifndef M88DS3103_PRIV_H | |
| +#define M88DS3103_PRIV_H | |
| + | |
| +#define FW_DOWN_SIZE 32 | |
| +#define FW_DOWN_LOOP (8192/FW_DOWN_SIZE) | |
| +#define DS3103_DEFAULT_FIRMWARE "dvb-fe-ds3103.fw" | |
| +#define DS3000_DEFAULT_FIRMWARE "dvb-fe-ds300x.fw" | |
| +#define MT_FE_MCLK_KHZ 96000 /* in kHz */ | |
| +#define MT_FE_CRYSTAL_KHZ   27000 /* in kHz */ | |
| +#define FREQ_OFFSET_AT_SMALL_SYM_RATE_KHz 3000 | |
| +#define DS3000_ID	0x3000 | |
| +#define DS3103_ID	0x3103 | |
| +#define TS2020_ID	0x2020 | |
| +#define TS2022_ID	0x2022 | |
| +#define UNKNOW_ID	0x0000 | |
| + | |
| +struct m88ds3103_state { | |
| +	struct i2c_adapter *i2c; | |
| +	const struct m88ds3103_config *config; | |
| +	 | |
| +	struct dvb_frontend frontend; | |
| +	 | |
| +	u32 preBer; | |
| +	u8 skip_fw_load;	 | |
| +	u8 first_lock; /* The first time of signal lock */ | |
| +	u16 demod_id; /* demod chip type */ | |
| +	u16 tuner_id; /* tuner chip type */ | |
| +	fe_delivery_system_t delivery_system; | |
| +}; | |
| + | |
| +/* For M88DS3103 demod dvbs mode.*/ | |
| +static u8 ds3103_dvbs_init_tab[] = { | |
| +	0x23, 0x07, | |
| +	0x08, 0x03, | |
| +	0x0c, 0x02, | |
| +	0x21, 0x54, | |
| +	0x25, 0x82, | |
| +	0x27, 0x31, | |
| +	0x30, 0x08, | |
| +	0x31, 0x40, | |
| +	0x32, 0x32, | |
| +	0x33, 0x35, | |
| +	0x35, 0xff, | |
| +	0x3a, 0x00, | |
| +	0x37, 0x10, | |
| +	0x38, 0x10, | |
| +	0x39, 0x02, | |
| +	0x42, 0x60, | |
| +	0x4a, 0x80, | |
| +	0x4b, 0x04, | |
| +	0x4d, 0x91, | |
| +	0x5d, 0xc8, | |
| +	0x50, 0x36, | |
| +	0x51, 0x36, | |
| +	0x52, 0x36, | |
| +	0x53, 0x36, | |
| +	0x63, 0x0f, | |
| +	0x64, 0x30, | |
| +	0x65, 0x40, | |
| +	0x68, 0x26, | |
| +	0x69, 0x4c, | |
| +	0x70, 0x20, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x40, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x60, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x80, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0xa0, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x1f, | |
| +	0x76, 0x38, | |
| +	0x77, 0xa6, | |
| +	0x78, 0x0c, | |
| +	0x79, 0x80, | |
| +	0x7f, 0x14, | |
| +	0x7c, 0x00, | |
| +	0xae, 0x82, | |
| +	0x80, 0x64, | |
| +	0x81, 0x66, | |
| +	0x82, 0x44, | |
| +	0x85, 0x04, | |
| +	0xcd, 0xf4, | |
| +	0x90, 0x33, | |
| +	0xa0, 0x44, | |
| +	0xc0, 0x08, | |
| +	0xc3, 0x10, | |
| +	0xc4, 0x08, | |
| +	0xc5, 0xf0, | |
| +	0xc6, 0xff, | |
| +	0xc7, 0x00, | |
| +	0xc8, 0x1a, | |
| +	0xc9, 0x80, | |
| +	0xe0, 0xf8, | |
| +	0xe6, 0x8b, | |
| +	0xd0, 0x40, | |
| +	0xf8, 0x20, | |
| +	0xfa, 0x0f, | |
| +	0x00, 0x00, | |
| +	0xbd, 0x01, | |
| +	0xb8, 0x00, | |
| +}; | |
| +/* For M88DS3103 demod dvbs2 mode.*/ | |
| +static u8 ds3103_dvbs2_init_tab[] = { | |
| +	0x23, 0x07, | |
| +	0x08, 0x07, | |
| +	0x0c, 0x02, | |
| +	0x21, 0x54, | |
| +	0x25, 0x82, | |
| +	0x27, 0x31, | |
| +	0x30, 0x08, | |
| +	0x32, 0x32, | |
| +	0x33, 0x35, | |
| +	0x35, 0xff, | |
| +	0x3a, 0x00, | |
| +	0x37, 0x10, | |
| +	0x38, 0x10, | |
| +	0x39, 0x02, | |
| +	0x42, 0x60, | |
| +	0x4a, 0x80, | |
| +	0x4b, 0x04, | |
| +	0x4d, 0x91, | |
| +	0x5d, 0xc8, | |
| +	0x50, 0x36, | |
| +	0x51, 0x36, | |
| +	0x52, 0x36, | |
| +	0x53, 0x36, | |
| +	0x63, 0x0f, | |
| +	0x64, 0x10, | |
| +	0x65, 0x20, | |
| +	0x68, 0x46, | |
| +	0x69, 0xcd, | |
| +	0x70, 0x20, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x40, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x60, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x80, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0xa0, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x1f, | |
| +	0x76, 0x38, | |
| +	0x77, 0xa6, | |
| +	0x78, 0x0c, | |
| +	0x79, 0x80, | |
| +	0x7f, 0x14, | |
| +	0x85, 0x08, | |
| +	0xcd, 0xf4, | |
| +	0x90, 0x33, | |
| +	0x86, 0x00, | |
| +	0x87, 0x0f, | |
| +	0x89, 0x00, | |
| +	0x8b, 0x44, | |
| +	0x8c, 0x66, | |
| +	0x9d, 0xc1, | |
| +	0x8a, 0x10, | |
| +	0xad, 0x40, | |
| +	0xa0, 0x44, | |
| +	0xc0, 0x08, | |
| +	0xc1, 0x10, | |
| +	0xc2, 0x08, | |
| +	0xc3, 0x10, | |
| +	0xc4, 0x08, | |
| +	0xc5, 0xf0, | |
| +	0xc6, 0xff, | |
| +	0xc7, 0x00, | |
| +	0xc8, 0x1a, | |
| +	0xc9, 0x80, | |
| +	0xca, 0x23, | |
| +	0xcb, 0x24, | |
| +	0xcc, 0xf4, | |
| +	0xce, 0x74, | |
| +	0x00, 0x00, | |
| +	0xbd, 0x01, | |
| +	0xb8, 0x00, | |
| +}; | |
| + | |
| +/* For M88DS3000 demod dvbs mode.*/ | |
| +static u8 ds3000_dvbs_init_tab[] = { | |
| +	0x23, 0x05, | |
| +	0x08, 0x03, | |
| +	0x0c, 0x02, | |
| +	0x21, 0x54, | |
| +	0x25, 0x82, | |
| +	0x27, 0x31, | |
| +	0x30, 0x08, | |
| +	0x31, 0x40, | |
| +	0x32, 0x32, | |
| +	0x33, 0x35, | |
| +	0x35, 0xff, | |
| +	0x3a, 0x00, | |
| +	0x37, 0x10, | |
| +	0x38, 0x10, | |
| +	0x39, 0x02, | |
| +	0x42, 0x60, | |
| +	0x4a, 0x40, | |
| +	0x4b, 0x04, | |
| +	0x4d, 0x91, | |
| +	0x5d, 0xc8, | |
| +	0x50, 0x77, | |
| +	0x51, 0x77, | |
| +	0x52, 0x36, | |
| +	0x53, 0x36, | |
| +	0x56, 0x01, | |
| +	0x63, 0x47, | |
| +	0x64, 0x30, | |
| +	0x65, 0x40, | |
| +	0x68, 0x26, | |
| +	0x69, 0x4c, | |
| +	0x70, 0x20, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x40, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x60, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x80, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0xa0, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x1f, | |
| +	0x76, 0x00, | |
| +	0x77, 0xd1, | |
| +	0x78, 0x0c, | |
| +	0x79, 0x80, | |
| +	0x7f, 0x04, | |
| +	0x7c, 0x00, | |
| +	0x80, 0x86, | |
| +	0x81, 0xa6, | |
| +	0x85, 0x04, | |
| +	0xcd, 0xf4, | |
| +	0x90, 0x33, | |
| +	0xa0, 0x44, | |
| +	0xc0, 0x18, | |
| +	0xc3, 0x10, | |
| +	0xc4, 0x08, | |
| +	0xc5, 0x80, | |
| +	0xc6, 0x80, | |
| +	0xc7, 0x0a, | |
| +	0xc8, 0x1a, | |
| +	0xc9, 0x80, | |
| +	0xfe, 0xb6, | |
| +	0xe0, 0xf8, | |
| +	0xe6, 0x8b, | |
| +	0xd0, 0x40, | |
| +	0xf8, 0x20, | |
| +	0xfa, 0x0f, | |
| +	0xad, 0x20, | |
| +	0xae, 0x07, | |
| +	0xb8, 0x00, | |
| +}; | |
| + | |
| +/* For M88DS3000 demod dvbs2 mode.*/ | |
| +static u8 ds3000_dvbs2_init_tab[] = { | |
| +	0x23, 0x0f, | |
| +	0x08, 0x07, | |
| +	0x0c, 0x02, | |
| +	0x21, 0x54, | |
| +	0x25, 0x82, | |
| +	0x27, 0x31, | |
| +	0x30, 0x08, | |
| +	0x31, 0x32, | |
| +	0x32, 0x32, | |
| +	0x33, 0x35, | |
| +	0x35, 0xff, | |
| +	0x3a, 0x00, | |
| +	0x37, 0x10, | |
| +	0x38, 0x10, | |
| +	0x39, 0x02, | |
| +	0x42, 0x60, | |
| +	0x4a, 0x80, | |
| +	0x4b, 0x04, | |
| +	0x4d, 0x91, | |
| +	0x5d, 0x88, | |
| +	0x50, 0x36, | |
| +	0x51, 0x36, | |
| +	0x52, 0x36, | |
| +	0x53, 0x36, | |
| +	0x63, 0x60, | |
| +	0x64, 0x10, | |
| +	0x65, 0x10, | |
| +	0x68, 0x04, | |
| +	0x69, 0x29, | |
| +	0x70, 0x20, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x40, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x60, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x80, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0xa0, | |
| +	0x71, 0x70, | |
| +	0x72, 0x04, | |
| +	0x73, 0x00, | |
| +	0x70, 0x1f, | |
| +	0xa0, 0x44, | |
| +	0xc0, 0x08, | |
| +	0xc1, 0x10, | |
| +	0xc2, 0x08, | |
| +	0xc3, 0x10, | |
| +	0xc4, 0x08, | |
| +	0xc5, 0xf0, | |
| +	0xc6, 0xf0, | |
| +	0xc7, 0x0a, | |
| +	0xc8, 0x1a, | |
| +	0xc9, 0x80, | |
| +	0xca, 0x23, | |
| +	0xcb, 0x24, | |
| +	0xce, 0x74, | |
| +	0x56, 0x01, | |
| +	0x90, 0x03, | |
| +	0x76, 0x80, | |
| +	0x77, 0x42, | |
| +	0x78, 0x0a, | |
| +	0x79, 0x80, | |
| +	0xad, 0x40, | |
| +	0xae, 0x07, | |
| +	0x7f, 0xd4, | |
| +	0x7c, 0x00, | |
| +	0x80, 0xa8, | |
| +	0x81, 0xda, | |
| +	0x7c, 0x01, | |
| +	0x80, 0xda, | |
| +	0x81, 0xec, | |
| +	0x7c, 0x02, | |
| +	0x80, 0xca, | |
| +	0x81, 0xeb, | |
| +	0x7c, 0x03, | |
| +	0x80, 0xba, | |
| +	0x81, 0xdb, | |
| +	0x85, 0x08, | |
| +	0x86, 0x00, | |
| +	0x87, 0x02, | |
| +	0x89, 0x80, | |
| +	0x8b, 0x44, | |
| +	0x8c, 0xaa, | |
| +	0x8a, 0x10, | |
| +	0xba, 0x00, | |
| +	0xf5, 0x04, | |
| +	0xd2, 0x32, | |
| +	0xb8, 0x00, | |
| +}; | |
| + | |
| +#endif /* M88DS3103_PRIV_H */ | |
| diff -urN a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile | |
| --- a/drivers/media/dvb-frontends/Makefile	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/dvb-frontends/Makefile	2013-05-03 17:04:31.000000000 +0800 | |
| @@ -103,4 +103,5 @@ | |
|  obj-$(CONFIG_DVB_RTL2832) += rtl2832.o | |
|  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o | |
|  obj-$(CONFIG_DVB_AF9033) += af9033.o | |
| - | |
| +obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o | |
| +obj-$(CONFIG_DVB_M88DC2800) += m88dc2800.o | |
| diff -urN a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c | |
| --- a/drivers/media/pci/cx23885/cimax2.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/cimax2.c	2013-03-31 22:03:29.000000000 +0800 | |
| @@ -415,7 +415,7 @@ | |
|  	return state->status; | |
|  } | |
|   | |
| -int netup_ci_init(struct cx23885_tsport *port) | |
| +int netup_ci_init(struct cx23885_tsport *port, bool isDVBSky) | |
|  { | |
|  	struct netup_ci_state *state; | |
|  	u8 cimax_init[34] = { | |
| @@ -464,6 +464,11 @@ | |
|  		goto err; | |
|  	} | |
|   | |
| +	if(isDVBSky) { | |
| +		cimax_init[32] = 0x22; | |
| +		cimax_init[33] = 0x00; | |
| +	} | |
| + | |
|  	port->port_priv = state; | |
|   | |
|  	switch (port->nr) { | |
| @@ -537,3 +542,19 @@ | |
|  	dvb_ca_en50221_release(&state->ca); | |
|  	kfree(state); | |
|  } | |
| + | |
| +/* CI irq handler for DVBSky board*/ | |
| +int dvbsky_ci_slot_status(struct cx23885_dev *dev) | |
| +{ | |
| +	struct cx23885_tsport *port = NULL; | |
| +	struct netup_ci_state *state = NULL; | |
| + | |
| +	ci_dbg_print("%s:\n", __func__); | |
| + | |
| +	port = &dev->ts1; | |
| +	state = port->port_priv; | |
| +	schedule_work(&state->work); | |
| +	ci_dbg_print("%s: Wakeup CI0\n", __func__); | |
| + | |
| +	return 1; | |
| +} | |
| diff -urN a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h | |
| --- a/drivers/media/pci/cx23885/cimax2.h	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/cimax2.h	2013-01-30 12:34:37.000000000 +0800 | |
| @@ -41,7 +41,9 @@ | |
|  extern int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status); | |
|  extern int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, | |
|  						int slot, int open); | |
| -extern int netup_ci_init(struct cx23885_tsport *port); | |
| +extern int netup_ci_init(struct cx23885_tsport *port, bool isDVBSky); | |
|  extern void netup_ci_exit(struct cx23885_tsport *port); | |
|   | |
| +extern int dvbsky_ci_slot_status(struct cx23885_dev *dev); | |
| + | |
|  #endif | |
| diff -urN a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c | |
| --- a/drivers/media/pci/cx23885/cx23885-cards.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/cx23885-cards.c	2013-05-03 17:34:46.000000000 +0800 | |
| @@ -569,6 +569,34 @@ | |
|  		.name		= "TeVii S471", | |
|  		.portb		= CX23885_MPEG_DVB, | |
|  	}, | |
| +	[CX23885_BOARD_BST_PS8512] = { | |
| +		.name		= "Bestunar PS8512", | |
| +		.portb		= CX23885_MPEG_DVB, | |
| +	}, | |
| +	[CX23885_BOARD_DVBSKY_S950] = { | |
| +		.name		= "DVBSKY S950", | |
| +		.portb		= CX23885_MPEG_DVB, | |
| +	}, | |
| +	[CX23885_BOARD_DVBSKY_S952] = { | |
| +		.name		= "DVBSKY S952", | |
| +		.portb		= CX23885_MPEG_DVB, | |
| +		.portc		= CX23885_MPEG_DVB, | |
| +	}, | |
| +	[CX23885_BOARD_DVBSKY_S950_CI] = { | |
| +		.ci_type	= 3, | |
| +		.name		= "DVBSKY S950CI DVB-S2 CI", | |
| +		.portb		= CX23885_MPEG_DVB, | |
| +	}, | |
| +	[CX23885_BOARD_DVBSKY_C2800E_CI] = { | |
| +		.ci_type	= 3, | |
| +		.name		= "DVBSKY C2800E DVB-C CI", | |
| +		.portb		= CX23885_MPEG_DVB, | |
| +	}, | |
| +	[CX23885_BOARD_DVBSKY_T9580] = { | |
| +		.name		= "DVBSKY T9580", | |
| +		.portb		= CX23885_MPEG_DVB, | |
| +		.portc		= CX23885_MPEG_DVB, | |
| +	}, | |
|  	[CX23885_BOARD_PROF_8000] = { | |
|  		.name		= "Prof Revolution DVB-S2 8000", | |
|  		.portb		= CX23885_MPEG_DVB, | |
| @@ -605,7 +633,7 @@ | |
|  				  CX25840_NONE1_CH3, | |
|  			.amux   = CX25840_AUDIO6, | |
|  		} }, | |
| -	} | |
| +	}	 | |
|  }; | |
|  const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); | |
|   | |
| @@ -818,6 +846,30 @@ | |
|  		.subdevice = 0x9022, | |
|  		.card      = CX23885_BOARD_TEVII_S471, | |
|  	}, { | |
| +		.subvendor = 0x14f1, | |
| +		.subdevice = 0x8512, | |
| +		.card      = CX23885_BOARD_BST_PS8512, | |
| +	}, { | |
| +		.subvendor = 0x4254, | |
| +		.subdevice = 0x0950, | |
| +		.card      = CX23885_BOARD_DVBSKY_S950,		 | |
| +	}, { | |
| +		.subvendor = 0x4254, | |
| +		.subdevice = 0x0952, | |
| +		.card      = CX23885_BOARD_DVBSKY_S952, | |
| +	}, { | |
| +		.subvendor = 0x4254, | |
| +		.subdevice = 0x950C, | |
| +		.card      = CX23885_BOARD_DVBSKY_S950_CI, | |
| +	}, { | |
| +		.subvendor = 0x4254, | |
| +		.subdevice = 0x2800, | |
| +		.card      = CX23885_BOARD_DVBSKY_C2800E_CI, | |
| +	}, { | |
| +		.subvendor = 0x4254, | |
| +		.subdevice = 0x9580, | |
| +		.card      = CX23885_BOARD_DVBSKY_T9580, | |
| +	}, { | |
|  		.subvendor = 0x8000, | |
|  		.subdevice = 0x3034, | |
|  		.card      = CX23885_BOARD_PROF_8000, | |
| @@ -1224,7 +1276,7 @@ | |
|  		cx_set(GP0_IO, 0x00040004); | |
|  		break; | |
|  	case CX23885_BOARD_TBS_6920: | |
| -	case CX23885_BOARD_PROF_8000: | |
| +	case CX23885_BOARD_PROF_8000:	 | |
|  		cx_write(MC417_CTL, 0x00000036); | |
|  		cx_write(MC417_OEN, 0x00001000); | |
|  		cx_set(MC417_RWD, 0x00000002); | |
| @@ -1394,9 +1446,84 @@ | |
|  		cx_set(GP0_IO, 0x00040004); | |
|  		mdelay(60); | |
|  		break; | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_BST_PS8512:			 | |
| +		cx23885_gpio_enable(dev, GPIO_2, 1); | |
| +		cx23885_gpio_clear(dev, GPIO_2); | |
| +		msleep(100);		 | |
| +		cx23885_gpio_set(dev, GPIO_2); | |
| +		break; | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
| +		cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ | |
| +		 | |
| +		cx23885_gpio_enable(dev, GPIO_2, 1); | |
| +		cx23885_gpio_enable(dev, GPIO_11, 1); | |
| +		 | |
| +		cx23885_gpio_clear(dev, GPIO_2); | |
| +		cx23885_gpio_clear(dev, GPIO_11); | |
| +		msleep(100);		 | |
| +		cx23885_gpio_set(dev, GPIO_2); | |
| +		cx23885_gpio_set(dev, GPIO_11);	 | |
| +		break; | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +		/* GPIO-0 INTA from CiMax, input | |
| +		   GPIO-1 reset CiMax, output, high active | |
| +		   GPIO-2 reset demod, output, low active | |
| +		   GPIO-3 to GPIO-10 data/addr for CAM | |
| +		   GPIO-11 ~CS0 to CiMax1 | |
| +		   GPIO-12 ~CS1 to CiMax2 | |
| +		   GPIO-13 ADL0 load LSB addr | |
| +		   GPIO-14 ADL1 load MSB addr | |
| +		   GPIO-15 ~RDY from CiMax | |
| +		   GPIO-17 ~RD to CiMax | |
| +		   GPIO-18 ~WR to CiMax | |
| +		 */ | |
| +		cx_set(GP0_IO, 0x00060002); /* GPIO 1/2 as output */ | |
| +		cx_clear(GP0_IO, 0x00010004); /*GPIO 0 as input*/ | |
| +		mdelay(100);/* reset delay */ | |
| +		cx_set(GP0_IO, 0x00060004); /* GPIO as out, reset high */ | |
| +		cx_clear(GP0_IO, 0x00010002); | |
| +		cx_write(MC417_CTL, 0x00000037);/* enable GPIO3-18 pins */ | |
| +		/* GPIO-15 IN as ~ACK, rest as OUT */ | |
| +		cx_write(MC417_OEN, 0x00001000); | |
| +		/* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */ | |
| +		cx_write(MC417_RWD, 0x0000c300); | |
| +		/* enable irq */ | |
| +		cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ | |
| +		break; | |
|  	} | |
|  } | |
|   | |
| +static int cx23885_ir_patch(struct i2c_adapter *i2c, u8 reg, u8 mask) | |
| +{ | |
| +	struct i2c_msg msgs[2]; | |
| +	u8 tx_buf[2], rx_buf[1]; | |
| +	/* Write register address */ | |
| +	tx_buf[0] = reg; | |
| +	msgs[0].addr = 0x4c; | |
| +	msgs[0].flags = 0; | |
| +	msgs[0].len = 1; | |
| +	msgs[0].buf = (char *) tx_buf; | |
| +	/* Read data from register */ | |
| +	msgs[1].addr = 0x4c; | |
| +	msgs[1].flags = I2C_M_RD; | |
| +	msgs[1].len = 1; | |
| +	msgs[1].buf = (char *) rx_buf;	 | |
| +	 | |
| +	i2c_transfer(i2c, msgs, 2); | |
| + | |
| +	tx_buf[0] = reg; | |
| +	tx_buf[1] = rx_buf[0] | mask; | |
| +	msgs[0].addr = 0x4c; | |
| +	msgs[0].flags = 0; | |
| +	msgs[0].len = 2; | |
| +	msgs[0].buf = (char *) tx_buf; | |
| +	 | |
| +	return i2c_transfer(i2c, msgs, 1); | |
| +} | |
| + | |
|  int cx23885_ir_init(struct cx23885_dev *dev) | |
|  { | |
|  	static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = { | |
| @@ -1482,6 +1609,23 @@ | |
|  		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | |
|  				 ir_rx_pin_cfg_count, ir_rx_pin_cfg); | |
|  		break; | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
| +		dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE); | |
| +		if (dev->sd_ir == NULL) { | |
| +			ret = -ENODEV; | |
| +			break; | |
| +		} | |
| +		v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config, | |
| +				 ir_rx_pin_cfg_count, ir_rx_pin_cfg); | |
| +				  | |
| +		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x1f,0x80); | |
| +		cx23885_ir_patch(&(dev->i2c_bus[2].i2c_adap),0x23,0x80); | |
| +		break; | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1250: | |
|  		if (!enable_885_ir) | |
|  			break; | |
| @@ -1511,9 +1655,15 @@ | |
|  		cx23888_ir_remove(dev); | |
|  		dev->sd_ir = NULL; | |
|  		break; | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +	case CX23885_BOARD_DVBSKY_T9580:		 | |
|  	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | |
|  	case CX23885_BOARD_TEVII_S470: | |
| -	case CX23885_BOARD_HAUPPAUGE_HVR1250: | |
| +	case CX23885_BOARD_HAUPPAUGE_HVR1250:	 | |
|  	case CX23885_BOARD_MYGICA_X8507: | |
|  		cx23885_irq_remove(dev, PCI_MSK_AV_CORE); | |
|  		/* sd_ir is a duplicate pointer to the AV Core, just clear it */ | |
| @@ -1556,6 +1706,12 @@ | |
|  		if (dev->sd_ir) | |
|  			cx23885_irq_add_enable(dev, PCI_MSK_IR); | |
|  		break; | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +	case CX23885_BOARD_DVBSKY_T9580:		 | |
|  	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | |
|  	case CX23885_BOARD_TEVII_S470: | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1250: | |
| @@ -1657,6 +1813,10 @@ | |
|  		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
|  		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
|  		break; | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
|  	case CX23885_BOARD_TEVII_S470: | |
|  	case CX23885_BOARD_TEVII_S471: | |
|  	case CX23885_BOARD_DVBWORLD_2005: | |
| @@ -1694,6 +1854,22 @@ | |
|  		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
|  		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
|  		break; | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +		ts1->gen_ctrl_val  = 0x5; /* Parallel */ | |
| +		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
| +		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
| +		ts2->gen_ctrl_val  = 0xe; /* Serial bus + punctured clock */ | |
| +		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
| +		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
| +		break; | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
| +		ts1->gen_ctrl_val  = 0x5; /* Parallel */ | |
| +		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
| +		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
| +		ts2->gen_ctrl_val  = 0x8; /* Serial bus */ | |
| +		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ | |
| +		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; | |
| +		break;		 | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1250: | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1500: | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1500Q: | |
| @@ -1749,6 +1925,12 @@ | |
|  	case CX23885_BOARD_MPX885: | |
|  	case CX23885_BOARD_MYGICA_X8507: | |
|  	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
|  	case CX23885_BOARD_AVERMEDIA_HC81R: | |
|  		dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, | |
|  				&dev->i2c_bus[2].i2c_adap, | |
| diff -urN a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c | |
| --- a/drivers/media/pci/cx23885/cx23885-core.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/cx23885-core.c	2013-05-03 17:36:31.000000000 +0800 | |
| @@ -1909,6 +1909,10 @@ | |
|  			(pci_status & PCI_MSK_GPIO0)) | |
|  		handled += altera_ci_irq(dev); | |
|   | |
| +	if (cx23885_boards[dev->board].ci_type == 3 && | |
| +			(pci_status & PCI_MSK_GPIO0)) | |
| +		handled += dvbsky_ci_slot_status(dev); | |
| +		 | |
|  	if (ts1_status) { | |
|  		if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) | |
|  			handled += cx23885_irq_ts(ts1, ts1_status); | |
| @@ -2144,6 +2148,8 @@ | |
|  		cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0); | |
|  		break; | |
|  	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
|  		cx23885_irq_add_enable(dev, PCI_MSK_GPIO0); | |
|  		break; | |
|  	} | |
| diff -urN a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c | |
| --- a/drivers/media/pci/cx23885/cx23885-dvb.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/cx23885-dvb.c	2013-05-03 17:38:34.000000000 +0800 | |
| @@ -51,6 +51,8 @@ | |
|  #include "stv6110.h" | |
|  #include "lnbh24.h" | |
|  #include "cx24116.h" | |
| +#include "m88ds3103.h" | |
| +#include "m88dc2800.h" | |
|  #include "cimax2.h" | |
|  #include "lgs8gxx.h" | |
|  #include "netup-eeprom.h" | |
| @@ -64,8 +66,8 @@ | |
|  #include "stv0367.h" | |
|  #include "drxk.h" | |
|  #include "mt2063.h" | |
| -#include "stv090x.h" | |
| -#include "stb6100.h" | |
| +#include "stv090x.h" | |
| +#include "stb6100.h" | |
|  #include "stb6100_cfg.h" | |
|  #include "tda10071.h" | |
|  #include "a8293.h" | |
| @@ -500,42 +502,130 @@ | |
|  	.if_khz = 5380, | |
|  }; | |
|   | |
| -static struct stv090x_config prof_8000_stv090x_config = { | |
| -	.device                 = STV0903, | |
| -	.demod_mode             = STV090x_SINGLE, | |
| -	.clk_mode               = STV090x_CLK_EXT, | |
| -	.xtal                   = 27000000, | |
| -	.address                = 0x6A, | |
| -	.ts1_mode               = STV090x_TSMODE_PARALLEL_PUNCTURED, | |
| -	.repeater_level         = STV090x_RPTLEVEL_64, | |
| -	.adc1_range             = STV090x_ADC_2Vpp, | |
| -	.diseqc_envelope_mode   = false, | |
| - | |
| -	.tuner_get_frequency    = stb6100_get_frequency, | |
| -	.tuner_set_frequency    = stb6100_set_frequency, | |
| -	.tuner_set_bandwidth    = stb6100_set_bandwidth, | |
| -	.tuner_get_bandwidth    = stb6100_get_bandwidth, | |
| -}; | |
|   | |
| -static struct stb6100_config prof_8000_stb6100_config = { | |
| -	.tuner_address = 0x60, | |
| -	.refclock = 27000000, | |
| -}; | |
| - | |
| -static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |
| +/* bst control */ | |
| +int bst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |
|  { | |
|  	struct cx23885_tsport *port = fe->dvb->priv; | |
|  	struct cx23885_dev *dev = port->dev; | |
| +	 | |
| +	cx23885_gpio_enable(dev, GPIO_1, 1); | |
| +	cx23885_gpio_enable(dev, GPIO_0, 1); | |
| + | |
| +	switch (voltage) { | |
| +	case SEC_VOLTAGE_13: | |
| +		cx23885_gpio_set(dev, GPIO_1); | |
| +		cx23885_gpio_clear(dev, GPIO_0); | |
| +		break; | |
| +	case SEC_VOLTAGE_18: | |
| +		cx23885_gpio_set(dev, GPIO_1); | |
| +		cx23885_gpio_set(dev, GPIO_0); | |
| +		break; | |
| +	case SEC_VOLTAGE_OFF: | |
| +		cx23885_gpio_clear(dev, GPIO_1); | |
| +		cx23885_gpio_clear(dev, GPIO_0); | |
| +		break; | |
| +	} | |
| +	return 0; | |
| +} | |
|   | |
| -	if (voltage == SEC_VOLTAGE_18) | |
| -		cx_write(MC417_RWD, 0x00001e00); | |
| -	else if (voltage == SEC_VOLTAGE_13) | |
| -		cx_write(MC417_RWD, 0x00001a00); | |
| -	else | |
| -		cx_write(MC417_RWD, 0x00001800); | |
| +int dvbsky_set_voltage_sec(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |
| +{ | |
| +	struct cx23885_tsport *port = fe->dvb->priv; | |
| +	struct cx23885_dev *dev = port->dev; | |
| +	 | |
| +	cx23885_gpio_enable(dev, GPIO_12, 1); | |
| +	cx23885_gpio_enable(dev, GPIO_13, 1); | |
| + | |
| +	switch (voltage) { | |
| +	case SEC_VOLTAGE_13: | |
| +		cx23885_gpio_set(dev, GPIO_13); | |
| +		cx23885_gpio_clear(dev, GPIO_12); | |
| +		break; | |
| +	case SEC_VOLTAGE_18: | |
| +		cx23885_gpio_set(dev, GPIO_13); | |
| +		cx23885_gpio_set(dev, GPIO_12); | |
| +		break; | |
| +	case SEC_VOLTAGE_OFF: | |
| +		cx23885_gpio_clear(dev, GPIO_13); | |
| +		cx23885_gpio_clear(dev, GPIO_12); | |
| +		break; | |
| +	} | |
|  	return 0; | |
|  } | |
|   | |
| +/* bestunar single dvb-s2 */ | |
| +static struct m88ds3103_config bst_ds3103_config = { | |
| +	.demod_address = 0x68, | |
| +	.ci_mode = 0, | |
| +	.pin_ctrl = 0x82, | |
| +	.ts_mode = 0, | |
| +	.set_voltage = bst_set_voltage, | |
| +}; | |
| +/* DVBSKY dual dvb-s2 */ | |
| +static struct m88ds3103_config dvbsky_ds3103_config_pri = { | |
| +	.demod_address = 0x68, | |
| +	.ci_mode = 0, | |
| +	.pin_ctrl = 0x82, | |
| +	.ts_mode = 0, | |
| +	.set_voltage = bst_set_voltage,	 | |
| +}; | |
| +static struct m88ds3103_config dvbsky_ds3103_config_sec = { | |
| +	.demod_address = 0x68, | |
| +	.ci_mode = 0, | |
| +	.pin_ctrl = 0x82, | |
| +	.ts_mode = 1, | |
| +	.set_voltage = dvbsky_set_voltage_sec,	 | |
| +}; | |
| + | |
| +static struct m88ds3103_config dvbsky_ds3103_ci_config = { | |
| +	.demod_address = 0x68, | |
| +	.ci_mode = 2, | |
| +	.pin_ctrl = 0x82, | |
| +	.ts_mode = 0, | |
| +}; | |
| + | |
| +static struct m88dc2800_config dvbsky_dc2800_config = { | |
| +	.demod_address = 0x1c, | |
| +	.ts_mode = 3,	 | |
| +}; | |
| + | |
| +static struct stv090x_config prof_8000_stv090x_config = { | |
| +        .device                 = STV0903, | |
| +        .demod_mode             = STV090x_SINGLE, | |
| +        .clk_mode               = STV090x_CLK_EXT, | |
| +        .xtal                   = 27000000, | |
| +        .address                = 0x6A, | |
| +        .ts1_mode               = STV090x_TSMODE_PARALLEL_PUNCTURED, | |
| +        .repeater_level         = STV090x_RPTLEVEL_64, | |
| +        .adc1_range             = STV090x_ADC_2Vpp, | |
| +        .diseqc_envelope_mode   = false, | |
| + | |
| +        .tuner_get_frequency    = stb6100_get_frequency, | |
| +        .tuner_set_frequency    = stb6100_set_frequency, | |
| +        .tuner_set_bandwidth    = stb6100_set_bandwidth, | |
| +        .tuner_get_bandwidth    = stb6100_get_bandwidth, | |
| +}; | |
| + | |
| +static struct stb6100_config prof_8000_stb6100_config = { | |
| +	.tuner_address = 0x60, | |
| +	.refclock = 27000000, | |
| +}; | |
| + | |
| +static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |
| +{ | |
| +	struct cx23885_tsport *port = fe->dvb->priv; | |
| +	struct cx23885_dev *dev = port->dev; | |
| + | |
| +	if (voltage == SEC_VOLTAGE_18) | |
| +		cx_write(MC417_RWD, 0x00001e00); | |
| +	else if (voltage == SEC_VOLTAGE_13) | |
| +		cx_write(MC417_RWD, 0x00001a00); | |
| +	else | |
| +		cx_write(MC417_RWD, 0x00001800); | |
| +	return 0; | |
| +} | |
| + | |
|  static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) | |
|  { | |
|  	struct dtv_frontend_properties *p = &fe->dtv_property_cache; | |
| @@ -1250,23 +1340,79 @@ | |
|  					&tevii_ds3000_config, | |
|  					&i2c_bus->i2c_adap); | |
|  		break; | |
| -	case CX23885_BOARD_PROF_8000: | |
| -		i2c_bus = &dev->i2c_bus[0]; | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +		i2c_bus = &dev->i2c_bus[1];	 | |
| +		fe0->dvb.frontend = dvb_attach(m88ds3103_attach, | |
| +					&bst_ds3103_config, | |
| +					&i2c_bus->i2c_adap); | |
| +		break;	 | |
| +			 | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +		switch (port->nr) { | |
| +		/* port B */ | |
| +		case 1: | |
| +			i2c_bus = &dev->i2c_bus[1]; | |
| +			fe0->dvb.frontend = dvb_attach(m88ds3103_attach, | |
| +						&dvbsky_ds3103_config_pri, | |
| +						&i2c_bus->i2c_adap); | |
| +			break; | |
| +		/* port C */ | |
| +		case 2: | |
| +			i2c_bus = &dev->i2c_bus[0]; | |
| +			fe0->dvb.frontend = dvb_attach(m88ds3103_attach, | |
| +						&dvbsky_ds3103_config_sec, | |
| +						&i2c_bus->i2c_adap);	 | |
| +			break; | |
| +		} | |
| +		break; | |
|   | |
| -		fe0->dvb.frontend = dvb_attach(stv090x_attach, | |
| -						&prof_8000_stv090x_config, | |
| -						&i2c_bus->i2c_adap, | |
| -						STV090x_DEMODULATOR_0); | |
| -		if (fe0->dvb.frontend != NULL) { | |
| -			if (!dvb_attach(stb6100_attach, | |
| -					fe0->dvb.frontend, | |
| -					&prof_8000_stb6100_config, | |
| -					&i2c_bus->i2c_adap)) | |
| -				goto frontend_detach; | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +		i2c_bus = &dev->i2c_bus[1];	 | |
| +		fe0->dvb.frontend = dvb_attach(m88ds3103_attach, | |
| +					&dvbsky_ds3103_ci_config, | |
| +					&i2c_bus->i2c_adap); | |
| +		break; | |
| +				 | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +		i2c_bus = &dev->i2c_bus[1];	 | |
| +		fe0->dvb.frontend = dvb_attach(m88dc2800_attach, | |
| +					&dvbsky_dc2800_config, | |
| +					&i2c_bus->i2c_adap); | |
| +		break; | |
|   | |
| -			fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage; | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
| +		switch (port->nr) { | |
| +		/* port B */ | |
| +		case 1: | |
| +			i2c_bus = &dev->i2c_bus[1]; | |
| +			fe0->dvb.frontend = dvb_attach(m88ds3103_attach, | |
| +						&dvbsky_ds3103_config_pri, | |
| +						&i2c_bus->i2c_adap); | |
| +			break; | |
| +		/* port C */ | |
| +		case 2: | |
| +			break; | |
|  		} | |
|  		break; | |
| +				 | |
| +	case CX23885_BOARD_PROF_8000: | |
| +		i2c_bus = &dev->i2c_bus[0]; | |
| + | |
| +		fe0->dvb.frontend = dvb_attach(stv090x_attach, | |
| +						&prof_8000_stv090x_config, | |
| +						&i2c_bus->i2c_adap, | |
| +						STV090x_DEMODULATOR_0); | |
| +		if (fe0->dvb.frontend != NULL) { | |
| +			if (!dvb_attach(stb6100_attach, | |
| +					fe0->dvb.frontend, | |
| +					&prof_8000_stb6100_config, | |
| +					&i2c_bus->i2c_adap)) | |
| +				goto frontend_detach; | |
| + | |
| +			fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage; | |
| +		} | |
| +		break; | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR4400: | |
|  		i2c_bus = &dev->i2c_bus[0]; | |
|  		fe0->dvb.frontend = dvb_attach(tda10071_attach, | |
| @@ -1325,7 +1471,7 @@ | |
|  		printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", | |
|  			port->nr, port->frontends.adapter.proposed_mac); | |
|   | |
| -		netup_ci_init(port); | |
| +		netup_ci_init(port, false); | |
|  		break; | |
|  		} | |
|  	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { | |
| @@ -1352,6 +1498,41 @@ | |
|  		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); | |
|  		break; | |
|  		} | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_T9580:{ | |
| +		u8 eeprom[256]; /* 24C02 i2c eeprom */ | |
| + | |
| +		if(port->nr > 2) | |
| +			break; | |
| + | |
| +		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; | |
| +		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); | |
| +		printk(KERN_INFO "DVBSKY PCIe MAC= %pM\n", eeprom + 0xc0+(port->nr-1)*8); | |
| +		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +  | |
| +			(port->nr-1)*8, 6); | |
| +		break; | |
| +		} | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: { | |
| +		u8 eeprom[256]; /* 24C02 i2c eeprom */ | |
| + | |
| +		if(port->nr > 2) | |
| +			break; | |
| + | |
| +		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; | |
| +		tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); | |
| +		printk(KERN_INFO "DVBSKY PCIe MAC= %pM\n", eeprom + 0xc0+(port->nr-1)*8); | |
| +		memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +  | |
| +			(port->nr-1)*8, 6); | |
| +			 | |
| +		netup_ci_init(port, true); | |
| +		break; | |
| +		} | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: { | |
| +		netup_ci_init(port, true); | |
| +		break; | |
| +		}		 | |
|  	} | |
|   | |
|  	return ret; | |
| @@ -1434,6 +1615,8 @@ | |
|   | |
|  	switch (port->dev->board) { | |
|  	case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
|  		netup_ci_exit(port); | |
|  		break; | |
|  	case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: | |
| diff -urN a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h | |
| --- a/drivers/media/pci/cx23885/cx23885.h	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/cx23885.h	2013-05-03 17:14:20.000000000 +0800 | |
| @@ -94,6 +94,14 @@ | |
|  #define CX23885_BOARD_HAUPPAUGE_HVR4400        38 | |
|  #define CX23885_BOARD_AVERMEDIA_HC81R          39 | |
|   | |
| +#define CX23885_BOARD_BASE_INDEX	       40 | |
| +#define CX23885_BOARD_BST_PS8512	       (CX23885_BOARD_BASE_INDEX) | |
| +#define CX23885_BOARD_DVBSKY_S952	       (CX23885_BOARD_BASE_INDEX+1) | |
| +#define CX23885_BOARD_DVBSKY_S950	       (CX23885_BOARD_BASE_INDEX+2) | |
| +#define CX23885_BOARD_DVBSKY_S950_CI	       (CX23885_BOARD_BASE_INDEX+3) | |
| +#define CX23885_BOARD_DVBSKY_C2800E_CI	       (CX23885_BOARD_BASE_INDEX+4) | |
| +#define CX23885_BOARD_DVBSKY_T9580	       (CX23885_BOARD_BASE_INDEX+5) | |
| + | |
|  #define GPIO_0 0x00000001 | |
|  #define GPIO_1 0x00000002 | |
|  #define GPIO_2 0x00000004 | |
| @@ -231,7 +239,7 @@ | |
|  	 */ | |
|  	u32			clk_freq; | |
|  	struct cx23885_input    input[MAX_CX23885_INPUT]; | |
| -	int			ci_type; /* for NetUP */ | |
| +	int			ci_type; /* 1 and 2 for NetUP, 3 for DVBSky. */ | |
|  	/* Force bottom field first during DMA (888 workaround) */ | |
|  	u32                     force_bff; | |
|  }; | |
| diff -urN a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c | |
| --- a/drivers/media/pci/cx23885/cx23885-input.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/cx23885-input.c	2013-05-03 17:42:09.000000000 +0800 | |
| @@ -89,6 +89,12 @@ | |
|  	case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: | |
|  	case CX23885_BOARD_TEVII_S470: | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1250: | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
|  	case CX23885_BOARD_MYGICA_X8507: | |
|  		/* | |
|  		 * The only boards we handle right now.  However other boards | |
| @@ -141,6 +147,12 @@ | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1850: | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1290: | |
|  	case CX23885_BOARD_HAUPPAUGE_HVR1250: | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
|  	case CX23885_BOARD_MYGICA_X8507: | |
|  		/* | |
|  		 * The IR controller on this board only returns pulse widths. | |
| @@ -291,6 +303,18 @@ | |
|  		/* A guess at the remote */ | |
|  		rc_map = RC_MAP_TEVII_NEC; | |
|  		break; | |
| +	case CX23885_BOARD_BST_PS8512: | |
| +	case CX23885_BOARD_DVBSKY_S950: | |
| +	case CX23885_BOARD_DVBSKY_S952: | |
| +	case CX23885_BOARD_DVBSKY_S950_CI: | |
| +	case CX23885_BOARD_DVBSKY_C2800E_CI: | |
| +	case CX23885_BOARD_DVBSKY_T9580: | |
| +		/* Integrated CX2388[58] IR controller */ | |
| +		driver_type = RC_DRIVER_IR_RAW; | |
| +		allowed_protos = RC_BIT_ALL; | |
| +		/* A guess at the remote */ | |
| +		rc_map = RC_MAP_DVBSKY; | |
| +		break; | |
|  	case CX23885_BOARD_MYGICA_X8507: | |
|  		/* Integrated CX23885 IR controller */ | |
|  		driver_type = RC_DRIVER_IR_RAW; | |
| diff -urN a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig | |
| --- a/drivers/media/pci/cx23885/Kconfig	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx23885/Kconfig	2013-05-03 17:43:05.000000000 +0800 | |
| @@ -23,6 +23,8 @@ | |
|  	select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT | |
| +	select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT | |
| +	select DVB_M88DC2800 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT | |
| diff -urN a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c | |
| --- a/drivers/media/pci/cx88/cx88-cards.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx88/cx88-cards.c	2013-05-03 17:06:55.000000000 +0800 | |
| @@ -2309,6 +2309,18 @@ | |
|  		} }, | |
|  		.mpeg           = CX88_MPEG_DVB, | |
|  	}, | |
| +	[CX88_BOARD_BST_PS8312] = { | |
| +		.name           = "Bestunar PS8312 DVB-S/S2", | |
| +		.tuner_type     = UNSET, | |
| +		.radio_type     = UNSET, | |
| +		.tuner_addr     = ADDR_UNSET, | |
| +		.radio_addr     = ADDR_UNSET, | |
| +		.input          = { { | |
| +			.type   = CX88_VMUX_DVB, | |
| +			.vmux   = 0, | |
| +		} }, | |
| +		.mpeg           = CX88_MPEG_DVB, | |
| +	}, | |
|  }; | |
|   | |
|  /* ------------------------------------------------------------------ */ | |
| @@ -2813,6 +2825,10 @@ | |
|  		.subvendor = 0x1822, | |
|  		.subdevice = 0x0023, | |
|  		.card      = CX88_BOARD_TWINHAN_VP1027_DVBS, | |
| +	}, { | |
| +		.subvendor = 0x14f1, | |
| +		.subdevice = 0x8312, | |
| +		.card      = CX88_BOARD_BST_PS8312, | |
|  	}, | |
|  }; | |
|   | |
| @@ -3547,6 +3563,12 @@ | |
|  		cx_write(MO_SRST_IO, 1); | |
|  		msleep(100); | |
|  		break; | |
| +	case  CX88_BOARD_BST_PS8312: | |
| +		cx_write(MO_GP1_IO, 0x808000); | |
| +		msleep(100); | |
| +		cx_write(MO_GP1_IO, 0x808080); | |
| +		msleep(100); | |
| +		break; | |
|  	} /*end switch() */ | |
|   | |
|   | |
| diff -urN a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c | |
| --- a/drivers/media/pci/cx88/cx88-dvb.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx88/cx88-dvb.c	2013-05-03 17:09:09.000000000 +0800 | |
| @@ -54,6 +54,7 @@ | |
|  #include "stv0288.h" | |
|  #include "stb6000.h" | |
|  #include "cx24116.h" | |
| +#include "m88ds3103.h" | |
|  #include "stv0900.h" | |
|  #include "stb6100.h" | |
|  #include "stb6100_proc.h" | |
| @@ -459,6 +460,56 @@ | |
|  		return core->prev_set_voltage(fe, voltage); | |
|  	return 0; | |
|  } | |
| +/*CX88_BOARD_BST_PS8312*/ | |
| +static int bst_dvbs_set_voltage(struct dvb_frontend *fe, | |
| +				      fe_sec_voltage_t voltage) | |
| +{ | |
| +	struct cx8802_dev *dev= fe->dvb->priv; | |
| +	struct cx88_core *core = dev->core; | |
| + | |
| +	cx_write(MO_GP1_IO, 0x111111); | |
| +	switch (voltage) { | |
| +		case SEC_VOLTAGE_13: | |
| +			cx_write(MO_GP1_IO, 0x020200); | |
| +			break; | |
| +		case SEC_VOLTAGE_18: | |
| +			cx_write(MO_GP1_IO, 0x020202); | |
| +			break; | |
| +		case SEC_VOLTAGE_OFF: | |
| +			cx_write(MO_GP1_IO, 0x111100); | |
| +			break; | |
| +	} | |
| + | |
| +	if (core->prev_set_voltage) | |
| +		return core->prev_set_voltage(fe, voltage); | |
| +	return 0; | |
| +} | |
| + | |
| +static int bst_dvbs_set_voltage_v2(struct dvb_frontend *fe, | |
| +				      fe_sec_voltage_t voltage) | |
| +{ | |
| +	struct cx8802_dev *dev= fe->dvb->priv; | |
| +	struct cx88_core *core = dev->core; | |
| + | |
| +	cx_write(MO_GP1_IO, 0x111101); | |
| +	switch (voltage) { | |
| +		case SEC_VOLTAGE_13: | |
| +			cx_write(MO_GP1_IO, 0x020200); | |
| +			break; | |
| +		case SEC_VOLTAGE_18: | |
| + | |
| +			cx_write(MO_GP1_IO, 0x020202); | |
| +			break; | |
| +		case SEC_VOLTAGE_OFF: | |
| + | |
| +			cx_write(MO_GP1_IO, 0x111110); | |
| +			break; | |
| +	} | |
| + | |
| +	if (core->prev_set_voltage) | |
| +		return core->prev_set_voltage(fe, voltage); | |
| +	return 0; | |
| +} | |
|   | |
|  static int vp1027_set_voltage(struct dvb_frontend *fe, | |
|  				    fe_sec_voltage_t voltage) | |
| @@ -706,6 +757,11 @@ | |
|  	.clk_out_div = 1, | |
|  }; | |
|   | |
| +static struct m88ds3103_config dvbsky_ds3103_config = { | |
| +	.demod_address = 0x68, | |
| +	.set_ts_params = ds3000_set_ts_param, | |
| +}; | |
| + | |
|  static const struct stv0900_config prof_7301_stv0900_config = { | |
|  	.demod_address = 0x6a, | |
|  /*	demod_mode = 0,*/ | |
| @@ -1477,6 +1533,35 @@ | |
|  				&tevii_ts2020_config, &core->i2c_adap); | |
|  			fe0->dvb.frontend->ops.set_voltage = | |
|  							tevii_dvbs_set_voltage; | |
| +                }		 | |
| +                break; | |
| +	case CX88_BOARD_BST_PS8312: | |
| +		fe0->dvb.frontend = dvb_attach(m88ds3103_attach, | |
| +						&dvbsky_ds3103_config, | |
| +						&core->i2c_adap); | |
| +		if (fe0->dvb.frontend != NULL){ | |
| +			int ret; | |
| +			u8 b0[] = { 0x60 }; | |
| +			u8 b1[2] = { 0 }; | |
| +			struct i2c_msg msg[] = { | |
| +				{ | |
| +				.addr = 0x50, | |
| +				.flags = 0, | |
| +				.buf = b0, | |
| +				.len = 1 | |
| +				}, { | |
| +				.addr = 0x50, | |
| +				.flags = I2C_M_RD, | |
| +				.buf = b1, | |
| +				.len = 2 | |
| +				} | |
| +			}; | |
| +			ret = i2c_transfer(&core->i2c_adap, msg, 2); | |
| +			printk("PS8312: config = %02x, %02x", b1[0],b1[1]); | |
| +			if(b1[0] == 0xaa) | |
| +				fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage_v2; | |
| +			else			 | |
| +				fe0->dvb.frontend->ops.set_voltage = bst_dvbs_set_voltage; | |
|  		} | |
|  		break; | |
|  	case CX88_BOARD_OMICOM_SS4_PCI: | |
| diff -urN a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h | |
| --- a/drivers/media/pci/cx88/cx88.h	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx88/cx88.h	2013-05-03 17:05:57.000000000 +0800 | |
| @@ -238,6 +238,7 @@ | |
|  #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 | |
|  #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89 | |
|  #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90 | |
| +#define CX88_BOARD_BST_PS8312              91 | |
|   | |
|  enum cx88_itype { | |
|  	CX88_VMUX_COMPOSITE1 = 1, | |
| diff -urN a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c | |
| --- a/drivers/media/pci/cx88/cx88-input.c	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx88/cx88-input.c	2013-01-26 14:52:03.000000000 +0800 | |
| @@ -419,6 +419,10 @@ | |
|  		rc_type          = RC_BIT_NEC; | |
|  		ir->sampling     = 0xff00; /* address */ | |
|  		break; | |
| +	case CX88_BOARD_BST_PS8312: | |
| +		ir_codes         = RC_MAP_DVBSKY; | |
| +		ir->sampling     = 0xff00; /* address */ | |
| +		break; | |
|  	} | |
|   | |
|  	if (!ir_codes) { | |
| diff -urN a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig | |
| --- a/drivers/media/pci/cx88/Kconfig	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/pci/cx88/Kconfig	2013-05-03 17:10:41.000000000 +0800 | |
| @@ -57,6 +57,7 @@ | |
|  	select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT | |
| +	select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT | |
|  	select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT | |
| diff -urN a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile | |
| --- a/drivers/media/rc/keymaps/Makefile	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/rc/keymaps/Makefile	2013-05-03 17:43:41.000000000 +0800 | |
| @@ -27,6 +27,7 @@ | |
|  			rc-dm1105-nec.o \ | |
|  			rc-dntv-live-dvb-t.o \ | |
|  			rc-dntv-live-dvbt-pro.o \ | |
| +			rc-dvbsky.o \ | |
|  			rc-em-terratec.o \ | |
|  			rc-encore-enltv2.o \ | |
|  			rc-encore-enltv.o \ | |
| diff -urN a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c | |
| --- a/drivers/media/rc/keymaps/rc-dvbsky.c	1970-01-01 08:00:00.000000000 +0800 | |
| +++ b/drivers/media/rc/keymaps/rc-dvbsky.c	2013-01-26 14:52:49.000000000 +0800 | |
| @@ -0,0 +1,78 @@ | |
| +/* rc-dvbsky.c - Keytable for Dvbsky Remote Controllers | |
| + * | |
| + * keymap imported from ir-keymaps.c | |
| + * | |
| + * | |
| + * Copyright (c) 2010-2012 by Nibble Max <nibble.max@gmail.com> | |
| + * | |
| + * This program is free software; you can redistribute it and/or modify | |
| + * it under the terms of the GNU General Public License as published by | |
| + * the Free Software Foundation; either version 2 of the License, or | |
| + * (at your option) any later version. | |
| + */ | |
| + | |
| +#include <media/rc-map.h> | |
| +#include <linux/module.h> | |
| +/* | |
| + * This table contains the complete RC5 code, instead of just the data part | |
| + */ | |
| + | |
| +static struct rc_map_table rc5_dvbsky[] = { | |
| +	{ 0x0000, KEY_0 }, | |
| +	{ 0x0001, KEY_1 }, | |
| +	{ 0x0002, KEY_2 }, | |
| +	{ 0x0003, KEY_3 }, | |
| +	{ 0x0004, KEY_4 }, | |
| +	{ 0x0005, KEY_5 }, | |
| +	{ 0x0006, KEY_6 }, | |
| +	{ 0x0007, KEY_7 }, | |
| +	{ 0x0008, KEY_8 }, | |
| +	{ 0x0009, KEY_9 }, | |
| +	{ 0x000a, KEY_MUTE }, | |
| +	{ 0x000d, KEY_OK }, | |
| +	{ 0x000b, KEY_STOP }, | |
| +	{ 0x000c, KEY_EXIT }, | |
| +	{ 0x000e, KEY_CAMERA }, /*Snap shot*/ | |
| +	{ 0x000f, KEY_SUBTITLE }, /*PIP*/ | |
| +	{ 0x0010, KEY_VOLUMEUP }, | |
| +	{ 0x0011, KEY_VOLUMEDOWN }, | |
| +	{ 0x0012, KEY_FAVORITES }, | |
| +	{ 0x0013, KEY_LIST }, /*Info*/ | |
| +	{ 0x0016, KEY_PAUSE }, | |
| +	{ 0x0017, KEY_PLAY }, | |
| +	{ 0x001f, KEY_RECORD }, | |
| +	{ 0x0020, KEY_CHANNELDOWN }, | |
| +	{ 0x0021, KEY_CHANNELUP }, | |
| +	{ 0x0025, KEY_POWER2 }, | |
| +	{ 0x0026, KEY_REWIND }, | |
| +	{ 0x0027, KEY_FASTFORWARD }, | |
| +	{ 0x0029, KEY_LAST }, | |
| +	{ 0x002b, KEY_MENU }, | |
| +	{ 0x002c, KEY_EPG }, | |
| +	{ 0x002d, KEY_ZOOM }, | |
| +}; | |
| + | |
| +static struct rc_map_list rc5_dvbsky_map = { | |
| +	.map = { | |
| +		.scan    = rc5_dvbsky, | |
| +		.size    = ARRAY_SIZE(rc5_dvbsky), | |
| +		.rc_type = RC_TYPE_RC5, | |
| +		.name    = RC_MAP_DVBSKY, | |
| +	} | |
| +}; | |
| + | |
| +static int __init init_rc_map_rc5_dvbsky(void) | |
| +{ | |
| +	return rc_map_register(&rc5_dvbsky_map); | |
| +} | |
| + | |
| +static void __exit exit_rc_map_rc5_dvbsky(void) | |
| +{ | |
| +	rc_map_unregister(&rc5_dvbsky_map); | |
| +} | |
| + | |
| +module_init(init_rc_map_rc5_dvbsky) | |
| +module_exit(exit_rc_map_rc5_dvbsky) | |
| + | |
| +MODULE_LICENSE("GPL"); | |
| +MODULE_AUTHOR("Nibble Max <nibble.max@gmail.com>"); | |
| diff -urN a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c | |
| --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c	1970-01-01 08:00:00.000000000 +0800 | |
| +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c	2013-05-03 17:47:38.000000000 +0800 | |
| @@ -0,0 +1,1032 @@ | |
| +/* | |
| + * Driver for DVBSky USB2.0 receiver | |
| + * | |
| + * Copyright (C) 2013 Max nibble <nibble.max@gmail.com> | |
| + * | |
| + * CIMax code is copied and modified from: | |
| + * CIMax2(R) SP2 driver in conjunction with NetUp Dual DVB-S2 CI card | |
| + * Copyright (C) 2009 NetUP Inc. | |
| + * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> | |
| + * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> | |
| + * | |
| + *    This program is free software; you can redistribute it and/or modify | |
| + *    it under the terms of the GNU General Public License as published by | |
| + *    the Free Software Foundation; either version 2 of the License, or | |
| + *    (at your option) any later version. | |
| + * | |
| + *    This program is distributed in the hope that it will be useful, | |
| + *    but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
| + *    GNU General Public License for more details. | |
| + * | |
| + *    You should have received a copy of the GNU General Public License | |
| + *    along with this program; if not, write to the Free Software | |
| + *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| + */ | |
| + | |
| +#include "dvb_ca_en50221.h" | |
| +#include "dvb_usb.h" | |
| +#include "m88ds3103.h" | |
| +#include "si2168.h" | |
| +#include "si2157.h" | |
| + | |
| +#define DVBSKY_MSG_DELAY	0/*2000*/ | |
| +#define DVBSKY_BUF_LEN	64 | |
| + | |
| +static int dvbsky_debug; | |
| +module_param(dvbsky_debug, int, 0644); | |
| +MODULE_PARM_DESC(dvbsky_debug, "Activates dvbsky usb debugging (default:0)"); | |
| + | |
| +#define DVBSKY_CI_CTL		0x04 | |
| +#define DVBSKY_CI_RD		1 | |
| + | |
| +#define dprintk(args...) \ | |
| +	do { \ | |
| +		if (dvbsky_debug) \ | |
| +			printk(KERN_INFO "dvbsky_usb: " args); \ | |
| +	} while (0) | |
| + | |
| +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |
| + | |
| +struct dvbsky_state { | |
| +	struct mutex stream_mutex; | |
| +	u8 has_ci; | |
| +	u8 ci_attached; | |
| +	struct i2c_client *i2c_client_demod; | |
| +	struct i2c_client *i2c_client_tuner; | |
| +	struct i2c_client *i2c_client_ci; | |
| +	struct dvb_ca_en50221 ci; | |
| +	unsigned long next_status_checked_time; | |
| +	u8 ci_i2c_addr; | |
| +	u8 current_ci_flag; | |
| +	int ci_status; | |
| +}; | |
| + | |
| +static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff) | |
| +{ | |
| +	struct dvbsky_state *state = d_to_priv(d); | |
| +	int ret; | |
| +	u8 obuf_pre[3] = { 0x37, 0, 0 }; | |
| +	u8 obuf_post[3] = { 0x36, 3, 0 }; | |
| +	dprintk("%s() -off \n", __func__); | |
| +	mutex_lock(&state->stream_mutex); | |
| +	ret = dvb_usbv2_generic_write(d, obuf_pre, 3); | |
| +	if (!ret && onoff) { | |
| +		msleep(10); | |
| +		ret = dvb_usbv2_generic_write(d, obuf_post, 3); | |
| +		dprintk("%s() -on \n", __func__); | |
| +	} | |
| +	mutex_unlock(&state->stream_mutex); | |
| +	return ret; | |
| +} | |
| + | |
| +/* CI opertaions */ | |
| +static int dvbsky_ci_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, | |
| +						u8 *buf, int len) | |
| +{ | |
| +	int ret; | |
| +	struct i2c_msg msg[] = { | |
| +		{ | |
| +			.addr	= addr, | |
| +			.flags	= 0, | |
| +			.buf	= ®, | |
| +			.len	= 1 | |
| +		}, { | |
| +			.addr	= addr, | |
| +			.flags	= I2C_M_RD, | |
| +			.buf	= buf, | |
| +			.len	= len | |
| +		} | |
| +	}; | |
| +	 | |
| +	ret = i2c_transfer(i2c_adap, msg, 2); | |
| +	 | |
| +	if (ret != 2) { | |
| +		dprintk("%s: error, Reg = 0x%02x, Status = %d\n", __func__, reg, ret); | |
| +		return -1; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int dvbsky_ci_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, | |
| +						u8 *buf, int len) | |
| +{ | |
| +	int ret; | |
| +	u8 buffer[len + 1]; | |
| + | |
| +	struct i2c_msg msg = { | |
| +		.addr	= addr, | |
| +		.flags	= 0, | |
| +		.buf	= &buffer[0], | |
| +		.len	= len + 1 | |
| +	}; | |
| + | |
| +	buffer[0] = reg; | |
| +	memcpy(&buffer[1], buf, len); | |
| + | |
| +	ret = i2c_transfer(i2c_adap, &msg, 1); | |
| + | |
| +	if (ret != 1) { | |
| +		dprintk("%s: error, Reg=[0x%02x], Status=%d\n", __func__, reg, ret); | |
| +		return -1; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int dvbsky_ci_op_cam(struct dvb_ca_en50221 *ci, int slot, | |
| +				u8 flag, u8 read, int addr, u8 data) | |
| +{ | |
| +	struct dvb_usb_device *d = ci->data; | |
| +	struct dvbsky_state *state = d_to_priv(d);	 | |
| +	u8 store; | |
| +	int ret; | |
| +	u8 command[4], respond[2], command_size, respond_size; | |
| + | |
| +	/*dprintk("%s()\n", __func__);*/ | |
| +	if (0 != slot) | |
| +		return -EINVAL; | |
| + | |
| +	if (state->current_ci_flag != flag) { | |
| +		ret = dvbsky_ci_read_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +				0, &store, 1); | |
| +		if (ret != 0) | |
| +			return ret; | |
| + | |
| +		store &= ~0x0c; | |
| +		store |= flag; | |
| + | |
| +		ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +				0, &store, 1); | |
| +		if (ret != 0) | |
| +			return ret; | |
| +	} | |
| +	state->current_ci_flag = flag; | |
| + | |
| +	command[1] = (u8)((addr >> 8) & 0xff); /*high part of address*/ | |
| +	command[2] = (u8)(addr & 0xff); /*low part of address*/ | |
| +	if (read) { | |
| +		command[0] = 0x71; | |
| +		command_size = 3; | |
| +		respond_size = 2; | |
| +	} else { | |
| +		command[0] = 0x70; | |
| +		command[3] = data; | |
| +		command_size = 4; | |
| +		respond_size = 1; | |
| +	} | |
| +	ret = dvb_usbv2_generic_rw(d, command, command_size, respond, respond_size); | |
| + | |
| +	return (read) ? respond[1] : 0; | |
| +} | |
| + | |
| +static int dvbsky_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, | |
| +						int slot, int addr) | |
| +{ | |
| +	return dvbsky_ci_op_cam(ci, slot, 0, DVBSKY_CI_RD, addr, 0); | |
| +} | |
| + | |
| +static int dvbsky_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, | |
| +						int slot, int addr, u8 data) | |
| +{ | |
| +	return dvbsky_ci_op_cam(ci, slot, 0, 0, addr, data); | |
| +} | |
| + | |
| +static int dvbsky_ci_read_cam_ctl(struct dvb_ca_en50221 *ci, int slot, u8 addr) | |
| +{ | |
| +	return dvbsky_ci_op_cam(ci, slot, DVBSKY_CI_CTL, DVBSKY_CI_RD, addr, 0); | |
| +} | |
| + | |
| +static int dvbsky_ci_write_cam_ctl(struct dvb_ca_en50221 *ci, int slot, | |
| +							u8 addr, u8 data) | |
| +{ | |
| +	return dvbsky_ci_op_cam(ci, slot, DVBSKY_CI_CTL, 0, addr, data); | |
| +} | |
| + | |
| +static int dvbsky_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) | |
| +{ | |
| +	struct dvb_usb_device *d = ci->data; | |
| +	struct dvbsky_state *state = d_to_priv(d); | |
| +	u8 buf =  0x80; | |
| +	int ret; | |
| +	dprintk("%s() slot=%d\n", __func__, slot); | |
| + | |
| +	if (0 != slot) | |
| +		return -EINVAL; | |
| + | |
| +	udelay(500); | |
| +	ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +							0, &buf, 1); | |
| + | |
| +	if (ret != 0) | |
| +		return ret; | |
| + | |
| +	udelay(500); | |
| + | |
| +	buf = 0x00; | |
| +	ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +							0, &buf, 1); | |
| +	msleep(1000); | |
| +	dprintk("%s() slot=%d complete\n", __func__, slot); | |
| +	return 0; | |
| + | |
| +} | |
| + | |
| +static int dvbsky_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) | |
| +{ | |
| +	/* not implemented */ | |
| +	dprintk("%s()\n", __func__); | |
| +	return 0; | |
| +} | |
| + | |
| +static int dvbsky_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) | |
| +{ | |
| +	struct dvb_usb_device *d = ci->data; | |
| +	struct dvbsky_state *state = d_to_priv(d); | |
| +	u8 buf; | |
| +	int ret; | |
| + | |
| +	dprintk("%s()\n", __func__); | |
| +	if (0 != slot) | |
| +		return -EINVAL; | |
| + | |
| +	dvbsky_ci_read_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +			0, &buf, 1); | |
| +	buf |= 0x60; | |
| + | |
| +	ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +							0, &buf, 1); | |
| +	return ret; | |
| +} | |
| + | |
| +static int dvbsky_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, | |
| +	int open) | |
| +{ | |
| +	struct dvb_usb_device *d = ci->data; | |
| +	struct dvbsky_state *state = d_to_priv(d); | |
| +	int ret = 0; | |
| +	u8 buf = 0; | |
| +	/*dprintk("%s()\n", __func__);*/ | |
| + | |
| +	/* CAM module INSERT/REMOVE processing. slow operation because of i2c | |
| +	 * transfers */ | |
| +	if (time_after(jiffies, state->next_status_checked_time)) { | |
| +		ret = dvbsky_ci_read_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +				0, &buf, 1); | |
| + | |
| +		/*dprintk("%s() status=%x\n", __func__, buf);*/ | |
| +		 | |
| +		state->next_status_checked_time = jiffies | |
| +			+ msecs_to_jiffies(1000); | |
| + | |
| +		if (ret != 0) | |
| +			return 0; | |
| + | |
| +		if (buf & 1) { | |
| +			state->ci_status = DVB_CA_EN50221_POLL_CAM_PRESENT | | |
| +				DVB_CA_EN50221_POLL_CAM_READY; | |
| +		} | |
| +		else | |
| +			state->ci_status = 0; | |
| +	} | |
| +	/*dprintk("%s() ret=%x\n", __func__, state->ci_status);*/ | |
| +	return state->ci_status; | |
| +} | |
| + | |
| +static int dvbsky_ci_init(struct dvb_usb_device *d) | |
| +{ | |
| +	struct dvbsky_state *state = d_to_priv(d); | |
| +	int ret; | |
| +	u8 cimax_init[34] = { | |
| +		0x00, /* module A control*/ | |
| +		0x00, /* auto select mask high A */ | |
| +		0x00, /* auto select mask low A */ | |
| +		0x00, /* auto select pattern high A */ | |
| +		0x00, /* auto select pattern low A */ | |
| +		0x44, /* memory access time A */ | |
| +		0x00, /* invert input A */ | |
| +		0x00, /* RFU */ | |
| +		0x00, /* RFU */ | |
| +		0x00, /* module B control*/ | |
| +		0x00, /* auto select mask high B */ | |
| +		0x00, /* auto select mask low B */ | |
| +		0x00, /* auto select pattern high B */ | |
| +		0x00, /* auto select pattern low B */ | |
| +		0x44, /* memory access time B */ | |
| +		0x00, /* invert input B */ | |
| +		0x00, /* RFU */ | |
| +		0x00, /* RFU */ | |
| +		0x00, /* auto select mask high Ext */ | |
| +		0x00, /* auto select mask low Ext */ | |
| +		0x00, /* auto select pattern high Ext */ | |
| +		0x00, /* auto select pattern low Ext */ | |
| +		0x00, /* RFU */ | |
| +		0x02, /* destination - module A */ | |
| +		0x01, /* power on (use it like store place) */ | |
| +		0x00, /* RFU */ | |
| +		0x00, /* int status read only */ | |
| +		0x00, /* Max: Disable the interrupt in USB solution.*/ | |
| +		0x05, /* EXTINT=active-high, INT=push-pull */ | |
| +		0x00, /* USCG1 */ | |
| +		0x04, /* ack active low */ | |
| +		0x00, /* LOCK = 0 */ | |
| +		0x22, /* serial mode, rising in, rising out, MSB first*/ | |
| +		0x00  /* synchronization */ | |
| +	};	 | |
| +	dprintk("%s()\n", __func__); | |
| +	state->current_ci_flag = 0xff; | |
| +	state->ci_status = 0; | |
| +	state->next_status_checked_time = jiffies + msecs_to_jiffies(1000); | |
| +	state->ci_i2c_addr = 0x40; | |
| + | |
| +	state->ci.owner               = THIS_MODULE; | |
| +	state->ci.read_attribute_mem  = dvbsky_ci_read_attribute_mem; | |
| +	state->ci.write_attribute_mem = dvbsky_ci_write_attribute_mem; | |
| +	state->ci.read_cam_control    = dvbsky_ci_read_cam_ctl; | |
| +	state->ci.write_cam_control   = dvbsky_ci_write_cam_ctl; | |
| +	state->ci.slot_reset          = dvbsky_ci_slot_reset; | |
| +	state->ci.slot_shutdown       = dvbsky_ci_slot_shutdown; | |
| +	state->ci.slot_ts_enable      = dvbsky_ci_slot_ts_enable; | |
| +	state->ci.poll_slot_status    = dvbsky_ci_poll_slot_status; | |
| +	state->ci.data                = d; | |
| + | |
| +	ret = dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +						0, &cimax_init[0], 34); | |
| +	/* lock registers */ | |
| +	ret |= dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +						0x1f, &cimax_init[0x18], 1); | |
| +	/* power on slots */ | |
| +	ret |= dvbsky_ci_write_i2c(&d->i2c_adap, state->ci_i2c_addr, | |
| +						0x18, &cimax_init[0x18], 1); | |
| +	if (0 != ret) | |
| +		return ret; | |
| +		 | |
| +	ret = dvb_ca_en50221_init(&d->adapter[0].dvb_adap, &state->ci, 0, 1); | |
| +	if (ret) | |
| +		return ret; | |
| +	state->ci_attached = 1; | |
| +	dprintk("%s() complete.\n", __func__); | |
| +	return 0; | |
| +} | |
| + | |
| +static void dvbsky_ci_release(struct dvb_usb_device *d) | |
| +{ | |
| +	struct dvbsky_state *state = d_to_priv(d); | |
| + | |
| +	/* detach CI */ | |
| +	if (state->ci_attached) | |
| +		dvb_ca_en50221_release(&state->ci); | |
| + | |
| +	return; | |
| +} | |
| + | |
| +static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff) | |
| +{ | |
| +	struct dvb_usb_device *d = fe_to_d(fe); | |
| +	/*dprintk("%s() %d\n", __func__, onoff);*/ | |
| +	return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1); | |
| +} | |
| + | |
| +/* GPIO */ | |
| +static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value) | |
| +{ | |
| +	u8 obuf[64], ibuf[64]; | |
| +	obuf[0] = 0x0e; | |
| +	obuf[1] = gport; | |
| +	obuf[2] = value; | |
| +	return dvb_usbv2_generic_rw(d, obuf, 3, ibuf, 1); | |
| +} | |
| + | |
| +/* I2C */ | |
| +static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |
| +	int num) | |
| +{ | |
| +	struct dvb_usb_device *d = i2c_get_adapdata(adap); | |
| +	int ret = 0; | |
| +	u8 ibuf[64], obuf[64];  | |
| + | |
| +	if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | |
| +		return -EAGAIN; | |
| + | |
| +	if (num > 2) { | |
| +		printk(KERN_ERR "dvbsky_usb: too many i2c messages[%d] than 2.", num); | |
| +		ret = -EOPNOTSUPP; | |
| +		goto i2c_error; | |
| +	} | |
| +		 | |
| +	if(num == 1) { | |
| +		if (msg[0].len > 60) { | |
| +			printk(KERN_ERR "dvbsky_usb: too many i2c bytes[%d] than 60.", msg[0].len); | |
| +			ret = -EOPNOTSUPP; | |
| +			goto i2c_error; | |
| +		} | |
| +		if (msg[0].flags & I2C_M_RD) { | |
| +			/* single read */ | |
| +			obuf[0] = 0x09; | |
| +			obuf[1] = 0; | |
| +			obuf[2] = msg[0].len; | |
| +			obuf[3] = msg[0].addr; | |
| +			ret = dvb_usbv2_generic_rw(d, obuf, 4, ibuf, msg[0].len + 1); | |
| +			/*dprintk("%s(): read status = %d\n", __func__, ibuf[0]);*/ | |
| +			if (!ret) | |
| +				memcpy(msg[0].buf, &ibuf[1], msg[0].len); | |
| +		} else { | |
| +			/* write */ | |
| +			obuf[0] = 0x08; | |
| +			obuf[1] = msg[0].addr; | |
| +			obuf[2] = msg[0].len; | |
| +			memcpy(&obuf[3], msg[0].buf, msg[0].len); | |
| +			ret = dvb_usbv2_generic_rw(d, obuf, msg[0].len + 3, ibuf, 1); | |
| +			/*dprintk("%s(): write status = %d\n", __func__, ibuf[0]);*/ | |
| +		} | |
| +	} else { | |
| +		if ((msg[0].len > 60) || (msg[1].len > 60)) { | |
| +			printk(KERN_ERR "dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.", msg[0].len, msg[1].len); | |
| +			ret = -EOPNOTSUPP; | |
| +			goto i2c_error; | |
| +		} | |
| +		/* write then read */ | |
| +		obuf[0] = 0x09; | |
| +		obuf[1] = msg[0].len; | |
| +		obuf[2] = msg[1].len; | |
| +		obuf[3] = msg[0].addr; | |
| +		memcpy(&obuf[4], msg[0].buf, msg[0].len); | |
| +		ret = dvb_usbv2_generic_rw(d, obuf, msg[0].len + 4, ibuf, msg[1].len + 1); | |
| +		/*dprintk("%s(): write then read status = %d\n", __func__, ibuf[0]);*/ | |
| +		if (!ret) | |
| +			memcpy(msg[1].buf, &ibuf[1], msg[1].len); | |
| +	} | |
| +i2c_error: | |
| +	mutex_unlock(&d->i2c_mutex); | |
| +	return (ret) ? ret : num; | |
| +} | |
| + | |
| +static u32 dvbsky_i2c_func(struct i2c_adapter *adapter) | |
| +{ | |
| +	return I2C_FUNC_I2C; | |
| +} | |
| + | |
| +static struct i2c_algorithm dvbsky_i2c_algo = { | |
| +	.master_xfer   = dvbsky_i2c_xfer, | |
| +	.functionality = dvbsky_i2c_func, | |
| +}; | |
| + | |
| +#if IS_ENABLED(CONFIG_RC_CORE) | |
| +static int dvbsky_rc_query(struct dvb_usb_device *d) | |
| +{ | |
| +	u32 code = 0xffff; | |
| +	u8 obuf[2], ibuf[2], toggle; | |
| +	int ret; | |
| +	obuf[0] = 0x10; | |
| +	ret = dvb_usbv2_generic_rw(d, obuf, 1, ibuf, 2); | |
| +	if(ret == 0) | |
| +		code = (ibuf[0] << 8) | ibuf[1]; | |
| + | |
| +	if (code != 0xffff) { | |
| +		dprintk("rc code: %x", code); | |
| +		toggle = (code & 0x800) ? 1 : 0; | |
| +		code &= 0x3f; | |
| +		rc_keydown(d->rc_dev, code, toggle); | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | |
| +{ | |
| +	rc->allowed_protos = RC_BIT_RC5; | |
| +	rc->query          = dvbsky_rc_query; | |
| +	rc->interval       = 300; | |
| +	return 0; | |
| +} | |
| +#else | |
| +	#define dvbsky_get_rc_config NULL | |
| +#endif | |
| + | |
| +static int dvbsky_sync_ctrl(struct dvb_frontend *fe) | |
| +{ | |
| +	struct dvb_usb_device *d = fe_to_d(fe); | |
| +	return dvbsky_stream_ctrl(d, 1); | |
| +} | |
| + | |
| +static int dvbsky_usb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | |
| +{ | |
| +	struct dvb_usb_device *d = fe_to_d(fe); | |
| +	u8 value; | |
| + | |
| +	if (voltage == SEC_VOLTAGE_OFF) | |
| +		value = 0; | |
| +	else | |
| +		value = 1; | |
| +	return dvbsky_gpio_ctrl(d, 0x80, value); | |
| +} | |
| + | |
| +static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6]) | |
| +{ | |
| +	struct dvb_usb_device *d = adap_to_d(adap); | |
| +	u8 obuf[] = { 0x1e, 0x00 }; | |
| +	u8 ibuf[6] = { 0 }; | |
| +	struct i2c_msg msg[] = { | |
| +		{ | |
| +			.addr = 0x51, | |
| +			.flags = 0, | |
| +			.buf = obuf, | |
| +			.len = 2, | |
| +		}, { | |
| +			.addr = 0x51, | |
| +			.flags = I2C_M_RD, | |
| +			.buf = ibuf, | |
| +			.len = 6, | |
| + | |
| +		} | |
| +	}; | |
| +	 | |
| +	if (i2c_transfer(&d->i2c_adap, msg, 2) == 2) | |
| +		memcpy(mac, ibuf, 6); | |
| + | |
| +	printk(KERN_INFO "dvbsky_usb MAC address=%pM\n", mac); | |
| +	 | |
| +	return 0; | |
| +} | |
| + | |
| +static struct m88ds3103_config dvbsky_usb_ds3103_config = { | |
| +	.demod_address = 0x68, | |
| +	.ci_mode = 1, | |
| +	.pin_ctrl = 0x83, | |
| +	.ts_mode = 0, | |
| +	.start_ctrl = dvbsky_sync_ctrl, | |
| +	.set_voltage = dvbsky_usb_set_voltage, | |
| +}; | |
| + | |
| +static int dvbsky_s960_attach(struct dvb_usb_adapter *adap) | |
| +{ | |
| +	struct dvbsky_state *state = adap_to_priv(adap); | |
| +	struct dvb_usb_device *d = adap_to_d(adap); | |
| +	int ret = 0; | |
| +	 | |
| +	dprintk("%s()\n", __func__); | |
| + | |
| +	dvbsky_gpio_ctrl(d, 0x04, 1); | |
| +		 | |
| +	dvbsky_gpio_ctrl(d, 0x83, 0); | |
| +	msleep(50); | |
| +	dvbsky_gpio_ctrl(d, 0x83, 1); | |
| +	msleep(20); | |
| +	 | |
| +	adap->fe[0] = dvb_attach(m88ds3103_attach, | |
| +				&dvbsky_usb_ds3103_config, | |
| +				&d->i2c_adap); | |
| +	if (!adap->fe[0]) { | |
| +		printk(KERN_ERR "dvbsky_s960_attach fail."); | |
| +		ret = -ENODEV; | |
| +	} | |
| +	 | |
| +	state->has_ci = 0; | |
| + | |
| +	return ret; | |
| +} | |
| + | |
| +static int dvbsky_t330_attach(struct dvb_usb_adapter *adap) | |
| +{ | |
| +	struct dvbsky_state *state = adap_to_priv(adap); | |
| +	struct dvb_usb_device *d = adap_to_d(adap); | |
| +	int ret = 0; | |
| +	struct i2c_adapter *i2c_adapter; | |
| +	struct i2c_client *client_demod, *client_tuner; | |
| +	struct i2c_board_info info; | |
| +	struct si2168_config si2168_config; | |
| +	struct si2157_config si2157_config; | |
| + | |
| +	/* attach demod */ | |
| +	memset(&si2168_config, 0, sizeof(si2168_config)); | |
| +	si2168_config.i2c_adapter = &i2c_adapter; | |
| +	si2168_config.fe = &adap->fe[0]; | |
| +	si2168_config.ts_mode = SI2168_TS_PARALLEL | 0x40; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2168", I2C_NAME_SIZE); | |
| +	info.addr = 0x64; | |
| +	info.platform_data = &si2168_config; | |
| + | |
| +	request_module(info.type); | |
| +	client_demod = i2c_new_device(&d->i2c_adap, &info); | |
| +	if (client_demod == NULL || | |
| +			client_demod->dev.driver == NULL) | |
| +		goto fail_demod_device; | |
| +	if (!try_module_get(client_demod->dev.driver->owner)) | |
| +		goto fail_demod_module; | |
| + | |
| +	/* attach tuner */ | |
| +	memset(&si2157_config, 0, sizeof(si2157_config)); | |
| +	si2157_config.fe = adap->fe[0]; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2157", I2C_NAME_SIZE); | |
| +	info.addr = 0x60; | |
| +	info.platform_data = &si2157_config; | |
| + | |
| +	request_module(info.type); | |
| +	client_tuner = i2c_new_device(i2c_adapter, &info); | |
| +	if (client_tuner == NULL || | |
| +			client_tuner->dev.driver == NULL) | |
| +		goto fail_tuner_device; | |
| +	if (!try_module_get(client_tuner->dev.driver->owner)) | |
| +		goto fail_tuner_module; | |
| + | |
| +	state->i2c_client_demod = client_demod; | |
| +	state->i2c_client_tuner = client_tuner; | |
| +	return ret; | |
| +fail_tuner_module: | |
| +	i2c_unregister_device(client_tuner); | |
| +fail_tuner_device: | |
| +	module_put(client_demod->dev.driver->owner); | |
| +fail_demod_module: | |
| +	i2c_unregister_device(client_demod); | |
| +fail_demod_device: | |
| +	ret = -ENODEV; | |
| +	return ret; | |
| +} | |
| + | |
| +static int dvbsky_t230_attach(struct dvb_usb_adapter *adap) | |
| +{ | |
| +	struct dvbsky_state *state = adap_to_priv(adap); | |
| +	struct dvb_usb_device *d = adap_to_d(adap); | |
| +	int ret = 0; | |
| +	struct i2c_adapter *i2c_adapter; | |
| +	struct i2c_client *client_demod, *client_tuner; | |
| +	struct i2c_board_info info; | |
| +	struct si2168_config si2168_config; | |
| +	struct si2157_config si2157_config; | |
| + | |
| +	/* attach demod */ | |
| +	memset(&si2168_config, 0, sizeof(si2168_config)); | |
| +	si2168_config.i2c_adapter = &i2c_adapter; | |
| +	si2168_config.fe = &adap->fe[0]; | |
| +	si2168_config.ts_mode = SI2168_TS_PARALLEL; | |
| +	si2168_config.ts_clock_inv = true; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2168", I2C_NAME_SIZE); | |
| +	info.addr = 0x64; | |
| +	info.platform_data = &si2168_config; | |
| + | |
| +	request_module(info.type); | |
| +	client_demod = i2c_new_device(&d->i2c_adap, &info); | |
| +	if (client_demod == NULL || | |
| +			client_demod->dev.driver == NULL) | |
| +		goto fail_demod_device; | |
| +	if (!try_module_get(client_demod->dev.driver->owner)) | |
| +		goto fail_demod_module; | |
| + | |
| +	/* attach tuner */ | |
| +	memset(&si2157_config, 0, sizeof(si2157_config)); | |
| +	si2157_config.fe = adap->fe[0]; | |
| +	si2157_config.if_port = 1; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2157", I2C_NAME_SIZE); | |
| +	info.addr = 0x60; | |
| +	info.platform_data = &si2157_config; | |
| + | |
| +	request_module(info.type); | |
| +	client_tuner = i2c_new_device(i2c_adapter, &info); | |
| +	if (client_tuner == NULL || | |
| +			client_tuner->dev.driver == NULL) | |
| +		goto fail_tuner_device; | |
| +	if (!try_module_get(client_tuner->dev.driver->owner)) | |
| +		goto fail_tuner_module; | |
| + | |
| +	state->i2c_client_demod = client_demod; | |
| +	state->i2c_client_tuner = client_tuner; | |
| +	return ret; | |
| +fail_tuner_module: | |
| +	i2c_unregister_device(client_tuner); | |
| +fail_tuner_device: | |
| +	module_put(client_demod->dev.driver->owner); | |
| +fail_demod_module: | |
| +	i2c_unregister_device(client_demod); | |
| +fail_demod_device: | |
| +	ret = -ENODEV; | |
| +	return ret; | |
| +} | |
| + | |
| +static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap) | |
| +{ | |
| +	struct dvbsky_state *state = adap_to_priv(adap); | |
| +	struct dvb_usb_device *d = adap_to_d(adap); | |
| +	int ret = 0; | |
| +	struct i2c_adapter *i2c_adapter; | |
| +	struct i2c_client *client_demod, *client_tuner; | |
| +	struct i2c_board_info info; | |
| +	struct si2168_config si2168_config; | |
| +	struct si2157_config si2157_config; | |
| + | |
| +	/* attach demod */ | |
| +	memset(&si2168_config, 0, sizeof(si2168_config)); | |
| +	si2168_config.i2c_adapter = &i2c_adapter; | |
| +	si2168_config.fe = &adap->fe[0]; | |
| +	si2168_config.ts_mode = SI2168_TS_PARALLEL; | |
| +	si2168_config.ts_clock_inv = 1; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2168", I2C_NAME_SIZE); | |
| +	info.addr = 0x64; | |
| +	info.platform_data = &si2168_config; | |
| + | |
| +	request_module(info.type); | |
| +	client_demod = i2c_new_device(&d->i2c_adap, &info); | |
| +	if (client_demod == NULL || | |
| +			client_demod->dev.driver == NULL) | |
| +		goto fail_demod_device; | |
| +	if (!try_module_get(client_demod->dev.driver->owner)) | |
| +		goto fail_demod_module; | |
| + | |
| +	/* attach tuner */ | |
| +	memset(&si2157_config, 0, sizeof(si2157_config)); | |
| +	si2157_config.fe = adap->fe[0]; | |
| +	si2157_config.if_port = 0; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2141", I2C_NAME_SIZE); | |
| +	info.addr = 0x60; | |
| +	info.platform_data = &si2157_config; | |
| + | |
| +	request_module("si2157"); | |
| +	client_tuner = i2c_new_device(i2c_adapter, &info); | |
| +	if (client_tuner == NULL || | |
| +			client_tuner->dev.driver == NULL) | |
| +		goto fail_tuner_device; | |
| +	if (!try_module_get(client_tuner->dev.driver->owner)) | |
| +		goto fail_tuner_module; | |
| + | |
| +	state->i2c_client_demod = client_demod; | |
| +	state->i2c_client_tuner = client_tuner; | |
| +	return ret; | |
| +fail_tuner_module: | |
| +	i2c_unregister_device(client_tuner); | |
| +fail_tuner_device: | |
| +	module_put(client_demod->dev.driver->owner); | |
| +fail_demod_module: | |
| +	i2c_unregister_device(client_demod); | |
| +fail_demod_device: | |
| +	ret = -ENODEV; | |
| +	return ret; | |
| +} | |
| + | |
| +static int dvbsky_mygica_t230c2_attach(struct dvb_usb_adapter *adap) | |
| +{ | |
| +	struct dvbsky_state *state = adap_to_priv(adap); | |
| +	struct dvb_usb_device *d = adap_to_d(adap); | |
| +	int ret = 0; | |
| +	struct i2c_adapter *i2c_adapter; | |
| +	struct i2c_client *client_demod, *client_tuner; | |
| +	struct i2c_board_info info; | |
| +	struct si2168_config si2168_config; | |
| +	struct si2157_config si2157_config; | |
| + | |
| +	/* attach demod */ | |
| +	memset(&si2168_config, 0, sizeof(si2168_config)); | |
| +	si2168_config.i2c_adapter = &i2c_adapter; | |
| +	si2168_config.fe = &adap->fe[0]; | |
| +	si2168_config.ts_mode = SI2168_TS_PARALLEL; | |
| +	si2168_config.ts_clock_inv = 1; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2168", I2C_NAME_SIZE); | |
| +	info.addr = 0x64; | |
| +	info.platform_data = &si2168_config; | |
| + | |
| +	request_module(info.type); | |
| +	client_demod = i2c_new_device(&d->i2c_adap, &info); | |
| +	if (client_demod == NULL || | |
| +			client_demod->dev.driver == NULL) | |
| +		goto fail_demod_device; | |
| +	if (!try_module_get(client_demod->dev.driver->owner)) | |
| +		goto fail_demod_module; | |
| + | |
| +	/* attach tuner */ | |
| +	memset(&si2157_config, 0, sizeof(si2157_config)); | |
| +	si2157_config.fe = adap->fe[0]; | |
| +	si2157_config.if_port = 0; | |
| +	memset(&info, 0, sizeof(struct i2c_board_info)); | |
| +	strlcpy(info.type, "si2141", I2C_NAME_SIZE); | |
| +	info.addr = 0x60; | |
| +	info.platform_data = &si2157_config; | |
| + | |
| +	request_module("si2157"); | |
| +	client_tuner = i2c_new_device(i2c_adapter, &info); | |
| +	if (client_tuner == NULL || | |
| +			client_tuner->dev.driver == NULL) | |
| +		goto fail_tuner_device; | |
| +	if (!try_module_get(client_tuner->dev.driver->owner)) | |
| +		goto fail_tuner_module; | |
| + | |
| +	state->i2c_client_demod = client_demod; | |
| +	state->i2c_client_tuner = client_tuner; | |
| +	return ret; | |
| +fail_tuner_module: | |
| +	i2c_unregister_device(client_tuner); | |
| +fail_tuner_device: | |
| +	module_put(client_demod->dev.driver->owner); | |
| +fail_demod_module: | |
| +	i2c_unregister_device(client_demod); | |
| +fail_demod_device: | |
| +	ret = -ENODEV; | |
| +	return ret; | |
| +} | |
| + | |
| +static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name) | |
| +{ | |
| +	return WARM; | |
| +} | |
| + | |
| +static int dvbsky_init(struct dvb_usb_device *d) | |
| +{ | |
| +	struct dvbsky_state *state = d_to_priv(d); | |
| +	int ret; | |
| + | |
| +	/* use default interface */ | |
| +	ret = usb_set_interface(d->udev, 0, 0); | |
| +	if (ret) | |
| +		return ret; | |
| + | |
| +	mutex_init(&state->stream_mutex); | |
| +	 | |
| +	/* attach CI */ | |
| +	if (state->has_ci) { | |
| +		dvbsky_gpio_ctrl(d, 0xc0, 1); | |
| +		msleep(100); | |
| +		dvbsky_gpio_ctrl(d, 0xc0, 0); | |
| +		msleep(50); | |
| +		state->ci_attached = 0; | |
| +		ret = dvbsky_ci_init(d); | |
| +		if (ret) | |
| +			return ret; | |
| +	} | |
| +	return 0; | |
| +} | |
| + | |
| +static void dvbsky_exit(struct dvb_usb_device *d) | |
| +{ | |
| +	return dvbsky_ci_release(d); | |
| +} | |
| + | |
| +/* DVB USB Driver stuff */ | |
| +static struct dvb_usb_device_properties dvbsky_s960_props = { | |
| +	.driver_name = KBUILD_MODNAME, | |
| +	.owner = THIS_MODULE, | |
| +	.adapter_nr = adapter_nr, | |
| +	.size_of_priv = sizeof(struct dvbsky_state), | |
| + | |
| +	.generic_bulk_ctrl_endpoint = 0x01, | |
| +	.generic_bulk_ctrl_endpoint_response = 0x81, | |
| + | |
| +	.i2c_algo         = &dvbsky_i2c_algo, | |
| +	.frontend_attach  = dvbsky_s960_attach, | |
| +	.init             = dvbsky_init, | |
| +	.get_rc_config    = dvbsky_get_rc_config, | |
| +	.streaming_ctrl   = dvbsky_streaming_ctrl, | |
| +	.identify_state	  = dvbsky_identify_state, | |
| +	.exit             = dvbsky_exit, | |
| +	.read_mac_address = dvbsky_read_mac_addr, | |
| + | |
| +	.num_adapters = 1, | |
| +	.adapter = { | |
| +		{ | |
| +			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096), | |
| +		} | |
| +	} | |
| +}; | |
| + | |
| +static struct dvb_usb_device_properties dvbsky_t330_props = { | |
| +	.driver_name = KBUILD_MODNAME, | |
| +	.owner = THIS_MODULE, | |
| +	.adapter_nr = adapter_nr, | |
| +	.size_of_priv = sizeof(struct dvbsky_state), | |
| + | |
| +	.generic_bulk_ctrl_endpoint = 0x01, | |
| +	.generic_bulk_ctrl_endpoint_response = 0x81, | |
| +	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY, | |
| + | |
| +	.i2c_algo         = &dvbsky_i2c_algo, | |
| +	.frontend_attach  = dvbsky_t330_attach, | |
| +	.init             = dvbsky_init, | |
| +	.get_rc_config    = dvbsky_get_rc_config, | |
| +	.streaming_ctrl   = dvbsky_streaming_ctrl, | |
| +	.identify_state	  = dvbsky_identify_state, | |
| +	.exit             = dvbsky_exit, | |
| +	.read_mac_address = dvbsky_read_mac_addr, | |
| + | |
| +	.num_adapters = 1, | |
| +	.adapter = { | |
| +		{ | |
| +			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096), | |
| +		} | |
| +	} | |
| +}; | |
| + | |
| +static struct dvb_usb_device_properties mygica_t230_props = { | |
| +	.driver_name = KBUILD_MODNAME, | |
| +	.owner = THIS_MODULE, | |
| +	.adapter_nr = adapter_nr, | |
| +	.size_of_priv = sizeof(struct dvbsky_state), | |
| + | |
| +	.generic_bulk_ctrl_endpoint = 0x01, | |
| +	.generic_bulk_ctrl_endpoint_response = 0x81, | |
| +	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY, | |
| + | |
| +	.i2c_algo         = &dvbsky_i2c_algo, | |
| +	.frontend_attach  = dvbsky_t230_attach, | |
| +	.init             = dvbsky_init, | |
| +	.get_rc_config    = dvbsky_get_rc_config, | |
| +	.streaming_ctrl   = dvbsky_streaming_ctrl, | |
| +	.identify_state	  = dvbsky_identify_state, | |
| +	.exit             = dvbsky_exit, | |
| +	.read_mac_address = dvbsky_read_mac_addr, | |
| + | |
| +	.num_adapters = 1, | |
| +	.adapter = { | |
| +		{ | |
| +			.stream = DVB_USB_STREAM_BULK(0x02, 5, 8192), | |
| +		} | |
| +	} | |
| +}; | |
| + | |
| +static struct dvb_usb_device_properties mygica_t230c_props = { | |
| +	.driver_name = KBUILD_MODNAME, | |
| +	.owner = THIS_MODULE, | |
| +	.adapter_nr = adapter_nr, | |
| +	.size_of_priv = sizeof(struct dvbsky_state), | |
| + | |
| +	.generic_bulk_ctrl_endpoint = 0x01, | |
| +	.generic_bulk_ctrl_endpoint_response = 0x81, | |
| +	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY, | |
| + | |
| +	.i2c_algo         = &dvbsky_i2c_algo, | |
| +	.frontend_attach  = dvbsky_mygica_t230c_attach, | |
| +	.init             = dvbsky_init, | |
| +	.get_rc_config    = dvbsky_get_rc_config, | |
| +	.streaming_ctrl   = dvbsky_streaming_ctrl, | |
| +	.identify_state	  = dvbsky_identify_state, | |
| +	.exit             = dvbsky_exit, | |
| + | |
| +	.num_adapters = 1, | |
| +	.adapter = { | |
| +		{ | |
| +			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096), | |
| +		} | |
| +	} | |
| +}; | |
| + | |
| +static struct dvb_usb_device_properties mygica_t230c2_props = { | |
| +	.driver_name = KBUILD_MODNAME, | |
| +	.owner = THIS_MODULE, | |
| +	.adapter_nr = adapter_nr, | |
| +	.size_of_priv = sizeof(struct dvbsky_state), | |
| + | |
| +	.generic_bulk_ctrl_endpoint = 0x01, | |
| +	.generic_bulk_ctrl_endpoint_response = 0x81, | |
| +	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY, | |
| + | |
| +	.i2c_algo         = &dvbsky_i2c_algo, | |
| +	.frontend_attach  = dvbsky_mygica_t230c2_attach, | |
| +	.init             = dvbsky_init, | |
| +	.get_rc_config    = dvbsky_get_rc_config, | |
| +	.streaming_ctrl   = dvbsky_streaming_ctrl, | |
| +	.identify_state	  = dvbsky_identify_state, | |
| +	.exit             = dvbsky_exit, | |
| + | |
| +	.num_adapters = 1, | |
| +	.adapter = { | |
| +		{ | |
| +			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096), | |
| +		} | |
| +	} | |
| +}; | |
| + | |
| +static const struct usb_device_id dvbsky_id_table[] = { | |
| +	{ DVB_USB_DEVICE(0x0572, 0x6831, | |
| +		&dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) }, | |
| +	{ DVB_USB_DEVICE(0x0572, 0x0320, | |
| +		&dvbsky_t330_props, "DVBSky T330", RC_MAP_DVBSKY) }, | |
| +	{ DVB_USB_DEVICE(0x0572, 0xc68a, | |
| +		&mygica_t230c2_props, "MyGica Mini DVB-T2 USB Stick T230C2", | |
| +		RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, | |
| +	{ DVB_USB_DEVICE(0x0572, 0xc689, | |
| +		&mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", | |
| +		RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, | |
| +	{ DVB_USB_DEVICE(0x0572, 0xc688, | |
| +		&mygica_t230_props, "MyGica Mini DVB-T2 USB Stick T230", | |
| +		RC_MAP_EMPTY) }, | |
| +	{ } | |
| +}; | |
| +MODULE_DEVICE_TABLE(usb, dvbsky_id_table); | |
| + | |
| +static struct usb_driver dvbsky_usb_driver = { | |
| +	.name = KBUILD_MODNAME, | |
| +	.id_table = dvbsky_id_table, | |
| +	.probe = dvb_usbv2_probe, | |
| +	.disconnect = dvb_usbv2_disconnect, | |
| +	.suspend = dvb_usbv2_suspend, | |
| +	.resume = dvb_usbv2_resume, | |
| +	.reset_resume = dvb_usbv2_reset_resume, | |
| +	.no_dynamic_id = 1, | |
| +	.soft_unbind = 1, | |
| +}; | |
| + | |
| +module_usb_driver(dvbsky_usb_driver); | |
| + | |
| +MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>"); | |
| +MODULE_DESCRIPTION("Driver for DVBSky USB2.0"); | |
| +MODULE_LICENSE("GPL"); | |
| diff -urN a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig | |
| --- a/drivers/media/usb/dvb-usb-v2/Kconfig	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/usb/dvb-usb-v2/Kconfig	2013-05-03 17:45:35.000000000 +0800 | |
| @@ -149,3 +149,10 @@ | |
|  	help | |
|  	  Say Y here to support the Realtek RTL28xxU DVB USB receiver. | |
|   | |
| +config DVB_USB_DVBSKY | |
| +	tristate "DVBSky USB2.0 support" | |
| +	depends on DVB_USB_V2 | |
| +	select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT | |
| +	help | |
| +	  Say Y here to support the USB receivers from DVBSky. | |
| + | |
| diff -urN a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile | |
| --- a/drivers/media/usb/dvb-usb-v2/Makefile	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/drivers/media/usb/dvb-usb-v2/Makefile	2013-02-17 12:03:00.000000000 +0800 | |
| @@ -43,6 +43,9 @@ | |
|  dvb-usb-rtl28xxu-objs := rtl28xxu.o | |
|  obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o | |
|   | |
| +dvb-usb-dvbsky-objs := dvbsky.o | |
| +obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o | |
| + | |
|  ccflags-y += -I$(srctree)/drivers/media/dvb-core | |
|  ccflags-y += -I$(srctree)/drivers/media/dvb-frontends | |
|  ccflags-y += -I$(srctree)/drivers/media/tuners | |
| diff -urN a/include/media/rc-map.h b/include/media/rc-map.h | |
| --- a/include/media/rc-map.h	2013-04-29 08:36:01.000000000 +0800 | |
| +++ b/include/media/rc-map.h	2013-05-03 17:02:46.000000000 +0800 | |
| @@ -118,6 +118,7 @@ | |
|  #define RC_MAP_DM1105_NEC                "rc-dm1105-nec" | |
|  #define RC_MAP_DNTV_LIVE_DVBT_PRO        "rc-dntv-live-dvbt-pro" | |
|  #define RC_MAP_DNTV_LIVE_DVB_T           "rc-dntv-live-dvb-t" | |
| +#define RC_MAP_DVBSKY                    "rc-dvbsky" | |
|  #define RC_MAP_EMPTY                     "rc-empty" | |
|  #define RC_MAP_EM_TERRATEC               "rc-em-terratec" | |
| #define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2"
 | |
| 
 |