Dvbworld DW2102 DVB-S USB2 driver.
Signed-off-by: Igor M. Liplianin <[EMAIL PROTECTED]>
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 ([EMAIL PROTECTED])
+ *
+ * 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) [EMAIL PROTECTED]");
+ 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
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb