[PATCH] Driver for RTL2832 demodulator chip

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

 



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@xxxxxxxxxxxxxx>
Date: Sun, 29 Apr 2012 22:51:26 +0200
Subject: [PATCH] First version of RTL2832 demod driver
Cc: Linux Media Mailing List <linux-media@xxxxxxxxxxxxxxx>

Signed-off-by: Thomas Mair <thomas.mair86@xxxxxxxxxxxxxx>
---
 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...@xxxxxxx>
+ *
+ * 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...@xxxxxxx>
+ *
+ * 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...@xxxxxxx>");
+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...@xxxxxxx>
+ *
+ * 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@xxxxxx>
  * Copyright (C) 2011 Antti Palosaari <crope@xxxxxx>
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@xxxxxxxxxxxxxx>
  *
  *    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@xxxxxx>");
+MODULE_AUTHOR("Thomas Mair <thomas.mair86@xxxxxxxxxxxxxx>");
 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@xxxxxxxxx>
+ *
+ *    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@xxxxxxxxx>");
+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@xxxxxxxxx>
+ *
+ *    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@xxxxxxxxx>
+ *
+ *    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 */
-- 
1.7.7.6
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux