/*
 * Realtek RTL2831U DVB USB driver
 *
 * Copyright (c) 2008 Realtek
 * Copyright (c) 2008 Jan Hoogenraad, Barnaby Shearer, Andy Hasper
 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
 *
 *    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.
 *
 *
 * Thanks to Realtek for a lot of support we received !
 */

#include "rtl2831u.h"
#include "rtl2830.h"
#include "mt2060.h"
#include "mxl5005s.h"
#include "fc2580.h"

#define RTL2831U

/* debug */
static int initdone = 0;
static int dvb_usb_rtl2831u_debug = -1;
module_param_named(debug, dvb_usb_rtl2831u_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);

static struct rtl2830_config rtl2831u_rtl2830_config;

static int rtl2831u_rw_udev(struct usb_device *udev, struct rtl2831u_req *req)
{
	int ret;
	unsigned int pipe;
	u8 requesttype;
	u8 buf[req->data_len];

	#define WRITE_MASK 0x0010
	if (req->index & WRITE_MASK) {
		/* write */
		memcpy(buf, req->data, req->data_len);
		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
		pipe = usb_sndctrlpipe(udev, 0);
	} else {
		/* read */
		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
		pipe = usb_rcvctrlpipe(udev, 0);
	}

	msleep(1); /* avoid I2C errors */

	ret = usb_control_msg(udev, pipe, 0, requesttype, req->value,
		req->index, buf, sizeof(buf), RTL2831U_USB_TIMEOUT);

	rtl2831u_debug_dump(0, requesttype, req->value, req->index, buf,
		req->data_len, deb_xfer);

	if (ret < 0)
		deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
	else
		ret = 0;

	/* read request, copy returned data to return buf */
	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
		memcpy(req->data, buf, req->data_len);

	return ret;
}

static int rtl2831u_ctrl_msg(struct dvb_usb_device *d, struct rtl2831u_req *req)
{
	return rtl2831u_rw_udev(d->udev, req);
}

/* I2C gate hack needed for RTL2831U since it closes gate automatically... */
static int rtl2831u_open_demod_gate(struct dvb_usb_device *d)
{
	struct rtl2831u_priv *priv = d->priv;
	u8 val = 0x08;
//	struct rtl2831u_req req = {0x0120, 0x0011, 0x0001, "\x08"};
	struct rtl2831u_req req = {0x0120, 0x0011, 0x0001, &val};
	int ret = 0;

	if (priv->chip_ver == 2)
		val = 0x18;

	ret = rtl2831u_ctrl_msg(d, &req);
	return ret;
}

/* I2C */
static int rtl2831u_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
			   int num)
{
	struct dvb_usb_device *d = i2c_get_adapdata(adap);
	int i = 0;
	struct rtl2831u_req req;
	int ret = 0;

	if (num > 2)
		return -EINVAL;

	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
		return -EAGAIN;

	while (i < num) {
		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
			if (msg[i].addr ==
				rtl2831u_rtl2830_config.demod_address) {
				req.value = (msg[i].buf[1] << 8) + msg[i].addr;
				req.index = DEMOD_READ + msg[i].buf[0];
				req.data_len = msg[i+1].len;
				req.data = &msg[i+1].buf[0];
				ret = rtl2831u_ctrl_msg(d, &req);
			} else {
				ret = rtl2831u_open_demod_gate(d); /* hack */
				if (ret)
					goto error;
				req.value = (msg[i].buf[0] << 8) + msg[i].addr;
				req.index = I2C_READ;
				req.data_len = msg[i+1].len;
				req.data = &msg[i+1].buf[0];
				ret = rtl2831u_ctrl_msg(d, &req);
			}
			i += 2;
		} else {
			if (msg[i].addr ==
				rtl2831u_rtl2830_config.demod_address) {
				req.value = (msg[i].buf[1] << 8) + msg[i].addr;
				req.index = DEMOD_WRITE + msg[i].buf[0];
				req.data_len = msg[i].len-2;
				req.data = &msg[i].buf[2];
				ret = rtl2831u_ctrl_msg(d, &req);
			} else {
				ret = rtl2831u_open_demod_gate(d); /* hack */
				if (ret)
					goto error;
				req.value = (msg[i].buf[0] << 8) + msg[i].addr;
				req.index = I2C_WRITE;
				req.data_len = msg[i].len-1;
				req.data = &msg[i].buf[1];
				ret = rtl2831u_ctrl_msg(d, &req);
			}
			i += 1;
		}
		if (ret)
			break;
	}

error:
	mutex_unlock(&d->i2c_mutex);
	return ret ? ret : i;
}

static u32 rtl2831u_i2c_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_I2C;
}

static struct i2c_algorithm rtl2831u_i2c_algo = {
	.master_xfer   = rtl2831u_i2c_xfer,
	.functionality = rtl2831u_i2c_func,
#ifdef NEED_ALGO_CONTROL
	.algo_control = dummy_algo_control,
#endif
};

/* Callbacks for DVB USB */
static struct rtl2830_config rtl2831u_rtl2830_config = {
	.demod_address = 0x20,
};

static int rtl2831_write_regs(struct dvb_usb_device *d, u16 type, u16 reg, u8 *val, u8 len)
{
	struct rtl2831u_req req;
	if (type == SYS)
		req.value = (0x30 << 8) + reg;
	else
		req.value = (0x20 << 8) + reg;
	req.index = type + 0x10;
	req.data_len = len;
	req.data = val;
	return rtl2831u_ctrl_msg(d, &req);
}

static int rtl2831_read_regs(struct dvb_usb_device *d, u16 type, u16 reg, u8 *val, u8 len)
{
	struct rtl2831u_req req;
	if (type == SYS)
		req.value = (0x30 << 8) + reg;
	else
		req.value = (0x20 << 8) + reg;
	req.index = type + 0x00;
	req.data_len = len;
	req.data = val;
	return rtl2831u_ctrl_msg(d, &req);
}


static int rtl2831_write_reg(struct dvb_usb_device *d, u16 type, u16 reg, u8 val)
{
	return rtl2831_write_regs(d, type, reg, &val, 1);
}

static int rtl2831_read_reg(struct dvb_usb_device *d, u16 type, u16 reg, u8 *val)
{
	return rtl2831_read_regs(d, type, reg, val, 1);
}

