Dvbworld DW2102 DVB-S USB2 driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Dvbworld DW2102 DVB-S USB2 driver.

Signed-off-by: Igor M. Liplianin <liplianin@xxxxx>
diff -crN v4l-dvb/linux/drivers/media/dvb/dvb-usb/Kconfig v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/Kconfig
*** v4l-dvb/linux/drivers/media/dvb/dvb-usb/Kconfig	2007-10-17 01:24:46.000000000 +0300
--- v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/Kconfig	2007-10-07 12:05:35.000000000 +0300
***************
*** 239,241 ****
--- 239,248 ----
  	  Say Y here to support the default remote control decoding for the
  	  Afatech AF9005 based receiver.
  
+ config DVB_USB_DW2102
+ 	tristate "DvbWorld 2102 DVB-S USB2.0 receiver"
+ 	depends on DVB_USB
+ 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ 	select DVB_PLL if !DVB_FE_CUSTOMISE
+ 	help
+ 	  Say Y here to support the DvbWorld 2102 DVB-S USB2.0 receiver.
diff -crN v4l-dvb/linux/drivers/media/dvb/dvb-usb/Makefile v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/Makefile
*** v4l-dvb/linux/drivers/media/dvb/dvb-usb/Makefile	2007-10-17 01:24:46.000000000 +0300
--- v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/Makefile	2007-10-07 12:06:16.000000000 +0300
***************
*** 61,64 ****
--- 61,67 ----
  dvb-usb-af9005-remote-objs = af9005-remote.o
  obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
  
+ dvb-usb-dw2102-objs = dw2102.o
+ obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
+ 
  EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff -crN v4l-dvb/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
*** v4l-dvb/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	2007-10-17 01:24:46.000000000 +0300
--- v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	2007-10-17 21:57:13.000000000 +0300
***************
*** 170,175 ****
--- 170,176 ----
  #define USB_PID_OPERA1_WARM				0x3829
  #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD		0x0514
  #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM		0x0513
+ #define USB_PID_DW2102					0x2102
  
  
  #endif
