All of lore.kernel.org
 help / color / mirror / Atom feed
From: poma <pomidorabelisima@gmail.com>
To: linux-media@vger.kernel.org
Subject: Re: [PATCH] Driver for RTL2832 demodulator chip
Date: Mon, 30 Apr 2012 11:38:25 +0200	[thread overview]
Message-ID: <4F9E5D91.30503@gmail.com> (raw)
In-Reply-To: <CAKZ=SG_ZZ__y5Hqq2zwk6KL4kpyqe++hM=mKi8ZwndxSWWtSaQ@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 75583 bytes --]

On 04/29/2012 11:42 PM, Thomas Mair wrote:
> Hello,
> 
> I just finished the driver for the RTL2832 demodulator chip. The patch
> contais modifications of Antti's rtl28xxu driver and a modified
> version of the fc0012 driver from Hans-Frieder Vogt posted recently on
> this list.
> 
> The driver as of now just implements the bare minimum to be working.
> The features I plan to add next are:
> - Remote control
> - Signal quality readings
> - Hardware PID filtering
> 
> I tested the driver with the Terratec Cinergy T Stick Black, which is
> the only device supported so far.
> 
> Regrads
> Thomas
> 
> From f6f653264cdd440bcbd09323e5a3445a7bcab96a Mon Sep 17 00:00:00 2001
> From: Thomas Mair <thomas.mair86@googlemail.com>
> Date: Sun, 29 Apr 2012 22:51:26 +0200
> Subject: [PATCH] First version of RTL2832 demod driver
> Cc: Linux Media Mailing List <linux-media@vger.kernel.org>
> 
> Signed-off-by: Thomas Mair <thomas.mair86@googlemail.com>
> ---
>  drivers/media/common/tuners/Kconfig        |    7 +
>  drivers/media/common/tuners/Makefile       |    1 +
>  drivers/media/common/tuners/fc0012-priv.h  |   42 ++
>  drivers/media/common/tuners/fc0012.c       |  384 +++++++++++++
>  drivers/media/common/tuners/fc0012.h       |   60 ++
>  drivers/media/dvb/dvb-usb/Kconfig          |    2 +
>  drivers/media/dvb/dvb-usb/dvb-usb-ids.h    |    1 +
>  drivers/media/dvb/dvb-usb/rtl28xxu.c       |  430 ++++++++++++---
>  drivers/media/dvb/frontends/Kconfig        |    7 +
>  drivers/media/dvb/frontends/Makefile       |    2 +-
>  drivers/media/dvb/frontends/rtl2832.c      |  832 ++++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/rtl2832.h      |  300 ++++++++++
>  drivers/media/dvb/frontends/rtl2832_priv.h |   60 ++
>  13 files changed, 2060 insertions(+), 68 deletions(-)
>  create mode 100644 drivers/media/common/tuners/fc0012-priv.h
>  create mode 100644 drivers/media/common/tuners/fc0012.c
>  create mode 100644 drivers/media/common/tuners/fc0012.h
>  create mode 100644 drivers/media/dvb/frontends/rtl2832.c
>  create mode 100644 drivers/media/dvb/frontends/rtl2832.h
>  create mode 100644 drivers/media/dvb/frontends/rtl2832_priv.h
> 
> diff --git a/drivers/media/common/tuners/Kconfig
> b/drivers/media/common/tuners/Kconfig
> index 0fd15d9..8518251 100644
> --- a/drivers/media/common/tuners/Kconfig
> +++ b/drivers/media/common/tuners/Kconfig
> @@ -211,6 +211,13 @@ config MEDIA_TUNER_FC0011
>  	help
>  	  Fitipower FC0011 silicon tuner driver.
> 
> +config MEDIA_TUNER_FC0012
> +	tristate "Fitipower FC0012 silicon tuner"
> +	depends on VIDEO_MEDIA && I2C
> +	default m if MEDIA_TUNER_CUSTOMISE
> +	help
> +	  Fitipower FC0012 silicon tuner driver.
> +
>  config MEDIA_TUNER_TDA18212
>  	tristate "NXP TDA18212 silicon tuner"
>  	depends on VIDEO_MEDIA && I2C
> diff --git a/drivers/media/common/tuners/Makefile
> b/drivers/media/common/tuners/Makefile
> index 64ee06f..f046106 100644
> --- a/drivers/media/common/tuners/Makefile
> +++ b/drivers/media/common/tuners/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
>  obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
>  obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
>  obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
> +obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
> 
>  ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
>  ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
> diff --git a/drivers/media/common/tuners/fc0012-priv.h
> b/drivers/media/common/tuners/fc0012-priv.h
> new file mode 100644
> index 0000000..c2c3c47
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012-priv.h
> @@ -0,0 +1,42 @@
> +/*
> + * Fitipower FC0012 tuner driver - private includes
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * 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.
> + */
> +
> +#ifndef _FC0012_PRIV_H_
> +#define _FC0012_PRIV_H_
> +
> +#define LOG_PREFIX "fc0012"
> +
> +#undef err
> +#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
> +#undef info
> +#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
> +#undef warn
> +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
> +
> +struct fc0012_priv {
> +       struct i2c_adapter *i2c;
> +       u8 addr;
> +       u8 xtal_freq;
> +
> +       u32 frequency;
> +       u32 bandwidth;
> +};
> +
> +#endif
> diff --git a/drivers/media/common/tuners/fc0012.c
> b/drivers/media/common/tuners/fc0012.c
> new file mode 100644
> index 0000000..bb9f008
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012.c
> @@ -0,0 +1,384 @@
> +/*
> + * Fitipower FC0012 tuner driver
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * 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.
> + */
> +
> +#include "fc0012.h"
> +#include "fc0012-priv.h"
> +
> +static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
> +{
> +	u8 buf[2] = {reg, val};
> +	struct i2c_msg msg = { .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 };
> +
> +	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
> +		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
> +	return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
> +{
> +	struct i2c_msg msg[2] = {
> +		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
> +		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
> +	};
> +
> +	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
> +		err("I2C read failed, reg: %02x", reg);
> +		return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int fc0012_release(struct dvb_frontend *fe)
> +{
> +	kfree(fe->tuner_priv);
> +	fe->tuner_priv = NULL;
> +	return 0;
> +}
> +
> +static int fc0012_init(struct dvb_frontend *fe)
> +{
> +	struct fc0012_priv *priv = fe->tuner_priv;
> +	int i, ret = 0;
> +	unsigned char reg[] = {
> +		0x00,   /* dummy reg. 0 */
> +		0x05,   /* reg. 0x01 */
> +		0x10,   /* reg. 0x02 */
> +		0x00,   /* reg. 0x03 */
> +		0x00,   /* reg. 0x04 */
> +		0x0f,   /* reg. 0x05 CHECK: correct? */ /* this is 0x0f in RTL (CNR test) */
> +		0x00,   /* reg. 0x06: divider 2, VCO slow */
> +		0x00,   /* reg. 0x07 */ /* this is also different in RTL code */
> +		0xff,   /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
> +			   Loop Bw 1/8 */
> +		0x6e,   /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
> +		0xb8,   /* reg. 0x0a: Disable LO Test Buffer */
> +		0x82,   /* reg. 0x0b: Output Clock is same as clock frequency */ /*
> also different in RTL*/
> +		0xfc,   /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8
> */ /* RTL */
> +		0x02,   /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
> +		0x00,   /* reg. 0x0e */
> +		0x00,   /* reg. 0x0f */
> +		0x00,   /* reg. 0x10 */ /* RTL */
> +		0x00,   /* reg. 0x11 */
> +		0x1f,   /* reg. 0x12: Set to maximum gain */
> +		0x08,   /* reg. 0x13: Enable IX2, Set to Middle Gain: 0x08,
> +			   Low Gain: 0x00, High Gain: 0x10 */
> +		0x00,   /* reg. 0x14 */
> +		0x04,   /* reg. 0x15: Enable LNA COMPS */
> +	};
> +
> +	info("%s", __func__);
> +
> +	switch (priv->xtal_freq) {
> +	case FC_XTAL_27_MHZ:
> +	case FC_XTAL_28_8_MHZ:
> +		reg[0x07] |= 0x20;
> +		break;
> +	case FC_XTAL_36_MHZ:
> +	default:
> +		break;
> +	}
> +	
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
> +	
> +	for (i = 1; i < sizeof(reg); i++) {
> +		ret = fc0012_writereg(priv, i, reg[i]);
> +	if (ret)
> +		break;
> +	}
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
> +
> +	if (ret)
> +		warn("%s: failed: %d", __func__, ret);
> +	return ret;
> +}
> +
> +static int fc0012_sleep(struct dvb_frontend *fe)
> +{
> +	/* nothing to do here */
> +	return 0;
> +}
> +
> +static int fc0012_set_params(struct dvb_frontend *fe)
> +{
> +	struct fc0012_priv *priv = fe->tuner_priv;
> +	int i, ret = 0;
> +	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
> +	u32 freq = p->frequency / 1000;
> +	u32 delsys = p->delivery_system;
> +	unsigned char reg[0x16], am, pm, multi;
> +	unsigned long fVCO;
> +	unsigned short xtal_freq_khz_2, xin, xdiv;
> +	int vco_select = false;
> +
> +	info("%s", __func__);
> +
> +	if(fe->callback){
> +		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
> FC0012_FE_CALLBACK_UHF_ENABLE, (freq > 300000 ? 0 : 1));
> +		if (ret)
> +			goto exit;
> +	}
> +	
> +	switch (priv->xtal_freq) {
> +	case FC_XTAL_27_MHZ:
> +		xtal_freq_khz_2 = 27000 / 2;
> +		break;
> +	case FC_XTAL_36_MHZ:
> +		xtal_freq_khz_2 = 36000 / 2;
> +		break;
> +	case FC_XTAL_28_8_MHZ:
> +	default:
> +		xtal_freq_khz_2 = 28800 / 2;
> +		break;
> +	}
> +
> +	/* select frequency divider and the frequency of VCO */
> +	if (freq * 96 < 3560000) {
> +		multi = 96;
> +		reg[5] = 0x82;
> +		reg[6] = 0x00;
> +	} else if (freq * 64 < 3560000) {
> +		multi = 64;
> +		reg[5] = 0x82;
> +		reg[6] = 0x02;
> +	} else if (freq * 48 < 3560000) {
> +		multi = 48;
> +		reg[5] = 0x42;
> +		reg[6] = 0x00;
> +	} else if (freq * 32 < 3560000) {
> +		multi = 32;
> +		reg[5] = 0x42;
> +		reg[6] = 0x02;
> +	} else if (freq * 24 < 3560000) {
> +		multi = 24;
> +		reg[5] = 0x22;
> +		reg[6] = 0x00;
> +	} else if (freq * 16 < 3560000) {
> +		multi = 16;
> +		reg[5] = 0x22;
> +		reg[6] = 0x02;
> +	} else if (freq * 12 < 3560000) {
> +		multi = 12;
> +		reg[5] = 0x12;
> +		reg[6] = 0x00;
> +	} else if (freq * 8 < 3560000) {
> +		multi = 8;
> +		reg[5] = 0x12;
> +		reg[6] = 0x02;
> +	} else if (freq * 6 < 3560000) {
> +		multi = 6;
> +		reg[5] = 0x0a;
> +		reg[6] = 0x00;
> +	} else {
> +		multi = 4;
> +		reg[5] = 0x0a;
> +		reg[6] = 0x02;
> +	}
> +
> +	fVCO = freq * multi;
> +	
> +	reg[6] |= 0x08;
> +	vco_select = true;
> +
> +	/* From divided value (XDIV) determined the FA and FP value */
> +	xdiv = (unsigned short)(fVCO / xtal_freq_khz_2);
> +	if ((fVCO - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
> +		xdiv++;
> +	
> +	pm = (unsigned char)(xdiv / 8);
> +	am = (unsigned char)(xdiv - (8 * pm));
> +	
> +	if (am < 2) {
> +		reg[1] = am + 8;
> +		reg[2] = pm - 1;
> +	} else {
> +		reg[1] = am;
> +		reg[2] = pm;
> +	}
> +
> +
> +	/* From VCO frequency determines the XIN ( fractional part of Delta
> +	Sigma PLL) and divided value (XDIV) */
> + 	xin = (unsigned short)(fVCO - (fVCO / xtal_freq_khz_2) * xtal_freq_khz_2);
> +	xin = (xin << 15) / xtal_freq_khz_2;
> +	if (xin >= 16384)
> +		xin += 32768;
> +
> +	reg[3] = xin >> 8;      /* xin with 9 bit resolution */
> +	reg[4] = xin & 0xff;
> +
> +	if (delsys == SYS_DVBT) {
> +		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
> +		switch (p->bandwidth_hz) {
> +		case 6000000:
> +			reg[6] |= 0x80;
> +			break;
> +		case 7000000:
> +			reg[6] &= ~0x80;
> +			reg[6] |= 0x40;
> +			break;
> +		case 8000000:
> +		default:
> +			reg[6] &= ~0xc0;
> +			break;
> +	}
> +	} else {
> +		err("%s: modulation type not supported!", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* modified for Realtek demod */
> +	reg[5] |= 0x07;
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
> +
> +	for (i = 1; i <= 6; i++) {
> +		ret = fc0012_writereg(priv, i, reg[i]);
> +		if (ret)
> +			goto exit;
> +       }
> +
> +	/* VCO Calibration */
> +	ret = fc0012_writereg(priv, 0x0e, 0x80);
> +	if (!ret)
> +		ret = fc0012_writereg(priv, 0x0e, 0x00);
> +
> +	/* VCO Re-Calibration if needed */
> +	if (!ret)
> +		ret = fc0012_writereg(priv, 0x0e, 0x00);
> +
> +	if (!ret) {
> +		msleep(10);
> +		ret = fc0012_readreg(priv, 0x0e, &reg[0x0e]);
> +	}
> +	if (ret)
> +		goto exit;
> +
> +	/* vco selection */
> +	reg[0x0e] &= 0x3f;
> +
> +	if (vco_select) {
> +		if (reg[0x0e] > 0x3c) {
> +		reg[6] &= ~0x08;
> +			ret = fc0012_writereg(priv, 0x06, reg[6]);
> +		if (!ret)
> +			ret = fc0012_writereg(priv, 0x0e, 0x80);
> +		if (!ret)
> +			ret = fc0012_writereg(priv, 0x0e, 0x00);
> +	       }
> +	} else {
> +		if (reg[0x0e] < 0x02) {
> +			reg[6] |= 0x08;
> +			ret = fc0012_writereg(priv, 0x06, reg[6]);
> +			if (!ret)
> +				ret = fc0012_writereg(priv, 0x0e, 0x80);
> +			if (!ret)
> +				ret = fc0012_writereg(priv, 0x0e, 0x00);
> +		}
> +	}
> +
> +	priv->frequency = p->frequency;
> +	priv->bandwidth = p->bandwidth_hz;
> +
> +exit:
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
> +	if (ret)
> +		pr_debug("%s: failed: %d", __func__, ret);
> +	return ret;
> +}
> +
> +static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
> +{
> +       struct fc0012_priv *priv = fe->tuner_priv;
> +       *frequency = priv->frequency;
> +       return 0;
> +}
> +
> +static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
> +{
> +       /* CHECK: always ? */
> +       *frequency = 0;
> +       return 0;
> +}
> +
> +static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
> +{
> +       struct fc0012_priv *priv = fe->tuner_priv;
> +       *bandwidth = priv->bandwidth;
> +       return 0;
> +}
> +
> +
> +static const struct dvb_tuner_ops fc0012_tuner_ops = {
> +       .info = {
> +	       .name		= "Fitipower FC0012",
> +
> +	       .frequency_min	= 170000000,
> +	       .frequency_max	= 860000000,
> +	       .frequency_step	= 0,
> +       },
> +
> +       .release	= fc0012_release,
> +
> +       .init = fc0012_init,
> +       .sleep = fc0012_sleep,
> +
> +       .set_params = fc0012_set_params,
> +
> +       .get_frequency = fc0012_get_frequency,
> +       .get_if_frequency = fc0012_get_if_frequency,
> +       .get_bandwidth = fc0012_get_bandwidth,
> +};
> +
> +struct dvb_frontend * fc0012_attach(struct dvb_frontend *fe,
> +       struct i2c_adapter *i2c, u8 i2c_address,
> +       enum fc0012_xtal_freq xtal_freq)
> +{
> +       struct fc0012_priv *priv = NULL;
> +
> +       priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
> +       if (priv == NULL)
> +	       return NULL;
> +
> +       priv->i2c = i2c;
> +       priv->addr = i2c_address;
> +       priv->xtal_freq = xtal_freq;
> +
> +       info("Fitipower FC0012 successfully attached.");
> +
> +       fe->tuner_priv = priv;
> +
> +       memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
> +	       sizeof(struct dvb_tuner_ops));
> +
> +       return fe;
> +}
> +EXPORT_SYMBOL(fc0012_attach);
> +
> +MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
> +MODULE_AUTHOR("Hans-Frieder Vogt <hfv...@gmx.net>");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("0.4");
> diff --git a/drivers/media/common/tuners/fc0012.h
> b/drivers/media/common/tuners/fc0012.h
> new file mode 100644
> index 0000000..1406e58
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012.h
> @@ -0,0 +1,60 @@
> +/*
> + * Fitipower FC0012 tuner driver - include
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * 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.
> + */
> +
> +#ifndef _FC0012_H_
> +#define _FC0012_H_
> +
> +#include "dvb_frontend.h"
> +
> +enum fc0012_xtal_freq {
> +       FC_XTAL_27_MHZ,         /* 27000000 */
> +       FC_XTAL_28_8_MHZ,       /* 28800000 */
> +       FC_XTAL_36_MHZ,         /* 36000000 */
> +};
> +
> +
> +/** enum fc0011_fe_callback_commands - Frontend callbacks
> + *
> + * @FC0012_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
> + */
> +enum fc0012_fe_callback_commands {
> +	FC0012_FE_CALLBACK_UHF_ENABLE,
> +};
> +
> +#define CONFIG_MEDIA_TUNER_FC0012
> +
> +#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
> +        (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
> +                                       struct i2c_adapter *i2c,
> +                                       u8 i2c_address,
> +                                       enum fc0012_xtal_freq xtal_freq);
> +#else
> +static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
> +                                               struct i2c_adapter *i2c,
> +                                               u8 i2c_address,
> +                                               enum fc0012_xtal_freq xtal_freq)
> +{
> +       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +       return NULL;
> +}
> +#endif
> +
> +#endif
> diff --git a/drivers/media/dvb/dvb-usb/Kconfig
> b/drivers/media/dvb/dvb-usb/Kconfig
> index be1db75..a24bbc1 100644
> --- a/drivers/media/dvb/dvb-usb/Kconfig
> +++ b/drivers/media/dvb/dvb-usb/Kconfig
> @@ -417,9 +417,11 @@ config DVB_USB_RTL28XXU
>  	tristate "Realtek RTL28xxU DVB USB support"
>  	depends on DVB_USB && EXPERIMENTAL
>  	select DVB_RTL2830
> +	select DVB_RTL2832
>  	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
>  	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
>  	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
> +	select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
>  	help
>  	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
> 
> diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> index 2418e41..19e942e 100644
> --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> @@ -238,6 +238,7 @@
>  #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
>  #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
>  #define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
> +#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK		0x00a9
>  #define USB_PID_TERRATEC_H7				0x10b4
>  #define USB_PID_TERRATEC_H7_2				0x10a3
>  #define USB_PID_TERRATEC_T3				0x10a0
> diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c
> b/drivers/media/dvb/dvb-usb/rtl28xxu.c
> index 8f4736a..bc9f966 100644
> --- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
> +++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
> @@ -3,6 +3,7 @@
>   *
>   * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
>   * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
>   *
>   *    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
> @@ -22,10 +23,12 @@
>  #include "rtl28xxu.h"
> 
>  #include "rtl2830.h"
> +#include "rtl2832.h"
> 
>  #include "qt1010.h"
>  #include "mt2060.h"
>  #include "mxl5005s.h"
> +#include "fc0012.h"
> 
>  /* debug */
>  static int dvb_usb_rtl28xxu_debug;
> @@ -76,7 +79,7 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device
> *d, struct rtl28xxu_req *req)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -297,7 +300,7 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	/* for QT1010 tuner probe */
>  	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
> 
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
> 
>  	/*
>  	 * RTL2831U GPIOs
> @@ -312,6 +315,7 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret)
>  		goto err;
> 
> +
>  	/* enable as output GPIO0, GPIO2, GPIO4 */
>  	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
>  	if (ret)
> @@ -332,10 +336,10 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret == 0 && buf[0] == 0x2c) {
>  		priv->tuner = TUNER_RTL2830_QT1010;
>  		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
> -		deb_info("%s: QT1010\n", __func__);
> +		deb_info("%s: QT1010", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: QT1010 probe failed=%d - %02x\n",
> +		deb_info("%s: QT1010 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
> 
> @@ -349,10 +353,10 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret == 0 && buf[0] == 0x63) {
>  		priv->tuner = TUNER_RTL2830_MT2060;
>  		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
> -		deb_info("%s: MT2060\n", __func__);
> +		deb_info("%s: MT2060", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: MT2060 probe failed=%d - %02x\n",
> +		deb_info("%s: MT2060 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
> 
> @@ -360,7 +364,7 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	ret = 0;
>  	priv->tuner = TUNER_RTL2830_MXL5005S;
>  	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
> -	deb_info("%s: MXL5005S\n", __func__);
> +	deb_info("%s: MXL5005S", __func__);
>  	goto found;
> 
>  found:
> @@ -374,37 +378,130 @@ found:
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
> +	.i2c_addr = 0x10, /* 0x20 */
> +	.xtal = 28800000,
> +	.ts_mode = 0,
> +	.spec_inv = 1,
> +	.if_dvbt = 0,
> +	.vtop = 0x20,
> +	.krf = 0x04,
> +	.agc_targ_val = 0x2d,
> +	.tuner = TUNER_RTL2832_FC0012
> +};
> +
> +
> +static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
> +		int cmd, int arg)
> +{
> +	int ret;
> +	u8 val;
> +
> +	info("%s cmd=%d arg=%d", __func__, cmd, arg);
> +	switch (cmd) {
> +	case FC0012_FE_CALLBACK_UHF_ENABLE:
> +		/* set output values */
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_DIR, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0xbf;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_DIR, val);
> +		if (ret)
> +			goto err;
> +
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x40;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
> +		if (ret)
> +			goto err;
> +
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +			goto err;
> +
> +		if (arg)
> +			val &= 0xbf; /* set GPIO6 low */
> +		else
> +			val |= 0x40; /* set GPIO6 high */
> +		
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +	return 0;
> +
> +err:
> +	err("%s: failed=%d", __func__, ret);
> +
>  	return ret;
>  }
> 
> +static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
> +{
> +	struct rtl28xxu_priv *priv = d->priv;
> +
> +	switch (priv->tuner) {
> +	case TUNER_RTL2832_FC0012:
> +		return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
> +	default:
> +		break;
> +	}
> +
> +	return -ENODEV;
> +}
> +
> +static int rtl2832u_frontend_callback(void *adapter_priv, int component,
> +				    int cmd, int arg)
> +{
> +	struct i2c_adapter *adap = adapter_priv;
> +	struct dvb_usb_device *d = i2c_get_adapdata(adap);
> +
> +	switch (component) {
> +	case DVB_FRONTEND_COMPONENT_TUNER:
> +		return rtl2832u_tuner_callback(d, cmd, arg);
> +	default:
> +		break;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +
> +
> +
>  static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
>  {
>  	int ret;
>  	struct rtl28xxu_priv *priv = adap->dev->priv;
> +	struct rtl2832_config *rtl2832_config;
> +
>  	u8 buf[1];
>  	/* open RTL2832U/RTL2832 I2C gate */
>  	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
>  	/* close RTL2832U/RTL2832 I2C gate */
>  	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
> -	/* for FC2580 tuner probe */
> -	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
> +	/* for FC0012 tuner probe */
> +	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
> 
> -	deb_info("%s:\n", __func__);
> -
> -	/* GPIO direction */
> -	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
> -	if (ret)
> -		goto err;
> -
> -	/* enable as output GPIO0, GPIO2, GPIO4 */
> -	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
> -	if (ret)
> -		goto err;
> -
> -	ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
> -	if (ret)
> -		goto err;
> +	deb_info("%s:", __func__);
> 
>  	/*
>  	 * Probe used tuner. We need to know used tuner before demod attach
> @@ -416,17 +513,20 @@ static int rtl2832u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret)
>  		goto err;
> 
> -	/* check FC2580 ID register; reg=01 val=56 */
> -	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
> -	if (ret == 0 && buf[0] == 0x56) {
> -		priv->tuner = TUNER_RTL2832_FC2580;
> -		deb_info("%s: FC2580\n", __func__);
> +
> +	/* check FC0012 ID register; reg=00 val=a1 */
> +	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
> +	if (ret == 0 && buf[0] == 0xa1) {
> +		priv->tuner = TUNER_RTL2832_FC0012;
> +		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
> +		deb_info("%s: FC0012", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: FC2580 probe failed=%d - %02x\n",
> +		deb_info("%s: FC0012 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
> 
> +
>  	/* close demod I2C gate */
>  	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
>  	if (ret)
> @@ -443,11 +543,19 @@ found:
>  		goto err;
> 
>  	/* attach demodulator */
> -	/* TODO: */
> +	adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
> +		&adap->dev->i2c_adap, priv->tuner);
> +		if (adap->fe_adap[0].fe == NULL) {
> +			ret = -ENODEV;
> +			goto err;
> +		}
> +
> +	/* set fe callbacks */
> +	adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -484,7 +592,7 @@ static int rtl2831u_tuner_attach(struct
> dvb_usb_adapter *adap)
>  	struct i2c_adapter *rtl2830_tuner_i2c;
>  	struct dvb_frontend *fe;
> 
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
> 
>  	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
>  	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
> @@ -515,7 +623,7 @@ static int rtl2831u_tuner_attach(struct
> dvb_usb_adapter *adap)
> 
>  	return 0;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -525,12 +633,13 @@ static int rtl2832u_tuner_attach(struct
> dvb_usb_adapter *adap)
>  	struct rtl28xxu_priv *priv = adap->dev->priv;
>  	struct dvb_frontend *fe;
> 
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
> 
>  	switch (priv->tuner) {
> -	case TUNER_RTL2832_FC2580:
> -		/* TODO: */
> -		fe = NULL;
> +	case TUNER_RTL2832_FC0012:
> +		fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
> +			&adap->dev->i2c_adap, 0xc6>>1, FC_XTAL_28_8_MHZ);
> +		return 0;
>  		break;
>  	default:
>  		fe = NULL;
> @@ -544,16 +653,16 @@ static int rtl2832u_tuner_attach(struct
> dvb_usb_adapter *adap)
> 
>  	return 0;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> -static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
> +static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
>  {
>  	int ret;
>  	u8 buf[2], gpio;
> 
> -	deb_info("%s: onoff=%d\n", __func__, onoff);
> +	deb_info("%s: onoff=%d", __func__, onoff);
> 
>  	ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
>  	if (ret)
> @@ -579,16 +688,186 @@ static int rtl28xxu_streaming_ctrl(struct
> dvb_usb_adapter *adap , int onoff)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
> +{
> +	int ret;
> +	u8 buf[2];
> +
> +	deb_info("%s: onoff=%d", __func__, onoff);
> +
> +
> +	if (onoff) {
> +		buf[0] = 0x00;
> +		buf[1] = 0x00;
> +	} else {
> +		buf[0] = 0x10; /* stall EPA */
> +		buf[1] = 0x02; /* reset EPA */
> +	}
> +
> +	ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
> +	if (ret)
> +		goto err;
> +
> +	return ret;
> +err:
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> -static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
> +
> +static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) {
> +
> +	int ret;
> +	struct rtl28xxu_req req;
> +	u8 val;
> +
> +	deb_info("%s: onoff=%d", __func__, onoff);
> +
> +	if(onoff){
> +		/* set output values */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x08;
> +		val &= 0xef;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* enable as output GPIO3 */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x08;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod_ctl_1 */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0xef;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod control */
> +		/* PLL enable */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		/* bit 7 to 1 */
> +		val |= 0x80;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod HW reset */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +		/* bit 5 to 0 */
> +		val &= 0xdf;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x20;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* set page cache to 0 */
> +		req.index = 0x0;
> +		req.value = 0x20 + (1<<8);
> +		req.data = &val;
> +		req.size = 1;
> +		ret = rtl28xxu_ctrl_msg(d, &req);
> +		if (ret)
> +			goto err;
> +
> +
> +		mdelay(5);
> +
> +		/*enable ADC_Q and ADC_I */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x48;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +
> +	} else {
> +		/* demod_ctl_1 */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x0c;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
> +		if (ret)
> +			goto err;
> +
> +		/* set output values */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +				goto err;
> +
> +		val |= 0x10;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod control */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0x37;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +	}
> +
> +	return ret;
> +err:
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
>  {
>  	int ret;
>  	u8 gpio, sys0;
> 
> -	deb_info("%s: onoff=%d\n", __func__, onoff);
> +	deb_info("%s: onoff=%d", __func__, onoff);
> 
>  	/* demod adc */
>  	ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
> @@ -600,12 +879,12 @@ static int rtl28xxu_power_ctrl(struct
> dvb_usb_device *d, int onoff)
>  	if (ret)
>  		goto err;
> 
> -	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
> +	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
> 
>  	if (onoff) {
>  		gpio |= 0x01; /* GPIO0 = 1 */
>  		gpio &= (~0x10); /* GPIO4 = 0 */
> -		sys0 = sys0 & 0x0f;
> +		sys0 = sys0 & 0x0f; /* enable demod adc */
>  		sys0 |= 0xe0;
>  	} else {
>  		gpio &= (~0x01); /* GPIO0 = 0 */
> @@ -613,7 +892,7 @@ static int rtl28xxu_power_ctrl(struct
> dvb_usb_device *d, int onoff)
>  		sys0 = sys0 & (~0xc0);
>  	}
> 
> -	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
> +	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
> 
>  	/* demod adc */
>  	ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
> @@ -627,7 +906,7 @@ static int rtl28xxu_power_ctrl(struct
> dvb_usb_device *d, int onoff)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -699,10 +978,12 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> +/* unused for now */
> +#if 0
>  static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  {
>  	int ret, i;
> @@ -760,14 +1041,16 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  exit:
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> +#endif
> 
>  enum rtl28xxu_usb_table_entry {
>  	RTL2831U_0BDA_2831,
>  	RTL2831U_14AA_0160,
>  	RTL2831U_14AA_0161,
> +	RTL2832U_0CCD_00A9,
>  };
> 
>  static struct usb_device_id rtl28xxu_table[] = {
> @@ -780,6 +1063,8 @@ static struct usb_device_id rtl28xxu_table[] = {
>  		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
> 
>  	/* RTL2832U */
> +	[RTL2832U_0CCD_00A9] = {
> +		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
>  	{} /* terminating entry */
>  };
> 
> @@ -802,7 +1087,7 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  					{
>  						.frontend_attach = rtl2831u_frontend_attach,
>  						.tuner_attach    = rtl2831u_tuner_attach,
> -						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
> +						.streaming_ctrl  = rtl2831u_streaming_ctrl,
>  						.stream = {
>  							.type = USB_BULK,
>  							.count = 6,
> @@ -818,7 +1103,7 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  			}
>  		},
> 
> -		.power_ctrl = rtl28xxu_power_ctrl,
> +		.power_ctrl = rtl2831u_power_ctrl,
> 
>  		.rc.core = {
>  			.protocol       = RC_TYPE_NEC,
> @@ -864,11 +1149,11 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  					{
>  						.frontend_attach = rtl2832u_frontend_attach,
>  						.tuner_attach    = rtl2832u_tuner_attach,
> -						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
> +						.streaming_ctrl  = rtl2832u_streaming_ctrl,
>  						.stream = {
>  							.type = USB_BULK,
> -							.count = 6,
> -							.endpoint = 0x81,
> +							.count = 10,
> +							.endpoint = 0x01,
>  							.u = {
>  								.bulk = {
>  									.buffersize = 8*512,
> @@ -880,23 +1165,26 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  			}
>  		},
> 
> -		.power_ctrl = rtl28xxu_power_ctrl,
> +		.power_ctrl = rtl2832u_power_ctrl,
> 
> -		.rc.core = {
> +		/*.rc.core = {
>  			.protocol       = RC_TYPE_NEC,
>  			.module_name    = "rtl28xxu",
>  			.rc_query       = rtl2832u_rc_query,
>  			.rc_interval    = 400,
>  			.allowed_protos = RC_TYPE_NEC,
>  			.rc_codes       = RC_MAP_EMPTY,
> -		},
> +		},*/
> 
>  		.i2c_algo = &rtl28xxu_i2c_algo,
> 
> -		.num_device_descs = 0, /* disabled as no support for RTL2832 */
> +		.num_device_descs = 1,
>  		.devices = {
>  			{
> -				.name = "Realtek RTL2832U reference design",
> +				.name = "Terratec Cinergy T Stick Black",
> +				.warm_ids = {
> +					&rtl28xxu_table[RTL2832U_0CCD_00A9],
> +				},
>  			},
>  		}
>  	},
> @@ -907,10 +1195,11 @@ static int rtl28xxu_probe(struct usb_interface *intf,
>  		const struct usb_device_id *id)
>  {
>  	int ret, i;
> +	u8 val;
>  	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
>  	struct dvb_usb_device *d;
> 
> -	deb_info("%s: interface=%d\n", __func__,
> +	deb_info("%s: interface=%d", __func__,
>  		intf->cur_altsetting->desc.bInterfaceNumber);
> 
>  	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
> @@ -926,22 +1215,31 @@ static int rtl28xxu_probe(struct usb_interface *intf,
>  	if (ret)
>  		goto err;
> 
> +
>  	/* init USB endpoints */
> -	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
> +	ret = rtl2831_rd_reg(d, USB_SYSCTL_0, &val);
> +	if (ret)
> +			goto err;
> +
> +	/* enable DMA and Full Packet Mode*/
> +	val |= 0x09;
> +	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, val);
>  	if (ret)
>  		goto err;
> 
> +	/* set EPA maximum packet size to 0x0200 */
>  	ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
>  	if (ret)
>  		goto err;
> 
> +	/* change EPA FIFO length */
>  	ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
>  	if (ret)
>  		goto err;
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -957,8 +1255,6 @@ static int __init rtl28xxu_module_init(void)
>  {
>  	int ret;
> 
> -	deb_info("%s:\n", __func__);
> -
>  	ret = usb_register(&rtl28xxu_driver);
>  	if (ret)
>  		err("usb_register failed=%d", ret);
> @@ -968,7 +1264,6 @@ static int __init rtl28xxu_module_init(void)
> 
>  static void __exit rtl28xxu_module_exit(void)
>  {
> -	deb_info("%s:\n", __func__);
> 
>  	/* deregister this driver from the USB subsystem */
>  	usb_deregister(&rtl28xxu_driver);
> @@ -979,4 +1274,5 @@ module_exit(rtl28xxu_module_exit);
> 
>  MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
>  MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
> +MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
>  MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/Kconfig
> b/drivers/media/dvb/frontends/Kconfig
> index f479834..f7d67d7 100644
> --- a/drivers/media/dvb/frontends/Kconfig
> +++ b/drivers/media/dvb/frontends/Kconfig
> @@ -432,6 +432,13 @@ config DVB_RTL2830
>  	help
>  	  Say Y when you want to support this frontend.
> 
> +config DVB_RTL2832
> +	tristate "Realtek RTL2832 DVB-T"
> +	depends on DVB_CORE && I2C
> +	default m if DVB_FE_CUSTOMISE
> +	help
> +	  Say Y when you want to support this frontend.
> +
>  comment "DVB-C (cable) frontends"
>  	depends on DVB_CORE
> 
> diff --git a/drivers/media/dvb/frontends/Makefile
> b/drivers/media/dvb/frontends/Makefile
> index b0381dc..a109aae 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -100,4 +100,4 @@ obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
>  obj-$(CONFIG_DVB_AF9033) += af9033.o
> -
> +obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
> diff --git a/drivers/media/dvb/frontends/rtl2832.c
> b/drivers/media/dvb/frontends/rtl2832.c
> new file mode 100644
> index 0000000..920b068
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832.c
> @@ -0,0 +1,832 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    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.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include "rtl2832_priv.h"
> +
> +
> +
> +int rtl2832_debug = 1;
> +module_param_named(debug, rtl2832_debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
> +
> +
> +static int reg_mask[32] = {
> +    0x00000001,
> +    0x00000003,
> +    0x00000007,
> +    0x0000000f,
> +    0x0000001f,
> +    0x0000003f,
> +    0x0000007f,
> +    0x000000ff,
> +    0x000001ff,
> +    0x000003ff,
> +    0x000007ff,
> +    0x00000fff,
> +    0x00001fff,
> +    0x00003fff,
> +    0x00007fff,
> +    0x0000ffff,
> +    0x0001ffff,
> +    0x0003ffff,
> +    0x0007ffff,
> +    0x000fffff,
> +    0x001fffff,
> +    0x003fffff,
> +    0x007fffff,
> +    0x00ffffff,
> +    0x01ffffff,
> +    0x03ffffff,
> +    0x07ffffff,
> +    0x0fffffff,
> +    0x1fffffff,
> +    0x3fffffff,
> +    0x7fffffff,
> +    0xffffffff
> +};
> +
> +static const rtl2832_reg_entry registers[] = {
> +  [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2},
> +  [DVBT_IIC_REPEAT] = {0x1,  0x1,   3,  3},
> +  [DVBT_TR_WAIT_MIN_8K]   = {0x1,  0x88,   11,  2},
> +  [DVBT_RSD_BER_FAIL_VAL] = {0x1,  0x8f,   15,  0},
> +  [DVBT_EN_BK_TRK]        = {0x1,  0xa6,   7,  7},
> +  [DVBT_AD_EN_REG]        = {0x0,  0x8,   7,  7},
> +  [DVBT_AD_EN_REG1]       = {0x0,  0x8,   6,  6},
> +  [DVBT_EN_BBIN]          = {0x1,  0xb1,   0,  0},
> +  [DVBT_MGD_THD0]         = {0x1,  0x95,   7,  0},
> +  [DVBT_MGD_THD1]         = {0x1,  0x96,   7,  0},
> +  [DVBT_MGD_THD2]         = {0x1,  0x97,   7,  0},
> +  [DVBT_MGD_THD3]         = {0x1,  0x98,   7,  0},
> +  [DVBT_MGD_THD4]         = {0x1,  0x99,   7,  0},
> +  [DVBT_MGD_THD5]         = {0x1,  0x9a,   7,  0},
> +  [DVBT_MGD_THD6]         = {0x1,  0x9b,   7,  0},
> +  [DVBT_MGD_THD7]         = {0x1,  0x9c,   7,  0},
> +  [DVBT_EN_CACQ_NOTCH]    = {0x1,  0x61,   4,  4},
> +  [DVBT_AD_AV_REF]        = {0x0,  0x9,   6,  0},
> +  [DVBT_REG_PI]           = {0x0,  0xa,   2,  0},
> +  [DVBT_PIP_ON]           = {0x0,  0x21,   3,  3},
> +  [DVBT_SCALE1_B92]       = {0x2,  0x92,   7,  0},
> +  [DVBT_SCALE1_B93]       = {0x2,  0x93,   7,  0},
> +  [DVBT_SCALE1_BA7]       = {0x2,  0xa7,   7,  0},
> +  [DVBT_SCALE1_BA9]       = {0x2,  0xa9,   7,  0},
> +  [DVBT_SCALE1_BAA]       = {0x2,  0xaa,   7,  0},
> +  [DVBT_SCALE1_BAB]       = {0x2,  0xab,   7,  0},
> +  [DVBT_SCALE1_BAC]       = {0x2,  0xac,   7,  0},
> +  [DVBT_SCALE1_BB0]       = {0x2,  0xb0,   7,  0},
> +  [DVBT_SCALE1_BB1]       = {0x2,  0xb1,   7,  0},
> +  [DVBT_KB_P1]            = {0x1,  0x64,   3,  1},
> +  [DVBT_KB_P2]            = {0x1,  0x64,   6,  4},
> +  [DVBT_KB_P3]            = {0x1,  0x65,   2,  0},
> +  [DVBT_OPT_ADC_IQ]       = {0x0,  0x6,   5,  4},
> +  [DVBT_AD_AVI]           = {0x0,  0x9,   1,  0},
> +  [DVBT_AD_AVQ]           = {0x0,  0x9,   3,  2},
> +  [DVBT_K1_CR_STEP12]     = {0x2,  0xad,   9,  4},
> +  [DVBT_TRK_KS_P2]        = {0x1,  0x6f,   2,  0},
> +  [DVBT_TRK_KS_I2]        = {0x1,  0x70,   5,  3},
> +  [DVBT_TR_THD_SET2]      = {0x1,  0x72,   3,  0},
> +  [DVBT_TRK_KC_P2]        = {0x1,  0x73,   5,  3},
> +  [DVBT_TRK_KC_I2]        = {0x1,  0x75,   2,  0},
> +  [DVBT_CR_THD_SET2]      = {0x1,  0x76,   7,  6},
> +  [DVBT_PSET_IFFREQ]     = {0x1,  0x19,   21,  0},
> +  [DVBT_SPEC_INV]        = {0x1,  0x15,   0,  0},
> +  [DVBT_RSAMP_RATIO]     = {0x1,  0x9f,   27,  2},
> +  [DVBT_CFREQ_OFF_RATIO] = {0x1,  0x9d,   23,  4},
> +  [DVBT_FSM_STAGE]       = {0x3,  0x51,   6,  3},
> +  [DVBT_RX_CONSTEL]      = {0x3,  0x3c,   3,  2},
> +  [DVBT_RX_HIER]         = {0x3,  0x3c,   6,  4},
> +  [DVBT_RX_C_RATE_LP]    = {0x3,  0x3d,   2,  0},
> +  [DVBT_RX_C_RATE_HP]    = {0x3,  0x3d,   5,  3},
> +  [DVBT_GI_IDX]          = {0x3,  0x51,   1,  0},
> +  [DVBT_FFT_MODE_IDX]    = {0x3,  0x51,   2,  2},
> +  [DVBT_RSD_BER_EST]     = {0x3,  0x4e,   15,  0},
> +  [DVBT_CE_EST_EVM]      = {0x4,  0xc,   15,  0},
> +  [DVBT_RF_AGC_VAL]      = {0x3,  0x5b,   13,  0},
> +  [DVBT_IF_AGC_VAL]      = {0x3,  0x59,   13,  0},
> +  [DVBT_DAGC_VAL]        = {0x3,  0x5,   7,  0},
> +  [DVBT_SFREQ_OFF]       = {0x3,  0x18,   13,  0},
> +  [DVBT_CFREQ_OFF]       = {0x3,  0x5f,   17,  0},
> +  [DVBT_POLAR_RF_AGC]    = {0x0,  0xe,   1,  1},
> +  [DVBT_POLAR_IF_AGC]    = {0x0,  0xe,   0,  0},
> +  [DVBT_AAGC_HOLD]       = {0x1,  0x4,   5,  5},
> +  [DVBT_EN_RF_AGC]       = {0x1,  0x4,   6,  6},
> +  [DVBT_EN_IF_AGC]       = {0x1,  0x4,   7,  7},
> +  [DVBT_IF_AGC_MIN]      = {0x1,  0x8,   7,  0},
> +  [DVBT_IF_AGC_MAX]      = {0x1,  0x9,   7,  0},
> +  [DVBT_RF_AGC_MIN]      = {0x1,  0xa,   7,  0},
> +  [DVBT_RF_AGC_MAX]      = {0x1,  0xb,   7,  0},
> +  [DVBT_IF_AGC_MAN]      = {0x1,  0xc,   6,  6},
> +  [DVBT_IF_AGC_MAN_VAL]  = {0x1,  0xc,   13,  0},
> +  [DVBT_RF_AGC_MAN]      = {0x1,  0xe,   6,  6},
> +  [DVBT_RF_AGC_MAN_VAL]  = {0x1,  0xe,   13,  0},
> +  [DVBT_DAGC_TRG_VAL]    = {0x1,  0x12,   7,  0},
> +  [DVBT_AGC_TARG_VAL_0]  = {0x1,  0x2,   0,  0},
> +  [DVBT_AGC_TARG_VAL_8_1] = {0x1,  0x3,   7,  0},
> +  [DVBT_AAGC_LOOP_GAIN]  = {0x1,  0xc7,   5,  1},
> +  [DVBT_LOOP_GAIN2_3_0]  = {0x1,  0x4,   4,  1},
> +  [DVBT_LOOP_GAIN2_4]    = {0x1,  0x5,   7,  7},
> +  [DVBT_LOOP_GAIN3]      = {0x1,  0xc8,   4,  0},
> +  [DVBT_VTOP1]           = {0x1,  0x6,   5,  0},
> +  [DVBT_VTOP2]           = {0x1,  0xc9,   5,  0},
> +  [DVBT_VTOP3]           = {0x1,  0xca,   5,  0},
> +  [DVBT_KRF1]            = {0x1,  0xcb,   7,  0},
> +  [DVBT_KRF2]            = {0x1,  0x7,   7,  0},
> +  [DVBT_KRF3]            = {0x1,  0xcd,   7,  0},
> +  [DVBT_KRF4]            = {0x1,  0xce,   7,  0},
> +  [DVBT_EN_GI_PGA]       = {0x1,  0xe5,   0,  0},
> +  [DVBT_THD_LOCK_UP]     = {0x1,  0xd9,   8,  0},
> +  [DVBT_THD_LOCK_DW]     = {0x1,  0xdb,   8,  0},
> +  [DVBT_THD_UP1]         = {0x1,  0xdd,   7,  0},
> +  [DVBT_THD_DW1]         = {0x1,  0xde,   7,  0},
> +  [DVBT_INTER_CNT_LEN]   = {0x1,  0xd8,   3,  0},
> +  [DVBT_GI_PGA_STATE]    = {0x1,  0xe6,   3,  3},
> +  [DVBT_EN_AGC_PGA]      = {0x1,  0xd7,   0,  0},
> +  [DVBT_CKOUTPAR]        = {0x1,  0x7b,   5,  5},
> +  [DVBT_CKOUT_PWR]       = {0x1,  0x7b,   6,  6},
> +  [DVBT_SYNC_DUR]        = {0x1,  0x7b,   7,  7},
> +  [DVBT_ERR_DUR]         = {0x1,  0x7c,   0,  0},
> +  [DVBT_SYNC_LVL]        = {0x1,  0x7c,   1,  1},
> +  [DVBT_ERR_LVL]         = {0x1,  0x7c,   2,  2},
> +  [DVBT_VAL_LVL]         = {0x1,  0x7c,   3,  3},
> +  [DVBT_SERIAL]          = {0x1,  0x7c,   4,  4},
> +  [DVBT_SER_LSB]         = {0x1,  0x7c,   5,  5},
> +  [DVBT_CDIV_PH0]        = {0x1,  0x7d,   3,  0},
> +  [DVBT_CDIV_PH1]        = {0x1,  0x7d,   7,  4},
> +  [DVBT_MPEG_IO_OPT_2_2] = {0x0,  0x6,   7,  7},
> +  [DVBT_MPEG_IO_OPT_1_0] = {0x0,  0x7,   7,  6},
> +  [DVBT_CKOUTPAR_PIP]    = {0x0,  0xb7,   4,  4},
> +  [DVBT_CKOUT_PWR_PIP]   = {0x0,  0xb7,   3,  3},
> +  [DVBT_SYNC_LVL_PIP]    = {0x0,  0xb7,   2,  2},
> +  [DVBT_ERR_LVL_PIP]     = {0x0,  0xb7,   1,  1},
> +  [DVBT_VAL_LVL_PIP]     = {0x0,  0xb7,   0,  0},
> +  [DVBT_CKOUTPAR_PID]    = {0x0,  0xb9,   4,  4},
> +  [DVBT_CKOUT_PWR_PID]   = {0x0,  0xb9,   3,  3},
> +  [DVBT_SYNC_LVL_PID]    = {0x0,  0xb9,   2,  2},
> +  [DVBT_ERR_LVL_PID]     = {0x0,  0xb9,   1,  1},
> +  [DVBT_VAL_LVL_PID]     = {0x0,  0xb9,   0,  0},
> +  [DVBT_SM_PASS]         = {0x1,  0x93,   11,  0},
> +  [DVBT_AD7_SETTING]     = {0x0,  0x11,   15,  0},
> +  [DVBT_RSSI_R]          = {0x3,  0x1,   6,  0},
> +  [DVBT_ACI_DET_IND]     = {0x3,  0x12,   0,  0},
> +  [DVBT_REG_MON]        = {0x0,  0xd,   1,  0},
> +  [DVBT_REG_MONSEL]     = {0x0,  0xd,   2,  2},
> +  [DVBT_REG_GPE]        = {0x0,  0xd,   7,  7},
> +  [DVBT_REG_GPO]        = {0x0,  0x10,   0,  0},
> +  [DVBT_REG_4MSEL]      = {0x0,  0x13,   0,  0},
> +};
> +
> +
> +
> +/* write multiple hardware registers */
> +static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
> +{
> +	int ret;
> +	u8 buf[1+len];
> +	struct i2c_msg msg[1] = {
> +		{
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = 0,
> +			.len = 1+len,
> +			.buf = buf,
> +		}
> +	};
> +
> +	buf[0] = reg;
> +	memcpy(&buf[1], val, len);
> +
> +	ret = i2c_transfer(priv->i2c, msg, 1);
> +	if (ret == 1) {
> +		ret = 0;
> +	} else {
> +		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
> +		ret = -EREMOTEIO;
> +	}
> +	return ret;
> +}
> +
> +/* read multiple hardware registers */
> +static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
> +{
> +	int ret;
> +	struct i2c_msg msg[2] = {
> +		{
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = 0,
> +			.len = 1,
> +			.buf = &reg,
> +		}, {
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = I2C_M_RD,
> +			.len = len,
> +			.buf = val,
> +		}
> +	};
> +
> +	ret = i2c_transfer(priv->i2c, msg, 2);
> +	if (ret == 2) {
> +		ret = 0;
> +	} else {
> +		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
> +		ret = -EREMOTEIO;
> +	}
> +	return ret;
> +}
> +
> +/* write multiple registers */
> +static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8
> page, u8 *val, int len)
> +{
> +	int ret;
> +
> +
> +	/* switch bank if needed */
> +	if (page != priv->page) {
> +		ret = rtl2832_wr(priv, 0x00, &page, 1);
> +		if (ret)
> +			return ret;
> +
> +		priv->page = page;
> +	}
> +
> +	return rtl2832_wr(priv, reg, val, len);
> +}
> +
> +/* read multiple registers */
> +static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8
> page, u8 *val, int len)
> +{
> +	int ret;
> +
> +	/* switch bank if needed */
> +	if (page != priv->page) {
> +		ret = rtl2832_wr(priv, 0x00, &page, 1);
> +		if (ret)
> +			return ret;
> +
> +		priv->page = page;
> +	}
> +
> +	return rtl2832_rd(priv, reg, val, len);
> +}
> +
> +#if 0 /* currently not used */
> +/* write single register */
> +static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
> +{
> +	return rtl2832_wr_regs(priv, reg, page, &val, 1);
> +}
> +#endif
> +
> +/* read single register */
> +static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
> +{
> +	return rtl2832_rd_regs(priv, reg, page, val, 1);
> +}
> +
> +int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val){
> +	int ret;
> +
> +	u8 reg_start_addr;
> +	u8 msb, lsb;
> +	u8 page;
> +	u8 reading[4];
> +	u32 reading_tmp;
> +	int i;
> +
> +	u8 len;
> +	u32 mask;
> +
> +	reg_start_addr = registers[reg].start_address;
> +	msb = registers[reg].msb;
> +	lsb = registers[reg].lsb;
> +	page = registers[reg].page;
> +
> +	len = (msb >> 3) + 1;
> +	mask = reg_mask[msb-lsb];
> +
> +
> +	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
> +	if (ret)
> +		goto err;
> +
> +	reading_tmp = 0;
> +	for(i = 0; i < len; i++){
> +		reading_tmp |= reading[i] << ((len-1-i)*8);
> +	}
> +
> +	*val = (reading_tmp >> lsb) & mask;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +
> +}
> +
> +int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
> +{
> +	int ret, i;
> +	u8 len;
> +	u8 reg_start_addr;
> +	u8 msb, lsb;
> +	u8 page;
> +	u32 mask;
> +
> +
> +	u8 reading[4];
> +	u8 writing[4];
> +	u32 reading_tmp;
> +	u32 writing_tmp;
> +
> +
> +	reg_start_addr = registers[reg].start_address;
> +	msb = registers[reg].msb;
> +	lsb = registers[reg].lsb;
> +	page = registers[reg].page;
> +
> +	len = (msb >> 3) + 1;
> +	mask = reg_mask[msb-lsb];
> +
> +
> +	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
> +	if (ret)
> +		goto err;
> +
> +	reading_tmp = 0;
> +	for (i = 0; i < len; i++) {
> +		reading_tmp |= reading[i] << ((len-1-i)*8);
> +	}
> +
> +	writing_tmp = reading_tmp & ~(mask << lsb);
> +	writing_tmp |= ((val & mask) << lsb);
> +
> +
> +	for (i = 0; i < len; i++) {
> +		writing[i] = (writing_tmp >> ((len-1-i)*8)) & 0xff;
> +	}
> +
> +	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
> +	if(ret)
> +		goto err;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +
> +}
> +
> +
> +static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
> +{
> +	int ret;
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	dbg("%s: enable=%d", __func__, enable);
> +
> +	/* gate already open or close */
> +	if (priv->i2c_gate_state == enable)
> +		return 0;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable?0x1:0x0));
> +
> +	if (ret)
> +		goto err;
> +
> +	priv->i2c_gate_state = enable;
> +
> +	return ret;
> +err:
> +	dbg("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +
> +
> +static int rtl2832_init(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	int i, ret;
> +
> +	u8 en_bbin;
> +	u64 pset_iffreq;
> +
> +	/* initialization values for the demodulator registers */
> +	static rtl2832_reg_value rtl2832_initial_regs_1[] = {
> +			{DVBT_AD_EN_REG,			0x1		},
> +			{DVBT_AD_EN_REG1,			0x1		},
> +			{DVBT_RSD_BER_FAIL_VAL,		0x2800	},
> +			{DVBT_MGD_THD0,				0x10	},
> +			{DVBT_MGD_THD1,				0x20	},
> +			{DVBT_MGD_THD2,				0x20	},
> +			{DVBT_MGD_THD3,				0x40	},
> +			{DVBT_MGD_THD4,				0x22	},
> +			{DVBT_MGD_THD5,				0x32	},
> +			{DVBT_MGD_THD6,				0x37	},
> +			{DVBT_MGD_THD7,				0x39	},
> +			{DVBT_EN_BK_TRK,			0x0		},
> +			{DVBT_EN_CACQ_NOTCH,		0x0		},
> +			{DVBT_AD_AV_REF,			0x2a	},
> +			{DVBT_REG_PI,				0x6		},
> +			{DVBT_PIP_ON,				0x0		},
> +			{DVBT_CDIV_PH0,				0x8		},
> +			{DVBT_CDIV_PH1,				0x8		},
> +			{DVBT_SCALE1_B92,			0x4		},
> +			{DVBT_SCALE1_B93,			0xb0	},
> +			{DVBT_SCALE1_BA7,			0x78	},
> +			{DVBT_SCALE1_BA9,			0x28	},
> +			{DVBT_SCALE1_BAA,			0x59	},
> +			{DVBT_SCALE1_BAB,			0x83	},
> +			{DVBT_SCALE1_BAC,			0xd4	},
> +			{DVBT_SCALE1_BB0,			0x65	},
> +			{DVBT_SCALE1_BB1,			0x43	},
> +			{DVBT_KB_P1,				0x1		},
> +			{DVBT_KB_P2,				0x4		},
> +			{DVBT_KB_P3,				0x7		},
> +			{DVBT_K1_CR_STEP12,			0xa		},
> +			{DVBT_REG_GPE,				0x1		},
> +			{DVBT_SERIAL,				0x0},
> +			{DVBT_CDIV_PH0,				0x9},
> +			{DVBT_CDIV_PH1,				0x9},
> +			{DVBT_MPEG_IO_OPT_2_2,		0x0},
> +			{DVBT_MPEG_IO_OPT_1_0,		0x0},
> +			{DVBT_TRK_KS_P2,			0x4},
> +			{DVBT_TRK_KS_I2,			0x7},
> +			{DVBT_TR_THD_SET2,			0x6},
> +			{DVBT_TRK_KC_I2,			0x5},
> +			{DVBT_CR_THD_SET2,			0x1},
> +
> +
> +		};
> +
> +	static rtl2832_reg_value rtl2832_initial_regs_2[] = {
> +			{DVBT_SPEC_INV,				0x0},
> +			{DVBT_DAGC_TRG_VAL,			0x5a	},
> +			{DVBT_AGC_TARG_VAL_0,		0x0		},
> +			{DVBT_AGC_TARG_VAL_8_1,		0x5a	},
> +			{DVBT_AAGC_LOOP_GAIN,		0x16    },
> +			{DVBT_LOOP_GAIN2_3_0,		0x6		},
> +			{DVBT_LOOP_GAIN2_4,			0x1		},
> +			{DVBT_LOOP_GAIN3,			0x16	},
> +			{DVBT_VTOP1,				0x35	},
> +			{DVBT_VTOP2,				0x21	},
> +			{DVBT_VTOP3,				0x21	},
> +			{DVBT_KRF1,					0x0		},
> +			{DVBT_KRF2,					0x40	},
> +			{DVBT_KRF3,					0x10	},
> +			{DVBT_KRF4,					0x10	},
> +			{DVBT_IF_AGC_MIN,			0x80	},
> +			{DVBT_IF_AGC_MAX,			0x7f	},
> +			{DVBT_RF_AGC_MIN,			0x80	},
> +			{DVBT_RF_AGC_MAX,			0x7f	},
> +			{DVBT_POLAR_RF_AGC,			0x0		},
> +			{DVBT_POLAR_IF_AGC,			0x0		},
> +			{DVBT_AD7_SETTING,			0xe9bf	},
> +			{DVBT_EN_GI_PGA,			0x0		},
> +			{DVBT_THD_LOCK_UP,			0x0		},
> +			{DVBT_THD_LOCK_DW,			0x0		},
> +			{DVBT_THD_UP1,				0x11	},
> +			{DVBT_THD_DW1,				0xef	},
> +			{DVBT_INTER_CNT_LEN,		0xc		},
> +			{DVBT_GI_PGA_STATE,			0x0		},
> +			{DVBT_EN_AGC_PGA,			0x1		},
> +			{DVBT_IF_AGC_MAN,			0x0		},
> +		};
> +
> +
> +	info("%s", __func__);
> +
> +	en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
> +
> +	/* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) /
> CrystalFreqHz) */
> +	pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
> +	pset_iffreq *= 0x400000;
> +	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
> +	pset_iffreq = pset_iffreq & 0x3fffff;
> +
> +
> +
> +	for (i = 0; i < 42; i++) {
> +		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_1[i].reg,
> rtl2832_initial_regs_1[i].value);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	/* if frequency settings */
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
> +		if (ret)
> +			goto err;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
> +		if(ret)
> +			goto err;
> +
> +	for (i = 0; i < 31; i++) {
> +		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_2[i].reg,
> rtl2832_initial_regs_2[i].value);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	priv->sleeping = false;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +}
> +
> +static int rtl2832_sleep(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	info("%s", __func__);
> +	priv->sleeping = true;
> +	return 0;
> +}
> +
> +int rtl2832_get_tune_settings(struct dvb_frontend *fe,
> +	struct dvb_frontend_tune_settings *s)
> +{
> +	info("%s", __func__);
> +	s->min_delay_ms = 1000;
> +	s->step_size = fe->ops.info.frequency_stepsize * 2;
> +	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
> +	return 0;
> +}
> +
> +static int rtl2832_set_frontend(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +	int ret, i, j;
> +	u64 bw_mode, num, num2;
> +	u32 resamp_ratio, cfreq_off_ratio;
> +
> +
> +	static u8 bw_params[3][32] = {
> +		/* 6 MHz bandwidth */
> +		{
> +			0xf5,	0xff,	0x15,	0x38,	0x5d,	0x6d,	0x52,	0x07,	0xfa,	0x2f,
> +			0x53,	0xf5,	0x3f,	0xca,	0x0b,	0x91,	0xea,	0x30,	0x63,	0xb2,
> +			0x13,	0xda,	0x0b,	0xc4,	0x18,	0x7e,	0x16,	0x66,	0x08,	0x67,
> +			0x19,	0xe0,
> +		},
> +
> +		/*  7 MHz bandwidth */
> +		{
> +			0xe7,	0xcc,	0xb5,	0xba,	0xe8,	0x2f,	0x67,	0x61,	0x00,	0xaf,
> +			0x86,	0xf2,	0xbf,	0x59,	0x04,	0x11,	0xb6,	0x33,	0xa4,	0x30,
> +			0x15,	0x10,	0x0a,	0x42,	0x18,	0xf8,	0x17,	0xd9,	0x07,	0x22,
> +			0x19,	0x10,
> +		},
> +
> +		/*  8 MHz bandwidth */
> +		{
> +			0x09,	0xf6,	0xd2,	0xa7,	0x9a,	0xc9,	0x27,	0x77,	0x06,	0xbf,
> +			0xec,	0xf4,	0x4f,	0x0b,	0xfc,	0x01,	0x63,	0x35,	0x54,	0xa7,
> +			0x16,	0x66,	0x08,	0xb4,	0x19,	0x6e,	0x19,	0x65,	0x05,	0xc8,
> +			0x19,	0xe0,
> +		},
> +	};
> +
> +
> +	info("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
> +			c->frequency, c->bandwidth_hz, c->inversion);
> +
> +
> +	/* program tuner */
> +	if (fe->ops.tuner_ops.set_params)
> +		fe->ops.tuner_ops.set_params(fe);
> +
> +
> +	switch (c->bandwidth_hz) {
> +		case 6000000:
> +			i = 0;
> +			bw_mode = 48000000;
> +			break;
> +		case 7000000:
> +			i = 1;
> +			bw_mode = 56000000;
> +			break;
> +		case 8000000:
> +			i = 2;
> +			bw_mode = 64000000;
> +			break;
> +		default:
> +			dbg("invalid bandwidth");
> +			return -EINVAL;
> +		}
> +
> +	for (j = 0; j < 32; j++){
> +		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	/* calculate and set resample ratio */
> +	/* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) /
> ConstWithBandwidthMode) */
> +	num = priv->cfg.xtal * 7;
> +	num *= 0x400000;
> +	num = div_u64(num, bw_mode);
> +	resamp_ratio =  num & 0x3ffffff;
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
> +	if (ret)
> +		goto err;
> +
> +	/* calculate and set cfreq off ratio */
> +	/* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20) /
> (CrystalFreqHz * 7)) */
> +	num = bw_mode << 20;
> +	num2 = priv->cfg.xtal * 7;
> +	num = div_u64(num, num2);
> +	num = -num;
> +	cfreq_off_ratio = num & 0xfffff;
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
> +	if (ret)
> +		goto err;
> +
> +
> +	/* soft reset */
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
> +	if (ret)
> +		goto err;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
> +	if (ret)
> +		goto err;
> +
> +	return ret;
> +err:
> +	info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	int ret;
> +	u32 tmp;
> +	*status = 0;
> +
> +
> +	info("%s", __func__);
> +	if (priv->sleeping)
> +		return 0;
> +
> +	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
> +	if (ret)
> +		goto err;
> +
> +	if (tmp == 11) {
> +		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
> +			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +	}
> +	/* TODO find out if this is also true */
> +	/*else if (tmp == 10) {
> +		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
> +			FE_HAS_VITERBI;
> +	}*/
> +
> +	return ret;
> +err:
> +	info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
> +{
> +	info("%s", __func__);
> +	*snr = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
> +{
> +	info("%s", __func__);
> +	*ber = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +	info("%s", __func__);
> +	*ucblocks = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
> +{
> +	info("%s", __func__);
> +	*strength = 0;
> +	return 0;
> +}
> +
> +static struct dvb_frontend_ops rtl2832_ops;
> +
> +static void rtl2832_release(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	info("%s", __func__);
> +	kfree(priv);
> +}
> +
> +struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
> +	struct i2c_adapter *i2c, u8 tuner)
> +{
> +	struct rtl2832_priv *priv = NULL;
> +	int ret = 0;
> +	u8 tmp;
> +
> +	info("%s", __func__);
> +
> +	/* allocate memory for the internal state */
> +	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
> +	if (priv == NULL)
> +		goto err;
> +
> +	/* setup the priv */
> +	priv->i2c = i2c;
> +	priv->tuner = tuner;
> +	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
> +
> +	/* check if the demod is there */
> +	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
> +	if (ret)
> +		goto err;
> +
> +	/* create dvb_frontend */
> +	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
> +	priv->fe.demodulator_priv = priv;
> +
> +	/* TODO implement sleep mode depending on RC */
> +	priv->sleeping = true;
> +
> +	return &priv->fe;
> +err:
> +	dbg("%s: failed=%d", __func__, ret);
> +	kfree(priv);
> +	return NULL;
> +}
> +EXPORT_SYMBOL(rtl2832_attach);
> +
> +static struct dvb_frontend_ops rtl2832_ops = {
> +	.delsys = { SYS_DVBT },
> +	.info = {
> +		.name = "Realtek RTL2832 (DVB-T)",
> +		.type               = FE_OFDM,
> +		.frequency_min      = 50000000,
> +		.frequency_max      = 862000000,
> +		.frequency_stepsize = 166667,
> +		.caps = FE_CAN_FEC_1_2 |
> +			FE_CAN_FEC_2_3 |
> +			FE_CAN_FEC_3_4 |
> +			FE_CAN_FEC_5_6 |
> +			FE_CAN_FEC_7_8 |
> +			FE_CAN_FEC_AUTO |
> +			FE_CAN_QPSK |
> +			FE_CAN_QAM_16 |
> +			FE_CAN_QAM_64 |
> +			FE_CAN_QAM_AUTO |
> +			FE_CAN_TRANSMISSION_MODE_AUTO |
> +			FE_CAN_GUARD_INTERVAL_AUTO |
> +			FE_CAN_HIERARCHY_AUTO |
> +			FE_CAN_RECOVER |
> +			FE_CAN_MUTE_TS
> +	},
> +
> +	.release = rtl2832_release,
> +
> +	.init = rtl2832_init,
> +	.sleep = rtl2832_sleep,
> +
> +	.get_tune_settings = rtl2832_get_tune_settings,
> +
> +	.set_frontend = rtl2832_set_frontend,
> +
> +	.read_status = rtl2832_read_status,
> +	.read_snr = rtl2832_read_snr,
> +	.read_ber = rtl2832_read_ber,
> +	.read_ucblocks = rtl2832_read_ucblocks,
> +	.read_signal_strength = rtl2832_read_signal_strength,
> +	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
> +};
> +
> +MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
> +MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("0.1");
> diff --git a/drivers/media/dvb/frontends/rtl2832.h
> b/drivers/media/dvb/frontends/rtl2832.h
> new file mode 100644
> index 0000000..b16631a
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832.h
> @@ -0,0 +1,300 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    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.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#ifndef RTL2832_H
> +#define RTL2832_H
> +
> +#include <linux/dvb/frontend.h>
> +
> +struct rtl2832_config {
> +	/*
> +	 * Demodulator I2C address.
> +	 */
> +	u8 i2c_addr;
> +
> +	/*
> +	 * Xtal frequency.
> +	 * Hz
> +	 * 4000000, 16000000, 25000000, 28800000
> +	 */
> +	u32 xtal;
> +
> +	/*
> +	 * IFs for all used modes.
> +	 * Hz
> +	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
> +	 */
> +	u32 if_dvbt;
> +
> +	/*
> +	 */
> +	u8 tuner;
> +};
> +
> +
> +#if defined(CONFIG_DVB_RTL2832) || \
> +	(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *rtl2832_attach(
> +	const struct rtl2832_config *cfg,
> +	struct i2c_adapter *i2c,
> +	u8 tuner
> +);
> +
> +extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
> +	struct dvb_frontend *fe
> +);
> +#else
> +static inline struct dvb_frontend *rtl2832_attach(
> +	const struct rtl2832_config *config,
> +	struct i2c_adapter *i2c
> +)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +
> +static inline struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
> +	struct dvb_frontend *fe
> +)
> +{
> +	return NULL;
> +}
> +#endif
> +
> +
> +/* Demod register bit names */
> +enum DVBT_REG_BIT_NAME
> +{
> +	DVBT_SOFT_RST,
> +	DVBT_IIC_REPEAT,
> +	DVBT_TR_WAIT_MIN_8K,
> +	DVBT_RSD_BER_FAIL_VAL,
> +	DVBT_EN_BK_TRK,
> +	DVBT_REG_PI,
> +	DVBT_REG_PFREQ_1_0,
> +	DVBT_PD_DA8,
> +	DVBT_LOCK_TH,
> +	DVBT_BER_PASS_SCAL,
> +	DVBT_CE_FFSM_BYPASS,
> +	DVBT_ALPHAIIR_N,
> +	DVBT_ALPHAIIR_DIF,
> +	DVBT_EN_TRK_SPAN,
> +	DVBT_LOCK_TH_LEN,
> +	DVBT_CCI_THRE,
> +	DVBT_CCI_MON_SCAL,
> +	DVBT_CCI_M0,
> +	DVBT_CCI_M1,
> +	DVBT_CCI_M2,
> +	DVBT_CCI_M3,
> +	DVBT_SPEC_INIT_0,
> +	DVBT_SPEC_INIT_1,
> +	DVBT_SPEC_INIT_2,
> +	DVBT_AD_EN_REG,
> +	DVBT_AD_EN_REG1,
> +	DVBT_EN_BBIN,
> +	DVBT_MGD_THD0,
> +	DVBT_MGD_THD1,
> +	DVBT_MGD_THD2,
> +	DVBT_MGD_THD3,
> +	DVBT_MGD_THD4,
> +	DVBT_MGD_THD5,
> +	DVBT_MGD_THD6,
> +	DVBT_MGD_THD7,
> +	DVBT_EN_CACQ_NOTCH,
> +	DVBT_AD_AV_REF,	
> +	DVBT_PIP_ON,
> +	DVBT_SCALE1_B92,
> +	DVBT_SCALE1_B93,
> +	DVBT_SCALE1_BA7,
> +	DVBT_SCALE1_BA9,
> +	DVBT_SCALE1_BAA,
> +	DVBT_SCALE1_BAB,
> +	DVBT_SCALE1_BAC,
> +	DVBT_SCALE1_BB0,
> +	DVBT_SCALE1_BB1,
> +	DVBT_KB_P1,
> +	DVBT_KB_P2,
> +	DVBT_KB_P3,
> +	DVBT_OPT_AD
> +	DVBT_AD_AVI
> +	DVBT_AD_AVQ
> +	DVBT_K1_CR_STEP12,
> +	DVBT_TRK_KS_P2,
> +	DVBT_TRK_KS_I2,
> +	DVBT_TR_THD_SET2,
> +	DVBT_TRK_KC_P2,
> +	DVBT_TRK_KC_I2,
> +	DVBT_CR_THD_SET2,
> +	DVBT_PSET_IFFREQ,
> +	DVBT_SPEC_INV,
> +	DVBT_BW_INDEX,
> +	DVBT_RSAMP_RATIO,
> +	DVBT_CFREQ_OFF_RATIO,
> +	DVBT_FSM_STAGE,
> +	DVBT_RX_CONSTEL,
> +	DVBT_RX_HIER,
> +	DVBT_RX_C_RATE_LP,
> +	DVBT_RX_C_RATE_HP,
> +	DVBT_GI_IDX,
> +	DVBT_FFT_MODE_IDX,
> +	DVBT_RSD_BER_EST,
> +	DVBT_CE_EST_EVM,
> +	DVBT_RF_AGC_VAL,
> +	DVBT_IF_AGC_VAL,
> +	DVBT_DAGC_VAL,
> +	DVBT_SFREQ_OFF,
> +	DVBT_CFREQ_OFF,
> +	DVBT_POLAR_RF_AGC,
> +	DVBT_POLAR_IF_AGC,
> +	DVBT_AAGC_HOLD,
> +	DVBT_EN_RF_AGC,
> +	DVBT_EN_IF_AGC,
> +	DVBT_IF_AGC_MIN,
> +	DVBT_IF_AGC_MAX,
> +	DVBT_RF_AGC_MIN,
> +	DVBT_RF_AGC_MAX,
> +	DVBT_IF_AGC_MAN,
> +	DVBT_IF_AGC_MAN_VAL,
> +	DVBT_RF_AGC_MAN,
> +	DVBT_RF_AGC_MAN_VAL,
> +	DVBT_DAGC_TRG_VAL,
> +	DVBT_AGC_TARG_VAL,
> +	DVBT_LOOP_GAIN_3_0,
> +	DVBT_LOOP_GAIN_4,
> +	DVBT_VTOP,	
> +	DVBT_KRF,
> +	DVBT_AGC_TARG_VAL_0,
> +	DVBT_AGC_TARG_VAL_8_1,
> +	DVBT_AAGC_LOOP_GAIN,
> +	DVBT_LOOP_GAIN2_3_0,
> +	DVBT_LOOP_GAIN2_4,
> +	DVBT_LOOP_GAIN3,
> +	DVBT_VTOP1,
> +	DVBT_VTOP2,
> +	DVBT_VTOP3,
> +	DVBT_KRF1,
> +	DVBT_KRF2,
> +	DVBT_KRF3,
> +	DVBT_KRF4,
> +	DVBT_EN_GI_PGA,
> +	DVBT_THD_LOCK_UP,
> +	DVBT_THD_LOCK_DW,
> +	DVBT_THD_UP1,
> +	DVBT_THD_DW1,
> +	DVBT_INTER_CNT_LEN,
> +	DVBT_GI_PGA_STATE,
> +	DVBT_EN_AGC_PGA,
> +	DVBT_CKOUTPAR,
> +	DVBT_CKOUT_PWR,
> +	DVBT_SYNC_DUR,
> +	DVBT_ERR_DUR,
> +	DVBT_SYNC_LVL,
> +	DVBT_ERR_LVL,
> +	DVBT_VAL_LVL,
> +	DVBT_SERIAL,
> +	DVBT_SER_LSB,
> +	DVBT_CDIV_PH0,
> +	DVBT_CDIV_PH1,
> +	DVBT_MPEG_IO_OPT_2_2,
> +	DVBT_MPEG_IO_OPT_1_0,
> +	DVBT_CKOUTPAR_PIP,
> +	DVBT_CKOUT_PWR_PIP,
> +	DVBT_SYNC_LVL_PIP,
> +	DVBT_ERR_LVL_PIP,
> +	DVBT_VAL_LVL_PIP,
> +	DVBT_CKOUTPAR_PID,
> +	DVBT_CKOUT_PWR_PID,
> +	DVBT_SYNC_LVL_PID,
> +	DVBT_ERR_LVL_PID,
> +	DVBT_VAL_LVL_PID,
> +	DVBT_SM_PASS,
> +	DVBT_UPDATE_REG_2,
> +	DVBT_BTHD_P3,
> +	DVBT_BTHD_D3,
> +	DVBT_FUNC4_REG0,
> +	DVBT_FUNC4_REG1,
> +	DVBT_FUNC4_REG2,
> +	DVBT_FUNC4_REG3,
> +	DVBT_FUNC4_REG4,
> +	DVBT_FUNC4_REG5,
> +	DVBT_FUNC4_REG6,
> +	DVBT_FUNC4_REG7,
> +	DVBT_FUNC4_REG8,
> +	DVBT_FUNC4_REG9,
> +	DVBT_FUNC4_REG10,
> +	DVBT_FUNC5_REG0,
> +	DVBT_FUNC5_REG1,
> +	DVBT_FUNC5_REG2,
> +	DVBT_FUNC5_REG3,
> +	DVBT_FUNC5_REG4,
> +	DVBT_FUNC5_REG5,
> +	DVBT_FUNC5_REG6,
> +	DVBT_FUNC5_REG7,
> +	DVBT_FUNC5_REG8,
> +	DVBT_FUNC5_REG9,
> +	DVBT_FUNC5_REG10,
> +	DVBT_FUNC5_REG11,
> +	DVBT_FUNC5_REG12,
> +	DVBT_FUNC5_REG13,
> +	DVBT_FUNC5_REG14,
> +	DVBT_FUNC5_REG15,
> +	DVBT_FUNC5_REG16,
> +	DVBT_FUNC5_REG17,
> +	DVBT_FUNC5_REG18,
> +	DVBT_AD7_SETTING,
> +	DVBT_RSSI_R,
> +	DVBT_ACI_DET_IND,
> +	DVBT_REG_MON,
> +	DVBT_REG_MONSEL,
> +	DVBT_REG_GPE,
> +	DVBT_REG_GPO,
> +	DVBT_REG_4MSEL,
> +	DVBT_TEST_REG_1,
> +	DVBT_TEST_REG_2,
> +	DVBT_TEST_REG_3,
> +	DVBT_TEST_REG_4,
> +	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
> +};
> +
> +
> +/* Register table length */
> +#define RTL2832_REG_TABLE_LEN	DVBT_REG_BIT_NAME_ITEM_TERMINATOR
> +
> +typedef struct
> +{
> +	u8 page;
> +	u8 start_address;
> +	u8 msb;
> +	u8 lsb;
> +}
> +rtl2832_reg_entry;
> +
> +typedef struct
> +{
> +	int reg;
> +	u32 value;
> +}
> +rtl2832_reg_value;
> +
> +
> +
> +
> +
> +#endif /* RTL2832_H */
> diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h
> b/drivers/media/dvb/frontends/rtl2832_priv.h
> new file mode 100644
> index 0000000..2f591c6
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832_priv.h
> @@ -0,0 +1,60 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    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.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#ifndef RTL2832_PRIV_H
> +#define RTL2832_PRIV_H
> +
> +#include "dvb_frontend.h"
> +#include "rtl2832.h"
> +
> +#define LOG_PREFIX "rtl2832"
> +
> +#undef dbg
> +#define dbg(f, arg...) \
> +	if (rtl2832_debug) \
> +		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
> +#undef err
> +#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
> +#undef info
> +#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
> +#undef warn
> +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
> +
> +struct rtl2832_priv {
> +	struct i2c_adapter *i2c;
> +	struct dvb_frontend fe;
> +	struct rtl2832_config cfg;
> +
> +	bool i2c_gate_state;
> +	bool sleeping;
> +
> +	u32 xtal;
> +
> +	u8 tuner;
> +	u8 page; /* active register page */
> +};
> +
> +struct rtl2832_reg_val_mask {
> +	u16 reg;
> +	u8  val;
> +	u8  mask;
> +};
> +
> +#endif /* RTL2832_PRIV_H */

Antti, Thomas - thanks!

Please merge these two patches for device:
-DeLOCK USB 2.0 DVB-T Receiver 61744
http://www.delock.com/produkte/gruppen/Multimedia/Delock_USB_20_DVB-T_Receiver_61744.html

lsusb:
..
Bus 002 Device 005: ID 1f4d:b803 G-Tek Electronics Group Lifeview
LV5TDLX DVB-T [RTL2832U]
..

modinfo dvb_usb_rtl28xxu:
filename:
/lib/modules/3.3.2-6.fc16.x86_64/kernel/drivers/media/dvb/dvb-usb/dvb-usb-rtl28xxu.ko
license:        GPL
author:         Thomas Mair <thomas.mair86@googlemail.com>
author:         Antti Palosaari <crope@iki.fi>
description:    Realtek RTL28xxU DVB USB driver
alias:          usb:v1F4DpB803d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0CCDp00A9d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v14AAp0161d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v14AAp0160d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0BDAp2831d*dc*dsc*dp*ic*isc*ip*
depends:        dvb-usb,rtl2830,rc-core
vermagic:       3.3.2-6.fc16.x86_64 SMP mod_unload
parm:           debug:set debugging level (int)
parm:           adapter_nr:DVB adapter numbers (array of short)

dmesg:
..
usb 2-3: new high-speed USB device number 5 using ehci_hcd
usb 2-3: New USB device found, idVendor=1f4d, idProduct=b803
usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 2-3: Product: RTL2838UHIDIR
usb 2-3: Manufacturer: Realtek
usb 2-3: SerialNumber: 00000041
dvb-usb: found a 'G-Tek Electronics Group Lifeview LV5TDLX DVB-T
[RTL2832U]' in warm state.
dvb-usb: will pass the complete MPEG2 transport stream to the software
demuxer.
DVB: registering new adapter (G-Tek Electronics Group Lifeview LV5TDLX
DVB-T [RTL2832U])
rtl2832: rtl2832_attach
DVB: registering adapter 2 frontend 0 (Realtek RTL2832 (DVB-T))...
fc0012: Fitipower FC0012 successfully attached.
dvb-usb: G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]
successfully initialized and connected.
..

lsdvb:

		lsdvb: Simple utility to list PCI/PCIe DVB devices
		Version: 0.0.4
		Copyright (C) Manu Abraham

usb (1:0 -1186842560:58) on PCI Domain:-7907219 Bus:0 Device:-1189043773
Function:58
	..
	DEVICE:0 ADAPTER:2 FRONTEND:0 (Realtek RTL2832 (DVB-T))
		 FE_OFDM Fmin=170MHz Fmax=860MHz


rgds,
poma

[-- Attachment #2: dvb-usb-ids-1f4d_b803.patch --]
[-- Type: text/x-patch, Size: 526 bytes --]

--- media_build/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	2012-04-30 10:40:01.848792922 +0200
+++ media_build-gtek/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	2012-04-30 09:44:51.353128972 +0200
@@ -135,6 +135,7 @@
 #define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
+#define USB_PID_GTEK					0xb803
 #define USB_PID_INTEL_CE9500				0x9500
 #define USB_PID_ITETECH_IT9135				0x9135
 #define USB_PID_ITETECH_IT9135_9005			0x9005

[-- Attachment #3: rtl28xxu-1f4d_b803.patch --]
[-- Type: text/x-patch, Size: 1039 bytes --]

--- media_build/linux/drivers/media/dvb/dvb-usb/rtl28xxu.c	2012-04-30 10:40:01.891790279 +0200
+++ media_build-gtek/linux/drivers/media/dvb/dvb-usb/rtl28xxu.c	2012-04-30 11:00:16.701619034 +0200
@@ -1051,6 +1051,7 @@
 	RTL2831U_14AA_0160,
 	RTL2831U_14AA_0161,
 	RTL2832U_0CCD_00A9,
+	RTL2832U_1F4D_B803,
 };
 
 static struct usb_device_id rtl28xxu_table[] = {
@@ -1065,6 +1066,8 @@
 	/* RTL2832U */
 	[RTL2832U_0CCD_00A9] = {
 		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
+	[RTL2832U_1F4D_B803] = {
+		USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
 	{} /* terminating entry */
 };
 
@@ -1178,7 +1181,7 @@
 
 		.i2c_algo = &rtl28xxu_i2c_algo,
 
-		.num_device_descs = 1,
+		.num_device_descs = 2,
 		.devices = {
 			{
 				.name = "Terratec Cinergy T Stick Black",
@@ -1186,6 +1189,12 @@
 					&rtl28xxu_table[RTL2832U_0CCD_00A9],
 				},
 			},
+			{
+				.name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1F4D_B803],
+				},
+			},
 		}
 	},
 

  reply	other threads:[~2012-04-30  9:38 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-29 21:42 [PATCH] Driver for RTL2832 demodulator chip Thomas Mair
2012-04-30  9:38 ` poma [this message]
2012-04-30 15:39   ` [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744 Thomas Mair
2012-05-01  6:48     ` poma
2012-05-03  7:25       ` poma
2012-05-03  9:03         ` Gianluca Gennari
2012-05-04  1:27           ` poma
2012-05-04 13:49             ` Gianluca Gennari
2012-05-05  0:33               ` poma
2012-05-05 16:01                 ` Thomas Mair
2012-05-05 16:54                   ` Hans-Frieder Vogt
2012-05-05 17:02                   ` Antti Palosaari
2012-05-04 13:57             ` Gianluca Gennari
     [not found]             ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
2012-05-05  0:18               ` poma
2012-05-03 18:17         ` Zdenek Styblik
2012-05-04  1:34           ` poma

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F9E5D91.30503@gmail.com \
    --to=pomidorabelisima@gmail.com \
    --cc=linux-media@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.