static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
{
	int ret;
	struct rtl2831u_priv *priv = adap->dev->priv;
	u8 buf[4], i;
	//OUT: 000004 ms 000149 ms c0 00 c0 00 00 03 01 00 <<<  63 MT2060
	//OUT: 000004 ms 052011 ms c0 00 c4 0f 00 03 01 00 <<<  2c QT1010
	//OUT: 000003 ms 000349 ms c0 00 ac 01 00 03 01 00 <<<  56 FC2580
	struct rtl2831u_req req_mt2060 = {0x00c0, I2C_READ, 1, buf};
	struct rtl2831u_req req_qt1010 = {0x0fc4, I2C_READ, 1, buf};
	struct rtl2831u_req req_fc2580 = {0x01ac, I2C_READ, 1, buf};
	deb_info("%s:\n", __func__);


#if 0
	ret = rtl2831_write_reg(adap->dev, SYS, GPD, 0x0a);
	if (ret)
		goto error;

	/* RTL2831U GPIOs
	   =========================================================
	   GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
	   GPIO2 | LED     | 0 off | 1 on  |
	   GPIO4 | tuner#1 | 0 on  | 1 off | MT2060 */


	/* enable as output GPIO0, GPIO2, GPIO4 */
	ret = rtl2831_write_reg(adap->dev, SYS, GPOE, 0x15);
	if (ret)
		goto error;
#endif

	/* 1.FULL packer mode(for bulk)
	   2.verification mode(will not used in future)
	   3.DMA enable */
	ret = rtl2831_write_reg(adap->dev, USB, USB_SYSCTL_0, 0x09);
	if (ret)
		goto error;

	/* check epa config,
	   [9-8]:00, 1 transaction per microframe
	   [7]:1, epa enable
	   [6-5]:10, bulk mode
	   [4]:1, device to host
	   [3:0]:0001, endpoint number */
	/* leave default */

	/* EPA maxsize packet
	   512:highspeedbulk, 64:fullspeedbulk
	   940:highspeediso,  940:fullspeediso */
	/* 0x00000200 = 512 */
	buf[0] = 0x00;
	buf[1] = 0x02;
	buf[2] = 0x00;
	buf[3] = 0x00;
	ret = rtl2831_write_regs(adap->dev, USB, USB_EPA_MAXPKT, buf, 4);
	if (ret)
		goto error;

	/* change fifo length of EPA */
	/* 0x00000014 = 20 */
	buf[0] = 0x14;
	buf[1] = 0x00;
	buf[2] = 0x00;
	buf[3] = 0x00;
	ret = rtl2831_write_regs(adap->dev, USB, USB_EPA_FIFO_CFG, buf, 4);
	if (ret)
		goto error;

#if 0
	/* reset epa fifo */
	/* 0x0200 */
	buf[0] = 0x00;
	buf[1] = 0x02;
	rtl2831_write_regs(adap->dev, USB, USB_EPA_CTL, buf, 2);
	/* 0x0000 */
	buf[0] = 0x00;
	buf[1] = 0x00;
	rtl2831_write_regs(adap->dev, USB, USB_EPA_CTL, buf, 2);
#endif

	/* probe tuner because we need to know few tuner specific demod
	   parameters before demod is attached */

	// for RTL2832U gate...
//	ret = rtl2831_write_reg(adap->dev, SYS, DEMOD_CTL, 0xe8);
	//tuner pwr
	//000052:  OUT: 000002 ms 000264 ms 40 00 01 30 10 02 01 00 >>>  08 // SYS GPIO_OUTPUT_VAL RTD2831_RMAP_INDEX_SYS_GPIO_OUTPUT_VAL
//	ret = rtl2831_write_reg(d, SYS, GPIO_OUTPUT_VAL, 0x08); // tämä niin tuner OK

	rtl2831u_rtl2830_config.rtl2830 = 0;
	rtl2831u_rtl2830_config.rtl2832 = 0;
	rtl2831u_rtl2830_config.crystal_freq = 28800000; //28.8MHz


	if (priv->chip_ver == 1) {
		/* RTL2831U */
		rtl2831u_rtl2830_config.rtl2830 = 1;

		/* open demod I2C gate */
		ret = rtl2831u_open_demod_gate(adap->dev);
		if (ret)
			goto error;

		/* check QT1010 ID(?) register; reg:0f val:2c */
		ret = rtl2831u_ctrl_msg(adap->dev, &req_qt1010);
		if (ret == 0 && buf[0] == 0x2c) {
			priv->tuner = TUNER_QT1010;
			rtl2831u_rtl2830_config.if_freq = 36125000;
			rtl2831u_rtl2830_config.rf_spec_inv = 1;
			rtl2831u_rtl2830_config.vtop = 0x20;
			rtl2831u_rtl2830_config.krf = 0x04;
			rtl2831u_rtl2830_config.agc_targ_val = 0x2d;
			goto tuner_found;
		} else {
			deb_info("%s: QT1010 probe failed:%d - %02x\n",
				__func__, ret, buf[0]);
		}

		/* open demod I2C gate */
		ret = rtl2831u_open_demod_gate(adap->dev);
		if (ret)
			goto error;

		/* check MT2060 ID register; reg:00 val:63 */
		ret = rtl2831u_ctrl_msg(adap->dev, &req_mt2060);
		if (ret == 0 && buf[0] == 0x63) {
			priv->tuner = TUNER_MT2060;
			rtl2831u_rtl2830_config.if_freq = 36125000;
			rtl2831u_rtl2830_config.rf_spec_inv = 1;
			rtl2831u_rtl2830_config.vtop = 0x20;
			rtl2831u_rtl2830_config.krf = 0x04;
			rtl2831u_rtl2830_config.agc_targ_val = 0x2d;
			goto tuner_found;
		} else {
			deb_info("%s: MT2060 probe failed:%d - %02x\n",
				__func__, ret, buf[0]);
		}

		if (priv->tuner == TUNER_NONE) {
			/* assume MXL5005S */
			priv->tuner = TUNER_MXL5005S;
			rtl2831u_rtl2830_config.if_freq = 4570000;
			rtl2831u_rtl2830_config.rf_spec_inv = 0;
			rtl2831u_rtl2830_config.vtop = 0x3f;
			rtl2831u_rtl2830_config.krf = 0x04;
			rtl2831u_rtl2830_config.agc_targ_val = 0x3e;
			goto tuner_found;
		}
	} else {
		/* RTL2832U */
		/* open demod I2C gate */
		ret = rtl2831u_open_demod_gate(adap->dev);
		if (ret)
			goto error;

		/* check FC2580 ID register; reg:01 val:56 */
		ret = rtl2831u_ctrl_msg(adap->dev, &req_fc2580);
		if (ret == 0 && buf[0] == 0x56) {
			priv->tuner = TUNER_FC2580;
			rtl2831u_rtl2830_config.rtl2832 = 1;
			goto tuner_found;
		}
	}
tuner_found:

	deb_info("%s: tuner:%d\n", __func__, priv->tuner);

	/* attach demodulator */
	adap->fe = dvb_attach(rtl2830_attach, &rtl2831u_rtl2830_config,
		&adap->dev->i2c_adap);
	if (adap->fe == NULL)
		return -ENODEV;

	return 0;
error:
	deb_info("%s: failed:%d\n", __func__, ret);
	return ret;
}

static struct mt2060_config rtl2831u_mt2060_config = {
	.i2c_address = 0xc0,
	.clock_out = 0,
};

static struct mxl5005s_config rtl2831u_mxl5003s_config = {
	.i2c_address     = 0xc6,
	.if_freq         = IF_FREQ_4570000HZ,
	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
	.agc_mode        = MXL_SINGLE_AGC,
	.tracking_filter = MXL_TF_C_H,
	.rssi_enable     = MXL_RSSI_ENABLE,
	.cap_select      = MXL_CAP_SEL_ENABLE,
	.div_out         = MXL_DIV_OUT_4,
	.clock_out       = MXL_CLOCK_OUT_DISABLE,
	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
	.top		 = MXL5005S_TOP_25P2,
	.mod_mode        = MXL_DIGITAL_MODE,
	.if_mode         = MXL_ZERO_IF,
	.AgcMasterByte   = 0x00,
};

static struct fc2580_config rtl2831u_fc2580_config = {
	.i2c_address = 0xac,
};

static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
{
	int ret;
	struct rtl2831u_priv *priv = adap->dev->priv;
	deb_info("%s:\n", __func__);

	switch (priv->tuner) {
	case TUNER_QT1010:
		err("QT1010 tuner not implemented");
		ret = -ENODEV;
		break;
	case TUNER_MT2060:
		ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap,
			&rtl2831u_mt2060_config, 1220) == NULL ? -ENODEV : 0;
		break;
	case TUNER_MXL5005S:
		ret = dvb_attach(mxl5005s_attach, adap->fe,
			&adap->dev->i2c_adap,
			&rtl2831u_mxl5003s_config) == NULL ? -ENODEV : 0;
		break;
	case TUNER_FC2580:
		ret = dvb_attach(fc2580_attach, adap->fe,
			&adap->dev->i2c_adap,
			&rtl2831u_fc2580_config) == NULL ? -ENODEV : 0;
		break;
	default:
		ret = -ENODEV;
		err("unknown tuner:%d", priv->tuner);
	}

	if (ret)
		deb_info("%s: failed:%d\n", __func__, ret);

	return ret;
}