diff -crN v4l-dvb/linux/drivers/media/dvb/dvb-usb/dw2102.c v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/dw2102.c
*** v4l-dvb/linux/drivers/media/dvb/dvb-usb/dw2102.c	1970-01-01 03:00:00.000000000 +0300
--- v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/dw2102.c	2007-10-17 01:49:43.000000000 +0300
***************
*** 0 ****
--- 1,402 ----
+ /* DVB USB framework compliant Linux driver for the DVBWorld DVB-S 2102 USB2 Card
+ *
+ * Copyright (C) 2007 Igor M. Liplianin (liplianin@xxxxx)
+ *
+ *	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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+ 
+ #include "dw2102.h"
+ #include "stv0299.h"
+ 
+ #define DW2102_READ_MSG 0
+ #define DW2102_WRITE_MSG 1
+ 
+ #define REG_1F_SYMBOLRATE_BYTE0 0x1f
+ #define REG_20_SYMBOLRATE_BYTE1 0x20
+ #define REG_21_SYMBOLRATE_BYTE2 0x21
+ 
+ #define DW2102_VOLTAGE_CTRL (0x1800)
+ 
+ /* Print a warning */
+ #define wprintk(fmt, arg...) \
+ 	printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg)
+ 
+ struct dw2102_state {
+ 	u32 last_key_pressed;
+ };
+ struct dw2102_rc_keys {
+ 	u32 keycode;
+ 	u32 event;
+ };
+ 
+ int dvb_usb_dw2102_debug;
+ module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
+ MODULE_PARM_DESC(debug,
+ 		 "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))."
+ 		 DVB_USB_DEBUG_STATUS);
+ static int dw2102_op_rw(struct usb_device *dev, u8 request, u16 value,
+ 			   u8 * data, u16 len, int flags)
+ {
+ 	int ret;
+ 	u8 u8buf[len];
+ 
+ 	unsigned int pipe = (flags == DW2102_READ_MSG) ?
+ 		usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
+ 	u8 request_type = (flags == DW2102_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+ 
+ 	if (flags == DW2102_WRITE_MSG)
+ 		memcpy(u8buf, data, len);
+ 	ret =
+ 		usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
+ 			value, 0 , u8buf, len, 2000);
+ 
+ 	if (flags == DW2102_READ_MSG)
+ 		memcpy(data, u8buf, len);
+ 	return ret;
+ }
+ 
+ /* I2C */
+ 
+ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ 			   int num)
+ {
+ 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ 	int i = 0, ret = 0;
+ 	u8 buf6[] = {0x2c,0x05,0xc0,0,0,0,0};
+ 	u8 request;
+ 	u16 value;
+ 	
+ 	if (!d)
+ 		return -ENODEV;
+ 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ 		return -EAGAIN;
+ 	
+ 	switch (num) {
+ 		case 2:
+ 			request=0xb5;
+ 			value = msg[0].buf[0];
+ 			for (i=0; i<msg[1].len; i++){
+ 				value = value + i;
+ 				ret = dw2102_op_rw(d->udev, 0xb5,
+ 					value, buf6, 2, DW2102_READ_MSG);
+ 				msg[1].buf[i] = buf6[0];
+ 
+ 			}
+ 			break;
+ 		case 1:
+ 			switch (msg[0].addr) {
+ 				case 0x68:
+ 					buf6[0] = 0x2a;
+ 					buf6[1] = msg[0].buf[0];
+ 					buf6[2] = msg[0].buf[1];
+ 					ret = dw2102_op_rw(d->udev, 0xb2,
+ 						0, buf6, 3, DW2102_WRITE_MSG);
+ 					break;
+ 				case 0x60:
+ 					if (msg[0].flags == 0) { 
+ 						buf6[0] = 0x2c;
+ 						buf6[1] = 5;
+ 						buf6[2] = 0xc0;
+ 						buf6[3] = msg[0].buf[0];
+ 						buf6[4] = msg[0].buf[1];
+ 						buf6[5] = msg[0].buf[2];
+ 						buf6[6] = msg[0].buf[3];
+ 						ret = dw2102_op_rw(d->udev, 0xb2,
+ 						0, buf6, 7, DW2102_WRITE_MSG);
+ 					} else {
+ 						ret = dw2102_op_rw(d->udev, 0xb5,
+ 						0, buf6, 1, DW2102_READ_MSG);
+ 						msg[0].buf[0] = buf6[0];
+ 					}
+ 					break;
+ 				case (DW2102_VOLTAGE_CTRL):
+ 					buf6[0] = 0x30;
+ 					buf6[1] = msg[0].buf[0];
+ 					ret = dw2102_op_rw(d->udev, 0xb2,
+ 						0, buf6, 2, DW2102_WRITE_MSG);
+ 					break;
+ 			}
+ 			
+ 		break;	
+ 	}
+ 
+ 	mutex_unlock(&d->i2c_mutex);
+ 	return num;
+ }
+ 
+ static u32 dw2102_i2c_func(struct i2c_adapter *adapter)
+ {
+ 	return I2C_FUNC_I2C;
+ }
+ 
+ static struct i2c_algorithm dw2102_i2c_algo = {
+ 	.master_xfer = dw2102_i2c_transfer,
+ 	.functionality = dw2102_i2c_func,
+ };
+ 
+ static int dw2102_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},
+ 	};
+ 	struct dvb_usb_adapter *udev_adap =
+ 	    (struct dvb_usb_adapter *)(fe->dvb->priv);
+ 	if (voltage == SEC_VOLTAGE_18) {
+ 		msg[0].addr = DW2102_VOLTAGE_CTRL;
+ 		msg[0].buf = command_18v;
+ 	}
+ 	i2c_transfer(&udev_adap->dev->i2c_adap, msg, 1);
+ 	return 0;
+ }
+ 
+ 
+ static int dw2102_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
+ 					  u32 ratio)
+ {
+ 	u8 aclk = 0;
+ 	u8 bclk = 0;
+ 
+ 	if (srate < 1500000) {
+ 		aclk = 0xb7;
+ 		bclk = 0x47;
+ 	} else if (srate < 3000000) {
+ 		aclk = 0xb7;
+ 		bclk = 0x4b;
+ 	} else if (srate < 7000000) {
+ 		aclk = 0xb7;
+ 		bclk = 0x4f;
+ 	} else if (srate < 14000000) {
+ 		aclk = 0xb7;
+ 		bclk = 0x53;
+ 	} else if (srate < 30000000) {
+ 		aclk = 0xb6;
+ 		bclk = 0x53;
+ 	} else if (srate < 45000000) {
+ 		aclk = 0xb4;
+ 		bclk = 0x51;
+ 	}
+ 
+ 	stv0299_writereg(fe, 0x13, aclk);
+ 	stv0299_writereg(fe, 0x14, bclk);
+ 	stv0299_writereg(fe, REG_1F_SYMBOLRATE_BYTE0, (ratio >> 16) & 0xff);
+ 	stv0299_writereg(fe, REG_20_SYMBOLRATE_BYTE1, (ratio >> 8) & 0xff);
+ 	stv0299_writereg(fe, REG_21_SYMBOLRATE_BYTE2, (ratio) & 0xf0);
+ 	return 0;
+ 
+ }
+ static u8 dw2102_inittab[] = {
+ 	0x01, 0x15,
+ 	0x02, 0x30,
+ 	0x03, 0x00,
+ 	0x04, 0x7d,		/* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 	0x05, 0x35,		/* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 	0x06, 0x40,		/* DAC not used, set to high impendance mode */
+ 	0x07, 0x00,		/* DAC LSB */
+ 	0x08, 0x40,		/* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 	0x09, 0x00,		/* FIFO */
+ 	0x0c, 0x51,		/* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 	0x0d, 0x82,		/* DC offset compensation = ON, beta_agc1 = 2 */
+ 	0x0e, 0x23,		/* alpha_tmg = 2, beta_tmg = 3 */
+ 	0x10, 0x3f,		// AGC2  0x3d
+ 	0x11, 0x84,
+ 	0x12, 0xb9,
+ 	0x15, 0xc9,		// lock detector threshold
+ 	0x16, 0x00,
+ 	0x17, 0x00,
+ 	0x18, 0x00,
+ 	0x19, 0x00,
+ 	0x1a, 0x00,
+ 	0x1f, 0x50,
+ 	0x20, 0x00,
+ 	0x21, 0x00,
+ 	0x22, 0x00,
+ 	0x23, 0x00,
+ 	0x28, 0x00,		// out imp: normal  out type: parallel FEC mode:0
+ 	0x29, 0x1e,		// 1/2 threshold
+ 	0x2a, 0x14,		// 2/3 threshold
+ 	0x2b, 0x0f,		// 3/4 threshold
+ 	0x2c, 0x09,		// 5/6 threshold
+ 	0x2d, 0x05,		// 7/8 threshold
+ 	0x2e, 0x01,
+ 	0x31, 0x1f,		// test all FECs
+ 	0x32, 0x19,		// viterbi and synchro search
+ 	0x33, 0xfc,		// rs control
+ 	0x34, 0x93,		// error control
+ 	0x0f, 0x52,
+ 	0xff, 0xff
+ 
+ };
+ 
+ static struct stv0299_config dw2102_stv0299_config = {
+ 	.demod_address = 0x68,
+ 	.min_delay_ms = 100,
+ 	.mclk = 88000000UL,
+ 	.invert = 1,
+ 	.skip_reinit = 0,
+ 	.lock_output = STV0229_LOCKOUTPUT_0,
+ 	.volt13_op0_op1 = STV0299_VOLT13_OP0,
+ 	.inittab = dw2102_inittab,
+ 	.set_symbol_rate = dw2102_stv0299_set_symbol_rate,
+ };
+ 
+ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
+ {
+ 	if ((d->fe =
+ 	     dvb_attach(stv0299_attach, &dw2102_stv0299_config,
+ 			&d->dev->i2c_adap)) != NULL) {
+ 		d->fe->ops.set_voltage = dw2102_set_voltage;
+ 		info("Attached stv0299!\n");
+ 		return 0;
+ 	}
+ 	return -EIO;
+ }
+ 
+ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
+ {
+ 	dvb_attach(
+ 		dvb_pll_attach, adap->fe, 0x60,
+ 		&adap->dev->i2c_adap, DVB_PLL_OPERA1
+ 	);
+ 	return 0;
+ }
+ 
+ 
+ static struct usb_device_id dw2102_table[] = {
+ 	{USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
+ 	{0}
+ };
+ 
+ MODULE_DEVICE_TABLE(usb, dw2102_table);
+ 
+ static int dw2102_load_firmware(struct usb_device *dev,
+ 				       const struct firmware *fw)
+ {
+ 	u8 *b, *p;
+ 	int ret = 0, i;
+ 	u8 reset;
+ 	u8 reset16 [] = {0,0};
+ 	info("start downloading DW2102 firmware");
+ 	p = kmalloc(fw->size, GFP_KERNEL);
+ 	reset = 1;
+ 	/*stop the CPU*/
+ 	dw2102_op_rw(dev, 0xa0, 0x7f92, &reset, 1, DW2102_WRITE_MSG);
+ 	dw2102_op_rw(dev, 0xa0, 0xe600, &reset, 1, DW2102_WRITE_MSG);
+ 
+ 	if (p != NULL) {
+ 		memcpy(p, fw->data, fw->size);
+ 		for (i = 0; i < fw->size; i += 0x40) {
+ 			b = (u8 *) p + i;	
+ 			if (dw2102_op_rw
+ 				(dev, 0xa0, i, b , 0x40,
+ 					DW2102_WRITE_MSG) != 0x40
+ 				) {
+ 				err("error while transferring firmware");
+ 				ret = -EINVAL;
+ 				break;
+ 			}
+ 		}
+ 		/* restart the CPU */
+ 		reset = 0;
+ 		if (ret || dw2102_op_rw
+ 				(dev, 0xa0, 0x7f92, &reset, 1,
+ 				DW2102_WRITE_MSG) != 1) {
+ 			err("could not restart the USB controller CPU.");
+ 			ret = -EINVAL;
+ 		}
+ 			if (ret || dw2102_op_rw
+ 				(dev, 0xa0, 0xe600, &reset, 1,
+ 				DW2102_WRITE_MSG) != 1) {
+ 			err("could not restart the USB controller CPU.");
+ 			ret = -EINVAL;
+ 		}
+ 			dw2102_op_rw
+ 				(dev, 0xbf, 0x0040, &reset, 0,
+ 				DW2102_WRITE_MSG);
+ 			dw2102_op_rw
+ 				(dev, 0xb9, 0x0000, &reset16, 2,
+ 				DW2102_READ_MSG);
+ 			
+ 		kfree(p);
+ 	}
+ 	return ret;
+ }
+ 														
+ static struct dvb_usb_device_properties dw2102_properties = {
+ 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ 	.usb_ctrl = DEVICE_SPECIFIC,
+ 	.firmware = "dvb-usb-dw2102.fw",
+ 	.size_of_priv = sizeof(struct dw2102_state),
+ 	.no_reconnect = 1,
+ 
+ 	.i2c_algo = &dw2102_i2c_algo,
+ 
+ 	.generic_bulk_ctrl_endpoint = 0x1,
+ 	/* parameter for the MPEG2-data transfer */
+ 	.num_adapters = 1,
+ 	.download_firmware = dw2102_load_firmware,
+ 	.adapter = {
+ 		{
+ 			.frontend_attach = dw2102_frontend_attach,
+ 			.streaming_ctrl = NULL,
+ 			.tuner_attach = dw2102_tuner_attach,
+ 			.stream = {
+ 				.type = USB_BULK,
+ 				.count = 7,
+ 				.endpoint = 0x82,
+ 				.u = {
+ 					.bulk = {
+ 						.buffersize = 4096,
+ 					}
+ 				}
+ 			},
+ 		}
+ 	},
+ 	.num_device_descs = 1,
+ 	.devices = {
+ 		{"DVBWorld DVB-S 2102 USB2.0",
+ 			{&dw2102_table[0], NULL},
+ 		},
+ 		{NULL},
+ 	}
+ };
+ 
+ static int dw2102_probe(struct usb_interface *intf,
+ 			const struct usb_device_id *id)
+ {
+ 	return dvb_usb_device_init(intf, &dw2102_properties, THIS_MODULE, NULL);
+ }
+ 
+ static struct usb_driver dw2102_driver = {
+ 	.name = "dw2102",
+ 	.probe = dw2102_probe,
+ 	.disconnect = dvb_usb_device_exit,
+ 	.id_table = dw2102_table,
+ };
+ 
+ static int __init dw2102_module_init(void)
+ {
+ 	int result = 0;
+ 	if ((result = usb_register(&dw2102_driver))) {
+ 		err("usb_register failed. Error number %d", result);
+ 	}
+ 	return result;
+ }
+ 
+ static void __exit dw2102_module_exit(void)
+ {
+ 	usb_deregister(&dw2102_driver);
+ }
+ 
+ module_init(dw2102_module_init);
+ module_exit(dw2102_module_exit);
+ 
+ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@xxxxx");
+ MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2102 USB2.0 device");
+ MODULE_VERSION("0.1");
+ MODULE_LICENSE("GPL");
diff -crN v4l-dvb/linux/drivers/media/dvb/dvb-usb/dw2102.h v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/dw2102.h
*** v4l-dvb/linux/drivers/media/dvb/dvb-usb/dw2102.h	1970-01-01 03:00:00.000000000 +0300
--- v4l-dvb-1/linux/drivers/media/dvb/dvb-usb/dw2102.h	2007-04-22 15:48:45.000000000 +0300
***************
*** 0 ****
--- 1,9 ----
+ #ifndef _DW2102_H_
+ #define _DW2102_H_
+ 
+ #define DVB_USB_LOG_PREFIX "dw2102"
+ #include "dvb-usb.h"
+ 
+ extern int dvb_usb_dw2102_debug;
+ #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug,0x02,args)
+ #endif
_______________________________________________
linux-dvb mailing list
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux