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