static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
{
	u8 buf[2], gpo;
	int ret;
	deb_info("%s: onoff:%d\n", __func__, onoff);

	/* LED, read GPIO */
	ret = rtl2831_read_reg(adap->dev, SYS, GPO, &gpo);
	if (ret)
		goto error;

	if(onoff) {
		buf[0] = 0x00;
		buf[1] = 0x00;
		gpo |= 0x04;    /* LED on, GPIO2 set 1 */
	} else {
		buf[0] = 0x10;  /* stall epa, set bit 4 to 1 */
		buf[1] = 0x02;  /* reset epa, set bit 9 to 1 */
		gpo &= (~0x04); /* LED off, GPIO2 set 0 */
	}

	/* LED, write GPIO */
	ret = rtl2831_write_reg(adap->dev, SYS, GPO, gpo);
	if (ret)
		goto error;

	/* endpoint A */
	ret = rtl2831_write_regs(adap->dev, USB, USB_EPA_CTL, buf, sizeof(buf));

error:
	if (ret)
		deb_info("%s: failed:%d\n", __func__, ret);

	return ret;
}

static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
{
	struct rtl2831u_priv *priv = d->priv;
	int ret;
	u8 gpo, sys_0;
	deb_info("%s: onoff:%d\n", __func__, onoff);

	/* USB interfaces: RTL2831U have 1 and RTL2832U have 2 */
	priv->chip_ver = d->udev->config->desc.bNumInterfaces;


#define USB_SYSCTL				0x0000 	
#define USB_CTRL				0x0010
#define USB_STAT				0x0014	
#define USB_EPA_CTL				0x0148  	
#define USB_EPA_CFG				0x0144
#define USB_EPA_MAXPKT			0x0158  
#define USB_EPA_FIFO_CFG		0x0160 

#define DEMOD_CTL				0x0000	
#define GPIO_OUTPUT_VAL		0x0001
#define GPIO_OUTPUT_EN			0x0003
#define GPIO_DIR					0x0004
#define GPIO_CFG0				0x0007
#define GPIO_CFG1				0x0008	
#define DEMOD_CTL1				0x000b

	if (priv->chip_ver == 2) {
		if (initdone)
			return 0;

//000005:  OUT: 000002 ms 000125 ms 40 00 00 20 10 01 01 00 >>>  09 // USB USB_SYSCTL 09 RTD2831_RMAP_INDEX_USB_SYSCTL = RTD2832U_USB, USB_SYSCTL, 0, 31
	ret = rtl2831_write_reg(d, USB, USB_SYSCTL, 0x09);
//000015:  OUT: 000002 ms 000145 ms 40 00 07 30 10 02 01 00 >>>  96 // SYS GPIO_CFG0       RTD2831_RMAP_INDEX_SYS_GPIO_CFG0_BIT67
	ret = rtl2831_write_reg(d, SYS, GPIO_CFG0, 0x96);
//000018:  OUT: 000002 ms 000150 ms 40 00 01 30 10 02 01 00 >>>  18 // SYS GPIO_OUTPUT_VAL RTD2831_RMAP_INDEX_SYS_GPIO_OUTPUT_VAL
	ret = rtl2831_write_reg(d, SYS, GPIO_DIR, 0x06);
//000021:  OUT: 000002 ms 000156 ms 40 00 04 30 10 02 01 00 >>>  06 // SYS GPIO_DIR        RTD2831_RMAP_INDEX_SYS_GPIO_DIR_BIT3
	ret = rtl2831_write_reg(d, SYS, GPIO_DIR, 0x06);
//000024:  OUT: 000001 ms 000162 ms 40 00 03 30 10 02 01 00 >>>  19 // SYS GPIO_OUTPUT_EN  RTD2831_RMAP_INDEX_SYS_GPIO_OUTPUT_EN_BIT3
	ret = rtl2831_write_reg(d, SYS, GPIO_OUTPUT_EN, 0x19);
//000027:  OUT: 000002 ms 000167 ms 40 00 10 20 10 01 01 00 >>>  29 // USB USB_CTRL        RTD2831_RMAP_INDEX_USB_CTRL_BIT5
	ret = rtl2831_write_reg(d, USB, USB_CTRL, 0x29);

//000030:  OUT: 000002 ms 000173 ms 40 00 01 30 10 02 01 00 >>>  18 // SYS GPIO_OUTPUT_VAL
	ret = rtl2831_write_reg(d, SYS, GPIO_OUTPUT_VAL, 0x18);
//000033:  OUT: 000002 ms 000178 ms 40 00 0b 30 10 02 01 00 >>>  02 // SYS DEMOD_CTL1
	ret = rtl2831_write_reg(d, SYS, DEMOD_CTL1, 0x02);
//000036:  OUT: 000002 ms 000184 ms 40 00 00 30 10 02 01 00 >>>  a0 // SYS DEMOD_CTL RTD2831_RMAP_INDEX_SYS_DEMOD_CTL
	ret = rtl2831_write_reg(d, SYS, DEMOD_CTL, 0xa0);
//000039:  OUT: 000001 ms 000190 ms 40 00 00 30 10 02 01 00 >>>  80 // SYS DEMOD_CTL RTD2831_RMAP_INDEX_SYS_DEMOD_CTL
	ret = rtl2831_write_reg(d, SYS, DEMOD_CTL, 0x80);
//000042:  OUT: 000002 ms 000195 ms 40 00 00 30 10 02 01 00 >>>  a0 // SYS DEMOD_CTL RTD2831_RMAP_INDEX_SYS_DEMOD_CTL
	ret = rtl2831_write_reg(d, SYS, DEMOD_CTL, 0xa0);
//000046:  OUT: 000002 ms 000253 ms 40 00 00 30 10 02 01 00 >>>  a8 // SYS DEMOD_CTL RTD2831_RMAP_INDEX_SYS_DEMOD_CTL
	ret = rtl2831_write_reg(d, SYS, DEMOD_CTL, 0xa8);

//000049:  OUT: 000002 ms 000258 ms 40 00 00 30 10 02 01 00 >>>  e8 // SYS DEMOD_CTL RTD2831_RMAP_INDEX_SYS_DEMOD_CTL
	ret = rtl2831_write_reg(d, SYS, DEMOD_CTL, 0xe8); // tämä niin demod gate OK

//tuner pwr
//000052:  OUT: 000002 ms 000264 ms 40 00 01 30 10 02 01 00 >>>  08 // SYS GPIO_OUTPUT_VAL RTD2831_RMAP_INDEX_SYS_GPIO_OUTPUT_VAL
	ret = rtl2831_write_reg(d, SYS, GPIO_OUTPUT_VAL, 0x08); // tämä niin tuner OK

initdone = 1;

	return 0;

	} else { //rtl2831u

	/* demod adc */
	ret = rtl2831_read_reg(d, SYS, SYS_0, &sys_0);
	if (ret)
		goto error;

	/* tuner power, read GPIO */
	ret = rtl2831_read_reg(d, SYS, GPO, &gpo);
	if (ret)
		goto error;

	deb_info("%s: onoff:%d < sys_0:%02x gpo:%02x\n", __func__, onoff, sys_0, gpo);

	if(onoff) {
		gpo |= 0x01;           /* GPIO0 set 1 */
		gpo &= (~0x10);        /* GPIO4 set 0 */
		sys_0 = sys_0 & 0x0f;
		sys_0 |= 0xe0;
	} else {
#if 0 /* keep */
		/* We cannot "power off" device currently because most ioctls
		   are are permitted even when device is "power off". */
		gpo &= (~0x01);        /* GPIO0 set 0 */
		gpo |= 0x10;           /* GPIO4 set 1 */
//		sys_0 = sys_0 & (~0x40); // close demod adc
		sys_0 = sys_0 & (~0xc0);
#endif
	}
//TODO: check why windows 0xc0, linux 0x40

	deb_info("%s: onoff:%d > sys_0:%02x gpo:%02x\n", __func__, onoff, sys_0, gpo);


	/* demod adc */
	ret = rtl2831_write_reg(d, SYS, SYS_0, sys_0);
	if (ret)
		goto error;

	/* tuner power, write GPIO */
	ret = rtl2831_write_reg(d, SYS, GPO, gpo);
	if (ret)
		goto error;

	}
error:
	if (ret)
		deb_info("%s: failed:%d\n", __func__, ret);

	return ret;
}

