Commit cd79d33e authored by Igor M. Liplianin's avatar Igor M. Liplianin Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (13818): Add Prof 7500 DVB-S2 USB card



The card based on stv0903 demod, stb6100 tuner.

Signed-off-by: default avatarIgor M. Liplianin <liplianin@me.by>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d41592a2
Loading
Loading
Loading
Loading
+84 −10
Original line number Diff line number Diff line
/* DVB USB framework compliant Linux driver for the
*	DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
*	TeVii S600, S630, S650 Cards
*	TeVii S600, S630, S650,
*	Prof 1100, 7500 Cards
* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
*
*	This program is free software; you can redistribute it and/or modify it
@@ -469,6 +470,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
								int num)
{
	struct dvb_usb_device *d = i2c_get_adapdata(adap);
	struct usb_device *udev = d->udev;
	int ret = 0;
	int len, i, j;

@@ -488,8 +490,13 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
		}
		case (DW2102_VOLTAGE_CTRL): {
			u8 obuf[2];

			obuf[0] = 1;
			obuf[1] = msg[j].buf[1];/* off-on */
			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
					obuf, 2, DW210X_WRITE_MSG);
			obuf[0] = 3;
			obuf[1] = msg[j].buf[0];
			obuf[1] = msg[j].buf[0];/* 13v-18v */
			ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
					obuf, 2, DW210X_WRITE_MSG);
			break;
@@ -527,6 +534,17 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
					i += 16;
					len -= 16;
				} while (len > 0);
			} else if ((udev->descriptor.idProduct == 0x7500)
					&& (j < (num - 1))) {
				/* write register addr before read */
				u8 obuf[msg[j].len + 2];
				obuf[0] = msg[j + 1].len;
				obuf[1] = (msg[j].addr << 1);
				memcpy(obuf + 2, msg[j].buf, msg[j].len);
				ret = dw210x_op_rw(d->udev, 0x92, 0, 0,
						obuf, msg[j].len + 2,
						DW210X_WRITE_MSG);
				break;
			} else {
				/* write registers */
				u8 obuf[msg[j].len + 2];
@@ -651,18 +669,25 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])

static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
	static u8 command_13v[1] = {0x00};
	static u8 command_18v[1] = {0x01};
	struct i2c_msg msg[] = {
		{.addr = DW2102_VOLTAGE_CTRL, .flags = 0,
			.buf = command_13v, .len = 1},
	static u8 command_13v[] = {0x00, 0x01};
	static u8 command_18v[] = {0x01, 0x01};
	static u8 command_off[] = {0x00, 0x00};
	struct i2c_msg msg = {
		.addr = DW2102_VOLTAGE_CTRL,
		.flags = 0,
		.buf = command_off,
		.len = 2,
	};

	struct dvb_usb_adapter *udev_adap =
		(struct dvb_usb_adapter *)(fe->dvb->priv);
	if (voltage == SEC_VOLTAGE_18)
		msg[0].buf = command_18v;
	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
		msg.buf = command_18v;
	else if (voltage == SEC_VOLTAGE_13)
		msg.buf = command_13v;

	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);

	return 0;
}

@@ -735,6 +760,18 @@ static struct stv6110_config dw2104_stv6110_config = {
	.clk_div = 1,
};

static struct stv0900_config prof_7500_stv0900_config = {
	.demod_address = 0x6a,
	.demod_mode = 0,
	.xtal = 27000000,
	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
	.diseqc_mode = 2,/* 2/3 PWM */
	.tun1_maddress = 0,/* 0x60 */
	.tun1_adc = 0,/* 2 Vpp */
	.path1_mode = 3,
	.tun1_type = 3,
};

static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
{
	struct dvb_tuner_ops *tuner_ops = NULL;
@@ -882,6 +919,19 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d)
	return -EIO;
}

static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
{
	d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
					&d->dev->i2c_adap, 0);
	if (d->fe == NULL)
		return -EIO;
	d->fe->ops.set_voltage = dw210x_set_voltage;

	info("Attached STV0900+STB6100A!\n");

	return 0;
}

static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
{
	dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -1073,6 +1123,7 @@ static struct usb_device_id dw2102_table[] = {
	{USB_DEVICE(0x9022, USB_PID_TEVII_S630)},
	{USB_DEVICE(0x3011, USB_PID_PROF_1100)},
	{USB_DEVICE(0x9022, USB_PID_TEVII_S660)},
	{USB_DEVICE(0x3034, 0x7500)},
	{ }
};

@@ -1387,9 +1438,30 @@ static struct dvb_usb_device_properties s6x0_properties = {
	}
};

struct dvb_usb_device_properties *p7500;
static struct dvb_usb_device_description d7500 = {
	"Prof 7500 USB DVB-S2",
	{&dw2102_table[9], NULL},
	{NULL},
};

static int dw2102_probe(struct usb_interface *intf,
		const struct usb_device_id *id)
{

	p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL);
	if (!p7500)
		return -ENOMEM;
	/* copy default structure */
	memcpy(p7500, &s6x0_properties,
			sizeof(struct dvb_usb_device_properties));
	/* fill only different fields */
	p7500->firmware = "dvb-usb-p7500.fw";
	p7500->devices[0] = d7500;
	p7500->rc_key_map = tbs_rc_keys;
	p7500->rc_key_map_size = ARRAY_SIZE(tbs_rc_keys);
	p7500->adapter->frontend_attach = prof_7500_frontend_attach;

	if (0 == dvb_usb_device_init(intf, &dw2102_properties,
			THIS_MODULE, NULL, adapter_nr) ||
	    0 == dvb_usb_device_init(intf, &dw2104_properties,
@@ -1397,6 +1469,8 @@ static int dw2102_probe(struct usb_interface *intf,
	    0 == dvb_usb_device_init(intf, &dw3101_properties,
			THIS_MODULE, NULL, adapter_nr) ||
	    0 == dvb_usb_device_init(intf, &s6x0_properties,
			THIS_MODULE, NULL, adapter_nr) ||
	    0 == dvb_usb_device_init(intf, p7500,
			THIS_MODULE, NULL, adapter_nr))
		return 0;

@@ -1431,6 +1505,6 @@ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
				" DVB-C 3101 USB2.0,"
				" TeVii S600, S630, S650, S660 USB2.0,"
				" Prof 1100 USB2.0 devices");
				" Prof 1100, 7500 USB2.0 devices");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
+2 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ struct stv0900_config {
	u8 tun2_maddress;
	u8 tun1_adc;/* 1 for stv6110, 2 for stb6100 */
	u8 tun2_adc;
	u8 tun1_type;/* for now 3 for stb6100 auto, else - software */
	u8 tun2_type;
	/* Set device param to start dma */
	int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured);
};
+86 −1
Original line number Diff line number Diff line
@@ -567,6 +567,46 @@ void stv0900_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
	}
}

u32 stv0900_get_freq_auto(struct stv0900_internal *intp, int demod)
{
	u32 freq, round;
	/*	Formulat :
	Tuner_Frequency(MHz)	= Regs / 64
	Tuner_granularity(MHz)	= Regs / 2048
	real_Tuner_Frequency	= Tuner_Frequency(MHz) - Tuner_granularity(MHz)
	*/
	freq = (stv0900_get_bits(intp, TUN_RFFREQ2) << 10) +
		(stv0900_get_bits(intp, TUN_RFFREQ1) << 2) +
		stv0900_get_bits(intp, TUN_RFFREQ0);

	freq = (freq * 1000) / 64;

	round = (stv0900_get_bits(intp, TUN_RFRESTE1) >> 2) +
		stv0900_get_bits(intp, TUN_RFRESTE0);

	round = (round * 1000) / 2048;

	return freq + round;
}

void stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
						u32 Bandwidth, int demod)
{
	u32 tunerFrequency;
	/* Formulat:
	Tuner_frequency_reg= Frequency(MHz)*64
	*/
	tunerFrequency = (Frequency * 64) / 1000;

	stv0900_write_bits(intp, TUN_RFFREQ2, (tunerFrequency >> 10));
	stv0900_write_bits(intp, TUN_RFFREQ1, (tunerFrequency >> 2) & 0xff);
	stv0900_write_bits(intp, TUN_RFFREQ0, (tunerFrequency & 0x03));
	/* Low Pass Filter = BW /2 (MHz)*/
	stv0900_write_bits(intp, TUN_BW, Bandwidth / 2000000);
	/* Tuner Write trig */
	stv0900_write_reg(intp, TNRLD, 1);
}

static s32 stv0900_get_rf_level(struct stv0900_internal *intp,
				const struct stv0900_table *lookup,
				enum fe_stv0900_demod_num demod)
@@ -1329,7 +1369,6 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
	enum fe_stv0900_error error = STV0900_NO_ERROR;
	enum fe_stv0900_error demodError = STV0900_NO_ERROR;
	struct stv0900_internal *intp = NULL;

	int selosci, i;

	struct stv0900_inode *temp_int = find_inode(state->i2c_adap,
@@ -1404,6 +1443,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
		stv0900_write_bits(intp, F0900_P1_RST_HWARE, 0);
	}

	intp->tuner_type[0] = p_init->tuner1_type;
	intp->tuner_type[1] = p_init->tuner2_type;
	/* tuner init */
	switch (p_init->tuner1_type) {
	case 3: /*FE_AUTO_STB6100:*/
		stv0900_write_reg(intp, R0900_P1_TNRCFG, 0x3c);
		stv0900_write_reg(intp, R0900_P1_TNRCFG2, 0x86);
		stv0900_write_reg(intp, R0900_P1_TNRCFG3, 0x18);
		stv0900_write_reg(intp, R0900_P1_TNRXTAL, 27); /* 27MHz */
		stv0900_write_reg(intp, R0900_P1_TNRSTEPS, 0x05);
		stv0900_write_reg(intp, R0900_P1_TNRGAIN, 0x17);
		stv0900_write_reg(intp, R0900_P1_TNRADJ, 0x1f);
		stv0900_write_reg(intp, R0900_P1_TNRCTL2, 0x0);
		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 3);
		break;
	/* case FE_SW_TUNER: */
	default:
		stv0900_write_bits(intp, F0900_P1_TUN_TYPE, 6);
		break;
	}

	stv0900_write_bits(intp, F0900_P1_TUN_MADDRESS, p_init->tun1_maddress);
	switch (p_init->tuner1_adc) {
	case 1:
@@ -1413,6 +1473,27 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
		break;
	}

	stv0900_write_reg(intp, R0900_P1_TNRLD, 1); /* hw tuner */

	/* tuner init */
	switch (p_init->tuner2_type) {
	case 3: /*FE_AUTO_STB6100:*/
		stv0900_write_reg(intp, R0900_P2_TNRCFG, 0x3c);
		stv0900_write_reg(intp, R0900_P2_TNRCFG2, 0x86);
		stv0900_write_reg(intp, R0900_P2_TNRCFG3, 0x18);
		stv0900_write_reg(intp, R0900_P2_TNRXTAL, 27); /* 27MHz */
		stv0900_write_reg(intp, R0900_P2_TNRSTEPS, 0x05);
		stv0900_write_reg(intp, R0900_P2_TNRGAIN, 0x17);
		stv0900_write_reg(intp, R0900_P2_TNRADJ, 0x1f);
		stv0900_write_reg(intp, R0900_P2_TNRCTL2, 0x0);
		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 3);
		break;
	/* case FE_SW_TUNER: */
	default:
		stv0900_write_bits(intp, F0900_P2_TUN_TYPE, 6);
		break;
	}

	stv0900_write_bits(intp, F0900_P2_TUN_MADDRESS, p_init->tun2_maddress);
	switch (p_init->tuner2_adc) {
	case 1:
@@ -1422,6 +1503,8 @@ static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe,
		break;
	}

	stv0900_write_reg(intp, R0900_P2_TNRLD, 1); /* hw tuner */

	stv0900_write_bits(intp, F0900_P1_TUN_IQSWAP, p_init->tun1_iq_inv);
	stv0900_write_bits(intp, F0900_P2_TUN_IQSWAP, p_init->tun2_iq_inv);
	stv0900_set_mclk(intp, 135000000);
@@ -1824,10 +1907,12 @@ struct dvb_frontend *stv0900_attach(const struct stv0900_config *config,
		init_params.tun1_maddress	= config->tun1_maddress;
		init_params.tun1_iq_inv		= STV0900_IQ_NORMAL;
		init_params.tuner1_adc		= config->tun1_adc;
		init_params.tuner1_type		= config->tun1_type;
		init_params.path2_ts_clock	= config->path2_mode;
		init_params.ts_config		= config->ts_config_regs;
		init_params.tun2_maddress	= config->tun2_maddress;
		init_params.tuner2_adc		= config->tun2_adc;
		init_params.tuner2_type		= config->tun2_type;
		init_params.tun2_iq_inv		= STV0900_IQ_SWAPPED;

		err_stv0900 = stv0900_init_internal(&state->frontend,
+11 −0
Original line number Diff line number Diff line
@@ -247,6 +247,7 @@ struct stv0900_init_params{

	u8	tun1_maddress;
	int	tuner1_adc;
	int 	tuner1_type;

	/* IQ from the tuner1 to the demod */
	enum stv0900_iq_inversion	tun1_iq_inv;
@@ -254,6 +255,7 @@ struct stv0900_init_params{

	u8	tun2_maddress;
	int	tuner2_adc;
	int	tuner2_type;

	/* IQ from the tuner2 to the demod */
	enum stv0900_iq_inversion	tun2_iq_inv;
@@ -309,6 +311,8 @@ struct stv0900_internal{
	s32	bw[2];
	s32	symbol_rate[2];
	s32	srch_range[2];
	/* for software/auto tuner */
	int	tuner_type[2];

	/* algorithm for search Blind, Cold or Warm*/
	enum fe_stv0900_search_algo	srch_algo[2];
@@ -394,4 +398,11 @@ extern enum
fe_stv0900_tracking_standard stv0900_get_standard(struct dvb_frontend *fe,
				enum fe_stv0900_demod_num demod);

extern u32
stv0900_get_freq_auto(struct stv0900_internal *intp, int demod);

extern void
stv0900_set_tuner_auto(struct stv0900_internal *intp, u32 Frequency,
						u32 Bandwidth, int demod);

#endif
+6 −0
Original line number Diff line number Diff line
@@ -3174,17 +3174,21 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define R0900_P1_TNRRF1 0xf4e9
#define TNRRF1 REGx(R0900_P1_TNRRF1)
#define F0900_P1_TUN_RFFREQ2 0xf4e900ff
#define TUN_RFFREQ2 FLDx(F0900_P1_TUN_RFFREQ2)

/*P1_TNRRF0*/
#define R0900_P1_TNRRF0 0xf4ea
#define TNRRF0 REGx(R0900_P1_TNRRF0)
#define F0900_P1_TUN_RFFREQ1 0xf4ea00ff
#define TUN_RFFREQ1 FLDx(F0900_P1_TUN_RFFREQ1)

/*P1_TNRBW*/
#define R0900_P1_TNRBW 0xf4eb
#define TNRBW REGx(R0900_P1_TNRBW)
#define F0900_P1_TUN_RFFREQ0 0xf4eb00c0
#define TUN_RFFREQ0 FLDx(F0900_P1_TUN_RFFREQ0)
#define F0900_P1_TUN_BW 0xf4eb003f
#define TUN_BW FLDx(F0900_P1_TUN_BW)

/*P1_TNRADJ*/
#define R0900_P1_TNRADJ 0xf4ec
@@ -3234,11 +3238,13 @@ extern s32 shiftx(s32 x, int demod, s32 shift);
#define F0900_P1_TUN_I2CLOCKED 0xf4f60010
#define F0900_P1_TUN_PROGDONE 0xf4f6000c
#define F0900_P1_TUN_RFRESTE1 0xf4f60003
#define TUN_RFRESTE1 FLDx(F0900_P1_TUN_RFRESTE1)

/*P1_TNRRESTE*/
#define R0900_P1_TNRRESTE 0xf4f7
#define TNRRESTE REGx(R0900_P1_TNRRESTE)
#define F0900_P1_TUN_RFRESTE0 0xf4f700ff
#define TUN_RFRESTE0 FLDx(F0900_P1_TUN_RFRESTE0)

/*P1_SMAPCOEF7*/
#define R0900_P1_SMAPCOEF7 0xf500
Loading