/* DVB USB Driver stuff */
#define	USB_VID_REALTEK			0x0bda
#define	USB_PID_RTD2831U		0x2831

#define	USB_VID_REALTEK_2		0x2304
#define	USB_PID_RTD2831U_2		0x022b

#define	USB_VID_HAIHUA			0x13d3
#define	USB_PID_HAIHUAUSB		0x3216
#define	USB_PID_HAIHUAMIN		0x3220
#define	USB_PID_HAIHUAA			0x3236
#define	USB_PID_HAIHUAL			0x3238
#define	USB_PID_HAIHUAZ			0x3244

#define	USB_VID_BILLIONTON		0x08dd
#define	USB_PID_BILLIONTON		0x2103

#define	USB_PID_COMPRO			0x0100
#define USB_PID_COMPRO_VIDEOMATE_U90	0x0150

#define	USB_VID_VESTEL			0x1a46
#define	USB_PID_VESTEL			0x1601

#define	USB_VID_FREECOM			0x14aa
#define	USB_PID_FREECOM			0x0160

#define	USB_VID_FREECOM_2		0x14ff
#define	USB_PID_FREECOM_2		0x0225

//1d19:1101

static struct usb_device_id rtl2831u_table[] = {
	{USB_DEVICE(USB_VID_REALTEK,    USB_PID_RTD2831U)},
	{USB_DEVICE(USB_VID_REALTEK_2,  USB_PID_RTD2831U_2)},
	{USB_DEVICE(USB_VID_HAIHUA,     USB_PID_HAIHUAUSB)},
	{USB_DEVICE(USB_VID_HAIHUA,     USB_PID_HAIHUAMIN)},
	{USB_DEVICE(USB_VID_HAIHUA,     USB_PID_HAIHUAA)},
	{USB_DEVICE(USB_VID_HAIHUA,     USB_PID_HAIHUAL)},
	{USB_DEVICE(USB_VID_HAIHUA,     USB_PID_HAIHUAZ)},
	{USB_DEVICE(USB_VID_BILLIONTON, USB_PID_BILLIONTON)},
	{USB_DEVICE(USB_VID_COMPRO,     USB_PID_COMPRO)},
	{USB_DEVICE(USB_VID_COMPRO,     USB_PID_COMPRO_VIDEOMATE_U90)},
	{USB_DEVICE(USB_VID_VESTEL,     USB_PID_VESTEL)},
	{USB_DEVICE(USB_VID_FREECOM,    USB_PID_FREECOM)},
	{USB_DEVICE(USB_VID_FREECOM_2,  USB_PID_FREECOM_2)},
	{USB_DEVICE(0x1d19, 0x1101)},
	{} /* Terminating entry */
};

MODULE_DEVICE_TABLE(usb, rtl2831u_table);

static struct dvb_usb_device_properties rtl2831u_properties[] = {
	{
		.caps = DVB_USB_IS_AN_I2C_ADAPTER,

		.usb_ctrl = DEVICE_SPECIFIC,
		.no_reconnect = 1,

		.size_of_priv = sizeof(struct rtl2831u_priv),

		.num_adapters = 1,
		.adapter = {
			{
				.streaming_ctrl  = rtl2831u_streaming_ctrl,

				.frontend_attach = rtl2831u_frontend_attach,
				.tuner_attach    = rtl2831u_tuner_attach,
				.stream = {
					.type = USB_BULK,
					.count = 6,
					.endpoint = 0x81,
					.u = {
						.bulk = {
							.buffersize = 4096,
						}
					}
				},
			}
		},

		.power_ctrl = rtl2831u_power_ctrl,

		.i2c_algo = &rtl2831u_i2c_algo,

		.num_device_descs = 9,
		.devices = {
			{
				.name = "RTL2831U DVB-T USB2.0 DEVICE",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[0], NULL},
			},
			{
				.name = "RTL2831U DVB-T USB2.0 DEVICE",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[1], NULL},
			},
			{
				.name = "DVB-T TV-Tuner Card-R",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[7], NULL},
			},
			{
				.name = "VideoMate TV U100",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[8], NULL},
			},
			{
				.name = "VideoMate U90",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[9], NULL},
			},
			{
				.name = "Vestel DVB-T TV Card",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[10], NULL},
			},
			{
				.name = "Freecom USB2.0 DVB-T",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[11], NULL},
			},
			{
				.name = "Freecom USB2.0 DVB-T",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[12], NULL},
			},
			{
				.name = "Fujtec",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[13], NULL},
			},
		}
	}, {
		.caps = DVB_USB_IS_AN_I2C_ADAPTER,

		.usb_ctrl = DEVICE_SPECIFIC,
		.no_reconnect = 1,

		.size_of_priv = sizeof(struct rtl2831u_priv),

		.num_adapters = 1,
		.adapter = {
			{
				.streaming_ctrl  = rtl2831u_streaming_ctrl,

				.frontend_attach  = rtl2831u_frontend_attach,
				.tuner_attach     = rtl2831u_tuner_attach,
				.stream = {
					.type = USB_BULK,
					.count = 6,
					.endpoint = 0x81,
					.u = {
						.bulk = {
							.buffersize = 4096,
						}
					}
				},
			}
		},

		.power_ctrl = rtl2831u_power_ctrl,

		.i2c_algo = &rtl2831u_i2c_algo,

		.num_device_descs = 5,
		.devices = {
			{
				.name = "DTV-DVB UDTT 7047-USB 2.0 DVB-T",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[2], NULL},
			},
			{
				.name = "DTV-DVB UDTT 7047M-USB 2.0 DVB-T",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[3], NULL},
			},
			{
				.name = "DTV-DVB UDTT 7047A-USB 2.0 DVB-T",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[4], NULL},
			},
			{
				.name = "DTV-DVB UDTT 704L-USB 2.0 DVB-T",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[5], NULL},
			},
			{
				.name = "DTV-DVB UDTT 7047Z-USB 2.0 DVB-T",
				.cold_ids = {NULL},
				.warm_ids = {&rtl2831u_table[6], NULL},
			},
		}
	},
};

static int rtl2831u_probe(struct usb_interface *intf,
			const struct usb_device_id *id)
{
	int ret = 0;
	struct dvb_usb_device *d = NULL;
	u8 i;
	u8 properties_count = ARRAY_SIZE(rtl2831u_properties);

	deb_info("%s: interface:%d\n", __func__,
		intf->cur_altsetting->desc.bInterfaceNumber);

	if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {

	for (i = 0; i < properties_count; i++) {
		ret = dvb_usb_device_init(intf, &rtl2831u_properties[i],
			THIS_MODULE, &d, adapter_nr);
		if (!ret)
			return 0;
		if (ret != -ENODEV) {
			deb_info("%s: failed:%d\n", __func__, ret);
			return ret;
		}
	}
	
	}

	return -ENODEV;
}

static struct usb_driver rtl2831u_driver = {
	.name       = "dvb_usb_rtl2831u",
	.probe      = rtl2831u_probe,
	.disconnect = dvb_usb_device_exit,
	.id_table   = rtl2831u_table,
};

/* module stuff */
static int __init rtl2831u_module_init(void)
{
	int ret;
	deb_info("%s:\n", __func__);
	ret = usb_register(&rtl2831u_driver);
	if (ret)
		err("usb_register failed:%d", ret);

	return ret;
}

static void __exit rtl2831u_module_exit(void)
{
	deb_info("%s:\n", __func__);
	/* deregister this driver from the USB subsystem */
	usb_deregister(&rtl2831u_driver);
}

module_init(rtl2831u_module_init);
module_exit(rtl2831u_module_exit);

MODULE_DESCRIPTION("Realtek RTL2831U DVB-T USB2.0 driver");
MODULE_AUTHOR("ChiaLing"); /* Realtek */
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");
