* [PATCH] Driver for RTL2832 demodulator chip
@ 2012-04-29 21:42 Thomas Mair
2012-04-30 9:38 ` poma
0 siblings, 1 reply; 16+ messages in thread
From: Thomas Mair @ 2012-04-29 21:42 UTC (permalink / raw)
To: linux-media, Antti Palosaari
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 = ®, .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, ®[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 = ®,
+ }, {
+ .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 */
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH] Driver for RTL2832 demodulator chip
2012-04-29 21:42 [PATCH] Driver for RTL2832 demodulator chip Thomas Mair
@ 2012-04-30 9:38 ` poma
2012-04-30 15:39 ` [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744 Thomas Mair
0 siblings, 1 reply; 16+ messages in thread
From: poma @ 2012-04-30 9:38 UTC (permalink / raw)
To: linux-media
[-- 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 = ®, .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, ®[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 = ®,
> + }, {
> + .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],
+ },
+ },
}
},
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-04-30 9:38 ` poma
@ 2012-04-30 15:39 ` Thomas Mair
2012-05-01 6:48 ` poma
0 siblings, 1 reply; 16+ messages in thread
From: Thomas Mair @ 2012-04-30 15:39 UTC (permalink / raw)
To: pomidorabelisima; +Cc: Thomas Mair, Linux Media Mailing List
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 | 2 +
drivers/media/dvb/dvb-usb/rtl28xxu.c | 439 +++++++++++++---
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, 2070 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 = ®, .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, ®[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..1ffee60 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -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
@@ -238,6 +239,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..1999c17 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};
-
- deb_info("%s:\n", __func__);
-
- /* GPIO direction */
- ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
- if (ret)
- goto err;
+ /* for FC0012 tuner probe */
+ struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
- /* 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 rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+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 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,17 @@ 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,
+ RTL2832U_1F4D_B803,
};
static struct usb_device_id rtl28xxu_table[] = {
@@ -780,6 +1064,10 @@ 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)},
+ [RTL2832U_1F4D_B803] = {
+ USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
{} /* terminating entry */
};
@@ -802,7 +1090,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 +1106,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 +1152,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 +1168,32 @@ 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 = 2,
.devices = {
{
- .name = "Realtek RTL2832U reference design",
+ .name = "Terratec Cinergy T Stick Black",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_0CCD_00A9],
+ },
+ },
+ {
+ .name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1F4D_B803],
+ },
},
}
},
@@ -907,10 +1204,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 +1224,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 +1264,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 +1273,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 +1283,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 = ®,
+ }, {
+ .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 */
--
1.7.7.6
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
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
0 siblings, 1 reply; 16+ messages in thread
From: poma @ 2012-05-01 6:48 UTC (permalink / raw)
To: linux-media
[-- Attachment #1: Type: text/plain, Size: 74707 bytes --]
On 04/30/2012 05:39 PM, Thomas Mair wrote:
> 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 | 2 +
> drivers/media/dvb/dvb-usb/rtl28xxu.c | 439 +++++++++++++---
> 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, 2070 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 = ®, .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, ®[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..1ffee60 100644
> --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> @@ -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
> @@ -238,6 +239,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..1999c17 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};
> -
> - deb_info("%s:\n", __func__);
> -
> - /* GPIO direction */
> - ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
> - if (ret)
> - goto err;
> + /* for FC0012 tuner probe */
> + struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
>
> - /* 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 rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
> +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 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,17 @@ 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,
> + RTL2832U_1F4D_B803,
> };
>
> static struct usb_device_id rtl28xxu_table[] = {
> @@ -780,6 +1064,10 @@ 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)},
> + [RTL2832U_1F4D_B803] = {
> + USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
> {} /* terminating entry */
> };
>
> @@ -802,7 +1090,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 +1106,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 +1152,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 +1168,32 @@ 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 = 2,
> .devices = {
> {
> - .name = "Realtek RTL2832U reference design",
> + .name = "Terratec Cinergy T Stick Black",
> + .warm_ids = {
> + &rtl28xxu_table[RTL2832U_0CCD_00A9],
> + },
> + },
> + {
> + .name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]",
> + .warm_ids = {
> + &rtl28xxu_table[RTL2832U_1F4D_B803],
> + },
> },
> }
> },
> @@ -907,10 +1204,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 +1224,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 +1264,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 +1273,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 +1283,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 = ®,
> + }, {
> + .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 */
OK, thanks!
This patch, 'v2-rtl2832-h.patch' correct make errors:
..
CC [M] /tmp/media_build/v4l/dvb-usb-remote.o
In file included from /tmp/media_build/v4l/rtl28xxu.c:26:0:
/tmp/media_build/v4l/rtl2832.h:136:2: error: expected ',' or '}' before
'DVBT_AD_AVI'
/tmp/media_build/v4l/rtl28xxu.c:388:2: error: unknown field 'ts_mode'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:389:2: error: unknown field 'spec_inv'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:391:2: error: unknown field 'vtop'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:392:2: error: unknown field 'krf'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:392:2: warning: excess elements in
struct initializer [enabled by default]
/tmp/media_build/v4l/rtl28xxu.c:392:2: warning: (near initialization for
'rtl28xxu_rtl2832_fc0012_config') [enabled by default]
/tmp/media_build/v4l/rtl28xxu.c:393:2: error: unknown field
'agc_targ_val' specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:393:2: warning: excess elements in
struct initializer [enabled by default]
/tmp/media_build/v4l/rtl28xxu.c:393:2: warning: (near initialization for
'rtl28xxu_rtl2832_fc0012_config') [enabled by default]
make[3]: *** [/tmp/media_build/v4l/rtl28xxu.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [_module_/tmp/media_build/v4l] Error 2
make[2]: Leaving directory `/usr/src/kernels/3.3.2-6.fc16.x86_64'
make[1]: *** [default] Error 2
make[1]: Leaving directory `/tmp/media_build/v4l'
make: *** [all] Error 2
rgds,
poma
[-- Attachment #2: v2-rtl2832-h.patch --]
[-- Type: text/x-patch, Size: 1042 bytes --]
--- v2-add-support-for-DeLOCK-USB-2.0-DVB-T-Receiver-61744.patch 2012-05-01 08:10:33.000000000 +0200
+++ v2-add-support-for-DeLOCK-USB-2.0-DVB-T-Receiver-61744-corr.patch 2012-05-01 08:08:03.000000000 +0200
@@ -2187,7 +2187,7 @@
index 0000000..b16631a
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2832.h
-@@ -0,0 +1,300 @@
+@@ -0,0 +1,322 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
@@ -2227,6 +2227,16 @@
+ u32 xtal;
+
+ /*
++ * TS output mode.
++ */
++ u8 ts_mode;
++
++ /*
++ * Spectrum inversion.
++ */
++ bool spec_inv;
++
++ /*
+ * IFs for all used modes.
+ * Hz
+ * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
@@ -2235,6 +2245,18 @@
+
+ /*
+ */
++ u8 vtop;
++
++ /*
++ */
++ u8 krf;
++
++ /*
++ */
++ u8 agc_targ_val;
++
++ /*
++ */
+ u8 tuner;
+};
+
@@ -2322,9 +2344,9 @@
+ DVBT_KB_P1,
+ DVBT_KB_P2,
+ DVBT_KB_P3,
-+ DVBT_OPT_AD
-+ DVBT_AD_AVI
-+ DVBT_AD_AVQ
++ DVBT_OPT_ADC_IQ,
++ DVBT_AD_AVI,
++ DVBT_AD_AVQ,
+ DVBT_K1_CR_STEP12,
+ DVBT_TRK_KS_P2,
+ DVBT_TRK_KS_I2,
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-01 6:48 ` poma
@ 2012-05-03 7:25 ` poma
2012-05-03 9:03 ` Gianluca Gennari
2012-05-03 18:17 ` Zdenek Styblik
0 siblings, 2 replies; 16+ messages in thread
From: poma @ 2012-05-03 7:25 UTC (permalink / raw)
To: linux-media
Cc: gennarone, Zdenek Styblik, fermio.kll, julianjm, thomas.mair86,
Antti Palosaari
[-- Attachment #1: Type: text/plain, Size: 1715 bytes --]
[
…]
Hi there,
These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and
'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on FC0012
tuner, altogether eleven.
Gianluca, please inform forum fellows to test&reply.
Zdenek, fermio - there is a note on
http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at
"Other DVB-T Sticks" regarding 'af4d:a803' device.
Is it based on RTL2832 with FC0012 tuner?
Julian, Thomas, Antii
cheers mates!
;)
poma
ps.
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:v1F4DpD803d*dc*dsc*dp*ic*isc*ip*
alias: usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip*
alias: usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip*
alias: usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip*
alias: usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip*
alias: usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip*
alias: usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip*
alias: usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip*
alias: usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip*
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)
[-- Attachment #2: dvb-usb-ids-v2-rtl2832-fc0012.patch --]
[-- Type: text/x-patch, Size: 2280 bytes --]
--- dvb-usb-ids.h.bcp 2012-05-03 05:28:38.261673063 +0200
+++ dvb-usb-ids.h 2012-05-03 07:07:41.510306992 +0200
@@ -129,10 +129,12 @@
#define USB_PID_E3C_EC168_3 0xfffb
#define USB_PID_E3C_EC168_4 0x1001
#define USB_PID_E3C_EC168_5 0x1002
+#define USB_PID_EZCAP_EZTV646 0x2838
#define USB_PID_FREECOM_DVBT 0x0160
#define USB_PID_FREECOM_DVBT_2 0x0161
#define USB_PID_UNIWILL_STK7700P 0x6003
#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012
+#define USB_PID_GENIUS_TVGO_DVB_T03_2 0x707f
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_GTEK 0xb803
@@ -146,6 +148,9 @@
#define USB_PID_KWORLD_395U_2 0xe39b
#define USB_PID_KWORLD_395U_3 0xe395
#define USB_PID_KWORLD_395U_4 0xe39a
+#define USB_PID_KWORLD_D393 0xd393
+#define USB_PID_KWORLD_D395 0xd395
+#define USB_PID_KWORLD_D399 0xd399
#define USB_PID_KWORLD_MC810 0xc810
#define USB_PID_KWORLD_PC160_2T 0xc160
#define USB_PID_KWORLD_PC160_T 0xc161
@@ -209,6 +214,7 @@
#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009 0x5200
#define USB_PID_HAUPPAUGE_TIGER_ATSC 0xb200
#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210 0xb210
+#define USB_PID_HU394 0xd394
#define USB_PID_AVERMEDIA_EXPRESS 0xb568
#define USB_PID_AVERMEDIA_VOLAR 0xa807
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
@@ -265,11 +271,13 @@
#define USB_PID_PCTV_400E 0x020f
#define USB_PID_PCTV_450E 0x0222
#define USB_PID_PCTV_452E 0x021f
+#define USB_PID_PROLECTRIX_DV107669 0xd803
#define USB_PID_REALTEK_RTL2831U 0x2831
#define USB_PID_REALTEK_RTL2832U 0x2832
#define USB_PID_TECHNOTREND_CONNECT_S2_3600 0x3007
#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI 0x300a
#define USB_PID_NEBULA_DIGITV 0x0201
+#define USB_PID_NOT_ONLY_LV5TDELUXE 0xc803
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM 0xd501
@@ -345,6 +353,7 @@
#define USB_PID_FRIIO_WHITE 0x0001
#define USB_PID_TVWAY_PLUS 0x0002
#define USB_PID_SVEON_STV20 0xe39d
+#define USB_PID_SVEON_STV20_2 0xd39d
#define USB_PID_SVEON_STV22 0xe401
#define USB_PID_SVEON_STV22_IT9137 0xe411
#define USB_PID_AZUREWAVE_AZ6027 0x3275
[-- Attachment #3: rtl28xxu-v2-rtl2832-fc0012.patch --]
[-- Type: text/x-patch, Size: 2786 bytes --]
--- rtl28xxu.c.bcp 2012-05-03 06:44:32.958461395 +0200
+++ rtl28xxu.c 2012-05-03 08:11:57.463559065 +0200
@@ -1052,6 +1052,15 @@
RTL2831U_14AA_0161,
RTL2832U_0CCD_00A9,
RTL2832U_1F4D_B803,
+ RTL2832U_0BDA_2838,
+ RTL2832U_0458_707F,
+ RTL2832U_1B80_D39D,
+ RTL2832U_1B80_D393,
+ RTL2832U_1B80_D394,
+ RTL2832U_1B80_D395,
+ RTL2832U_1B80_D399,
+ RTL2832U_1F4D_C803,
+ RTL2832U_1F4D_D803,
};
static struct usb_device_id rtl28xxu_table[] = {
@@ -1068,6 +1077,24 @@
USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
[RTL2832U_1F4D_B803] = {
USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
+ [RTL2832U_0BDA_2838] = {
+ USB_DEVICE(USB_VID_REALTEK, USB_PID_EZCAP_EZTV646)},
+ [RTL2832U_0458_707F] = {
+ USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03_2)},
+ [RTL2832U_1B80_D39D] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_2)},
+ [RTL2832U_1B80_D393] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_D393)},
+ [RTL2832U_1B80_D394] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_HU394)},
+ [RTL2832U_1B80_D395] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_D395)},
+ [RTL2832U_1B80_D399] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_D399)},
+ [RTL2832U_1F4D_C803] = {
+ USB_DEVICE(USB_VID_GTEK, USB_PID_NOT_ONLY_LV5TDELUXE)},
+ [RTL2832U_1F4D_D803] = {
+ USB_DEVICE(USB_VID_GTEK, USB_PID_PROLECTRIX_DV107669)},
{} /* terminating entry */
};
@@ -1181,7 +1208,7 @@
.i2c_algo = &rtl28xxu_i2c_algo,
- .num_device_descs = 2,
+ .num_device_descs = 11,
.devices = {
{
.name = "Terratec Cinergy T Stick Black",
@@ -1195,6 +1222,60 @@
&rtl28xxu_table[RTL2832U_1F4D_B803],
},
},
+ {
+ .name = "EzCAP EzTV646",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_0BDA_2838],
+ },
+ },
+ {
+ .name = "Genius TVGo DVB-T03 2",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_0458_707F],
+ },
+ },
+ {
+ .name = "Sveon STV20 2",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1B80_D39D],
+ },
+ },
+ {
+ .name = "DVB-T TV Stick D393",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1B80_D393],
+ },
+ },
+ {
+ .name = "DIKOM USB-DVBT HD - HU394",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1B80_D394],
+ },
+ },
+ {
+ .name = "DVB-T TV Stick D395",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1B80_D395],
+ },
+ },
+ {
+ .name = "DVB-T TV Stick D399",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1B80_D399],
+ },
+ },
+ {
+ .name = "Not Only TV DVB-T USB DELUXE LV5TDELUXE",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1F4D_C803],
+ },
+ },
+ {
+ .name = "PROlectrix USB DVB-T & DAB Dongle DV107669",
+ .warm_ids = {
+ &rtl28xxu_table[RTL2832U_1F4D_D803],
+ },
+ },
}
},
[-- Attachment #4: vid-pid-rtl2832-fc0012.txt --]
[-- Type: text/plain, Size: 2972 bytes --]
0bda:2838
*USB_VID_REALTEK 0x0bda
USB_PID_EZCAP_EZTV646 0x2838
EzCAP EzTV646
http://www.szforwardvideo.com/product/Pro_18_7.html
http://ubuntuforums.org/showthread.php?t=1532934
RTL2832U_0BDA_2838
0ccd:00a9
*USB_VID_TERRATEC 0x0ccd
*USB_PID_TERRATEC_CINERGY_T_STICK_BLACK 0x00a9
TERRATEC Cinergy T Stick Black - "Rev.1"
http://linux.terratec.de/tv_en.html
http://www.terratec.net/en/products/Cinergy_T_Stick_Black_107611.html
*RTL2832U_0CCD_00A9
0458:707f
*USB_VID_KYE 0x0458
USB_PID_GENIUS_TVGO_DVB_T03_2 0x707f
Genius TVGo DVB-T03 - "Ver.B"
http://www.linuxtv.org/wiki/index.php/Genius_TVGo_DVB-T03
http://www.abclinuxu.cz/hardware/pridavne-karty/televizni-karty/dvb-t/usb/genius-tvgo-dvb-t03-hw-z-2011
RTL2832U_0458_707F
1b80:d39d
*USB_VID_KWORLD_2 0x1b80
USB_PID_SVEON_STV20_2 0xd39d
Sveon STV20
http://www.sveon.com/fichaSTV20.html
https://github.com/ambrosa/DVB-Realtek-RTL2832U-2.2.2-10tuner-mod_kernel-3.0.0/issues/4
RTL2832U_1B80_D39D
1b80:d393
*USB_VID_KWORLD_2 0x1b80
USB_PID_KWORLD_D393 0xd393
Ardata MyVision DVB-T TV
http://www.ardata.pl/tuner-telewizyjny-ardata-myvision-dvb-t-tv
Gigabyte U7300 USB DVB-T
http://www.gigabyte.com/products/product-page.aspx?pid=3493#sp
http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:gigabyte-u7300-usb-dvb-t-tuner
NILOX DVB-T Stick N15
http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:nilox-dvb-t_stick_n15
Twintech UT-30 USB2.0 DVB-T Stick with FM Radio
http://www.twintech3d.com/products_features.asp?num=300
RTL2832U_1B80_D393
1b80:d394
*USB_VID_KWORLD_2 0x1b80
USB_PID_HU394 0xd394
DIKOM USB-DVBT HD
http://twitter.com/#!/spin877/status/188265508401979392
http://xgazza.altervista.org/Linux/DVB/dikom_dvbt.JPG
RTL2832U_1B80_D394
1b80:d395
*USB_VID_KWORLD_2 0x1b80
USB_PID_KWORLD_D395 0xd395
MaxMedia HU394-T USB DVB-T Multi (FM, DAB, DAB+)
http://www.maxmediatek.com/pd-page/DVB-T_USB.htm
PEAK Hardware 102569AGPK DVB-T Digital TV USB Stick
http://ubuntuforums.org/showthread.php?t=1678094
RTL2832U_1B80_D395
1b80:d399
DVB-T TV Stick D399
*USB_VID_KWORLD_2 0x1b80
USB_PID_KWORLD_D399 0xd399
http://ubuntuforums.org/showthread.php?t=1678094&page=2
RTL2832U_1B80_D399
1f4d:b803
*USB_VID_GTEK 0x1f4d
*USB_PID_GTEK 0xb803
DeLOCK USB 2.0 DVB-T Receiver 61744
http://www.delock.com/produkte/gruppen/Multimedia/Delock_USB_20_DVB-T_Receiver_61744.html
G-Tek T803
MyGica T803 DVB-T USB TV Stick
http://www.mygica.com/product.asp?id=149
*RTL2832U_1F4D_B803
1f4d:c803
*USB_VID_GTEK 0x1f4d
USB_PID_NOT_ONLY_LV5TDELUXE 0xc803
LifeView/Not Only TV DVB-T USB DELUXE LV5TDELUXE
http://notonlytv.net/p_lv5tdeluxe.html
RTL2832U_1F4D_C803
1f4d:d803
*USB_VID_GTEK 0x1f4d
USB_PID_PROLECTRIX_DV107669 0xd803
PROlectrix USB DVB-T & DAB Dongle DV107669
http://www.reddit.com/user/GrahamM242
RTL2832U_1F4D_D803
https://github.com/tmair/DVB-Realtek-RTL2832U-2.2.2-10tuner-mod_kernel-3.0.0/blob/master/README
http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-03 7:25 ` poma
@ 2012-05-03 9:03 ` Gianluca Gennari
2012-05-04 1:27 ` poma
2012-05-03 18:17 ` Zdenek Styblik
1 sibling, 1 reply; 16+ messages in thread
From: Gianluca Gennari @ 2012-05-03 9:03 UTC (permalink / raw)
To: poma
Cc: linux-media, Zdenek Styblik, fermio.kll, julianjm, thomas.mair86,
Antti Palosaari
Hi poma,
I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
mini DVB-T stick) and both are based on the E4000 tuner, which is not
supported in the kernel at the moment.
I have no idea if there are sticks with the same USB PID and the fc0012
tuner.
Regards,
Gianluca
Il 03/05/2012 09:25, poma ha scritto:
>
> [
…]
>
> Hi there,
>
> These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and
> 'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on FC0012
> tuner, altogether eleven.
> Gianluca, please inform forum fellows to test&reply.
> Zdenek, fermio - there is a note on
> http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at
> "Other DVB-T Sticks" regarding 'af4d:a803' device.
> Is it based on RTL2832 with FC0012 tuner?
>
> Julian, Thomas, Antii
> cheers mates!
> ;)
> poma
>
> ps.
> 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:v1F4DpD803d*dc*dsc*dp*ic*isc*ip*
> alias: usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip*
> alias: usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip*
> alias: usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip*
> alias: usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip*
> alias: usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip*
> alias: usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip*
> alias: usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip*
> alias: usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip*
> 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)
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-03 7:25 ` poma
2012-05-03 9:03 ` Gianluca Gennari
@ 2012-05-03 18:17 ` Zdenek Styblik
2012-05-04 1:34 ` poma
1 sibling, 1 reply; 16+ messages in thread
From: Zdenek Styblik @ 2012-05-03 18:17 UTC (permalink / raw)
To: poma
Cc: linux-media, gennarone, fermio.kll, julianjm, thomas.mair86,
Antti Palosaari
Hello poma,
I'm sorry, but that's all info I've been "given". :-\
Best regards,
Z.
On 05/03/12 09:25, poma wrote:
>
> [
…]
>
> Hi there,
>
> These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and
> 'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on
> FC0012 tuner, altogether eleven. Gianluca, please inform forum
> fellows to test&reply. Zdenek, fermio - there is a note on
> http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at
> "Other DVB-T Sticks" regarding 'af4d:a803' device. Is it based on
> RTL2832 with FC0012 tuner?
>
> Julian, Thomas, Antii cheers mates! ;) poma
>
> ps. 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:v1F4DpD803d*dc*dsc*dp*ic*isc*ip*
> alias: usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip* alias:
> usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip* alias:
> usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip* 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)
>
--
Zdenek Styblik
email: stybla@turnovfree.net
jabber: stybla@jabber.turnovfree.net
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-03 9:03 ` Gianluca Gennari
@ 2012-05-04 1:27 ` poma
2012-05-04 13:49 ` Gianluca Gennari
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: poma @ 2012-05-04 1:27 UTC (permalink / raw)
To: linux-media, gennarone
On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
> Hi poma,
> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
> mini DVB-T stick) and both are based on the E4000 tuner, which is not
> supported in the kernel at the moment.
> I have no idea if there are sticks with the same USB PID and the fc0012
> tuner.
OK, second one - no name device is "Realtek RTL2832U reference design"**.
First one:
Once upon a time there was a "EasyCAP"…
"After while crocodile!"
…and "EzCAP" was born.
http://szforwardvideo.en.alibaba.com/aboutus.html
Obviously Easycap EZTV646 != EzCAP EzTV646
http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
ezcap EzTV646 0BDA:2838 RTL2832U/FC0012 Some revisions may have the E4000*
http://i.imgur.com/mFD1X.jpg
(Generic) 0BDa:2838 RTL2832U/E4000*
…
And, in addition:
http://sdr.osmocom.org/trac/wiki/rtl-sdr
0x0bda 0x2832 all of them Generic RTL2832U (e.g. hama nano)**
0x0bda 0x2838 E4000 ezcap USB 2.0 DVB-T/DAB/FM dongle
…
Maybe?
https://sites.google.com/site/myrtlsdr/
"EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
to force FC0012 tuner because it has the same PID as EZTV668 (PID:
0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
Works, not so good at filtering."
…
Conclusion:
At least two devices share same vid/pid with different tuners - fc0012
vs e4000.
How to resolve this from a drivers perspective in a proper way?
Beside,
there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
E4000)
by Harald Welte
http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
http://sdr.osmocom.org/trac/
http://sdr.osmocom.org/trac/wiki/rtl-sdr
http://wiki.spench.net/wiki/RTL2832U***
regards,
poma
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-03 18:17 ` Zdenek Styblik
@ 2012-05-04 1:34 ` poma
0 siblings, 0 replies; 16+ messages in thread
From: poma @ 2012-05-04 1:34 UTC (permalink / raw)
To: Zdenek Styblik, linux-media
On 05/03/2012 08:17 PM, Zdenek Styblik wrote:
> Hello poma,
>
> I'm sorry, but that's all info I've been "given". :-\
It is as it is.
;)
regards,
poma
> On 05/03/12 09:25, poma wrote:
>>
>> [
…]
>>
>> Hi there,
>>
>> These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and
>> 'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on
>> FC0012 tuner, altogether eleven. Gianluca, please inform forum
>> fellows to test&reply. Zdenek, fermio - there is a note on
>> http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at
>> "Other DVB-T Sticks" regarding 'af4d:a803' device. Is it based on
>> RTL2832 with FC0012 tuner?
>>
>> Julian, Thomas, Antii cheers mates! ;) poma
>>
>> ps. 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:v1F4DpD803d*dc*dsc*dp*ic*isc*ip*
>> alias: usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip* 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)
>>
>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-04 1:27 ` poma
@ 2012-05-04 13:49 ` Gianluca Gennari
2012-05-05 0:33 ` poma
2012-05-04 13:57 ` Gianluca Gennari
[not found] ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
2 siblings, 1 reply; 16+ messages in thread
From: Gianluca Gennari @ 2012-05-04 13:49 UTC (permalink / raw)
To: poma; +Cc: linux-media
Hi poma,
thanks for the very interesting links.
Il 04/05/2012 03:27, poma ha scritto:
> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>> Hi poma,
>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>> supported in the kernel at the moment.
>> I have no idea if there are sticks with the same USB PID and the fc0012
>> tuner.
>
> OK, second one - no name device is "Realtek RTL2832U reference design"**.
>
> First one:
> Once upon a time there was a "EasyCAP"�
> "After while crocodile!"
> �and "EzCAP" was born.
> http://szforwardvideo.en.alibaba.com/aboutus.html
> Obviously Easycap EZTV646 != EzCAP EzTV646
> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
> ezcap EzTV646 0BDA:2838 RTL2832U/FC0012 Some revisions may have the E4000*
> http://i.imgur.com/mFD1X.jpg
> (Generic) 0BDa:2838 RTL2832U/E4000*
> �
> And, in addition:
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> 0x0bda 0x2832 all of them Generic RTL2832U (e.g. hama nano)**
> 0x0bda 0x2838 E4000 ezcap USB 2.0 DVB-T/DAB/FM dongle
> �
> Maybe?
> https://sites.google.com/site/myrtlsdr/
That's it. Opening the device enclosure, I can read this on the PCB:
"EzTV668 1.0"
and it looks identical to the picture posted there.
> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
> Works, not so good at filtering."
> �
> Conclusion:
> At least two devices share same vid/pid with different tuners - fc0012
> vs e4000.
> How to resolve this from a drivers perspective in a proper way?
This is not a big problem: the rtl2832 driver should read the tuner type
from an internal register and load the proper module (or exit with an
error message if the tuner is unsupported).
> Beside,
> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
> E4000)
> by Harald Welte
> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
> http://sdr.osmocom.org/trac/
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> http://wiki.spench.net/wiki/RTL2832U***
Very nice. So we should ask Harald Welte if he is willing to have his
driver merged in the kernel.
> regards,
> poma
>
Regards,
Gianluca
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-04 1:27 ` poma
2012-05-04 13:49 ` Gianluca Gennari
@ 2012-05-04 13:57 ` Gianluca Gennari
[not found] ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
2 siblings, 0 replies; 16+ messages in thread
From: Gianluca Gennari @ 2012-05-04 13:57 UTC (permalink / raw)
To: poma; +Cc: linux-media
Il 04/05/2012 03:27, poma ha scritto:
> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>> Hi poma,
>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>> supported in the kernel at the moment.
>> I have no idea if there are sticks with the same USB PID and the fc0012
>> tuner.
>
> OK, second one - no name device is "Realtek RTL2832U reference design"**.
Just for reference, the "no name device" I bought on ebay is exactly
this one:
http://i01.i.aliimg.com/photo/v0/513925059/Mini_notebook_USB_DVB_T_Stick_receiver.jpg
Tuner: E4000
USB PID: 0BDA:2832
It is listed as "Unikoo UK001T (P160)" on the RTL SDR compatibility list:
http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
Best regards,
Gianluca
>
> First one:
> Once upon a time there was a "EasyCAP"�
> "After while crocodile!"
> �and "EzCAP" was born.
> http://szforwardvideo.en.alibaba.com/aboutus.html
> Obviously Easycap EZTV646 != EzCAP EzTV646
> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
> ezcap EzTV646 0BDA:2838 RTL2832U/FC0012 Some revisions may have the E4000*
> http://i.imgur.com/mFD1X.jpg
> (Generic) 0BDa:2838 RTL2832U/E4000*
> �
> And, in addition:
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> 0x0bda 0x2832 all of them Generic RTL2832U (e.g. hama nano)**
> 0x0bda 0x2838 E4000 ezcap USB 2.0 DVB-T/DAB/FM dongle
> �
> Maybe?
> https://sites.google.com/site/myrtlsdr/
> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
> Works, not so good at filtering."
> �
> Conclusion:
> At least two devices share same vid/pid with different tuners - fc0012
> vs e4000.
> How to resolve this from a drivers perspective in a proper way?
>
> Beside,
> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
> E4000)
> by Harald Welte
> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
> http://sdr.osmocom.org/trac/
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> http://wiki.spench.net/wiki/RTL2832U***
>
> regards,
> poma
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
[not found] ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
@ 2012-05-05 0:18 ` poma
0 siblings, 0 replies; 16+ messages in thread
From: poma @ 2012-05-05 0:18 UTC (permalink / raw)
To: Thomas Mair, linux-media
On 05/04/2012 08:50 AM, Thomas Mair wrote:
> Am 04.05.2012 03:27 schrieb "poma" <pomidorabelisima@gmail.com>:
>>
>> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>>> Hi poma,
>>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>>> supported in the kernel at the moment.
>>> I have no idea if there are sticks with the same USB PID and the fc0012
>>> tuner.
>>
>> OK, second one - no name device is "Realtek RTL2832U reference design"**.
>>
>> First one:
>> Once upon a time there was a "EasyCAP"…
>> "After while crocodile!"
>> …and "EzCAP" was born.
>> http://szforwardvideo.en.alibaba.com/aboutus.html
>> Obviously Easycap EZTV646 != EzCAP EzTV646
>>
> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
>> ezcap EzTV646 0BDA:2838 RTL2832U/FC0012 Some revisions
> may have the E4000*
>> http://i.imgur.com/mFD1X.jpg
>> (Generic) 0BDa:2838 RTL2832U/E4000*
>> …
>> And, in addition:
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> 0x0bda 0x2832 all of them Generic RTL2832U (e.g. hama nano)**
>> 0x0bda 0x2838 E4000 ezcap USB 2.0 DVB-T/DAB/FM dongle
>> …
>> Maybe?
>> https://sites.google.com/site/myrtlsdr/
>> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
>> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
>> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
>> Works, not so good at filtering."
>> …
>> Conclusion:
>> At least two devices share same vid/pid with different tuners - fc0012
>> vs e4000.
>> How to resolve this from a drivers perspective in a proper way?
> The handling of the different tuners of devices with the same vid/pid
> should not be a problem, because rtl28xxu driver probes for the tuner when
> the device is initialized.
>
Thanks for clarifying!
rtl28xxu.c:
…
* Probe used tuner. We need to know used tuner before demod attach
* since there is some demod params needed to set according to tuner.
…
/* check FC0012 ID register; reg=00 val=a1 */
…
>> Beside,
>> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
>> E4000)
>> by Harald Welte
>> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
>> http://sdr.osmocom.org/trac/
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> http://wiki.spench.net/wiki/RTL2832U***
> So what is missing is the e4000 tuner driver.
>
True.
> Btw i do have a list of devices that include the Rtl2832 demod. I will send
> that list on the weekend.
>
Groovy!
> Regards
> Thomas
>
regards,
poma
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-04 13:49 ` Gianluca Gennari
@ 2012-05-05 0:33 ` poma
2012-05-05 16:01 ` Thomas Mair
0 siblings, 1 reply; 16+ messages in thread
From: poma @ 2012-05-05 0:33 UTC (permalink / raw)
To: gennarone, linux-media
On 05/04/2012 03:49 PM, Gianluca Gennari wrote:
> Hi poma,
> thanks for the very interesting links.
>
;)
> Il 04/05/2012 03:27, poma ha scritto:
>> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>>> Hi poma,
>>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>>> supported in the kernel at the moment.
>>> I have no idea if there are sticks with the same USB PID and the fc0012
>>> tuner.
>>
>> OK, second one - no name device is "Realtek RTL2832U reference design"**.
>>
>> First one:
>> Once upon a time there was a "EasyCAP"�
>> "After while crocodile!"
>> �and "EzCAP" was born.
>> http://szforwardvideo.en.alibaba.com/aboutus.html
>> Obviously Easycap EZTV646 != EzCAP EzTV646
>> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
>> ezcap EzTV646 0BDA:2838 RTL2832U/FC0012 Some revisions may have the E4000*
>> http://i.imgur.com/mFD1X.jpg
>> (Generic) 0BDa:2838 RTL2832U/E4000*
>> �
>> And, in addition:
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> 0x0bda 0x2832 all of them Generic RTL2832U (e.g. hama nano)**
>> 0x0bda 0x2838 E4000 ezcap USB 2.0 DVB-T/DAB/FM dongle
>> �
>> Maybe?
>> https://sites.google.com/site/myrtlsdr/
>
> That's it. Opening the device enclosure, I can read this on the PCB:
> "EzTV668 1.0"
> and it looks identical to the picture posted there.
>
Groovy!
>> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
>> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
>> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
>> Works, not so good at filtering."
>> �
>> Conclusion:
>> At least two devices share same vid/pid with different tuners - fc0012
>> vs e4000.
>> How to resolve this from a drivers perspective in a proper way?
>
> This is not a big problem: the rtl2832 driver should read the tuner type
> from an internal register and load the proper module (or exit with an
> error message if the tuner is unsupported).
>
Ack, thanks!
>> Beside,
>> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
>> E4000)
>> by Harald Welte
>> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
>> http://sdr.osmocom.org/trac/
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> http://wiki.spench.net/wiki/RTL2832U***
>
> Very nice. So we should ask Harald Welte if he is willing to have his
> driver merged in the kernel.
>
Undoubtedly!
Please ping Thomas and Antti, accordingly.
>> regards,
>> poma
>>
>
> Regards,
> Gianluca
regards,
poma
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
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
0 siblings, 2 replies; 16+ messages in thread
From: Thomas Mair @ 2012-05-05 16:01 UTC (permalink / raw)
To: poma; +Cc: gennarone, linux-media, Antti Palosaari
I am currently finishing up the work at the demod driver and will
probably send a new version to the list tomorrow.
As I don't own a device with a different tuner than the fc0012 I will
include an error message about the unsupported tuner and print its
type. So It is easier to get the information about the tuners.
Right now I am writing the signal_strength callback and stumbled upon
the following problem:
The signal strength is read from the fc0012 tuner (only for fc0012).
How should the driver implement this situation. Is there a callback I
could implement within the tuner or should I just read the tuner
registers from the demodulator?
Regards
Thomas
2012/5/5 poma <pomidorabelisima@gmail.com>:
> On 05/04/2012 03:49 PM, Gianluca Gennari wrote:
>> Hi poma,
>> thanks for the very interesting links.
>>
> ;)
>
>> Il 04/05/2012 03:27, poma ha scritto:
>>> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>>>> Hi poma,
>>>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>>>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>>>> supported in the kernel at the moment.
>>>> I have no idea if there are sticks with the same USB PID and the fc0012
>>>> tuner.
>>>
>>> OK, second one - no name device is "Realtek RTL2832U reference design"**.
>>>
>>> First one:
>>> Once upon a time there was a "EasyCAP"�
>>> "After while crocodile!"
>>> �and "EzCAP" was born.
>>> http://szforwardvideo.en.alibaba.com/aboutus.html
>>> Obviously Easycap EZTV646 != EzCAP EzTV646
>>> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
>>> ezcap EzTV646 0BDA:2838 RTL2832U/FC0012 Some revisions may have the E4000*
>>> http://i.imgur.com/mFD1X.jpg
>>> (Generic) 0BDa:2838 RTL2832U/E4000*
>>> �
>>> And, in addition:
>>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>>> 0x0bda 0x2832 all of them Generic RTL2832U (e.g. hama nano)**
>>> 0x0bda 0x2838 E4000 ezcap USB 2.0 DVB-T/DAB/FM dongle
>>> �
>>> Maybe?
>>> https://sites.google.com/site/myrtlsdr/
>>
>> That's it. Opening the device enclosure, I can read this on the PCB:
>> "EzTV668 1.0"
>> and it looks identical to the picture posted there.
>>
> Groovy!
>
>>> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
>>> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
>>> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
>>> Works, not so good at filtering."
>>> �
>>> Conclusion:
>>> At least two devices share same vid/pid with different tuners - fc0012
>>> vs e4000.
>>> How to resolve this from a drivers perspective in a proper way?
>>
>> This is not a big problem: the rtl2832 driver should read the tuner type
>> from an internal register and load the proper module (or exit with an
>> error message if the tuner is unsupported).
>>
> Ack, thanks!
>
>>> Beside,
>>> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
>>> E4000)
>>> by Harald Welte
>>> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
>>> http://sdr.osmocom.org/trac/
>>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>>> http://wiki.spench.net/wiki/RTL2832U***
>>
>> Very nice. So we should ask Harald Welte if he is willing to have his
>> driver merged in the kernel.
>>
> Undoubtedly!
> Please ping Thomas and Antti, accordingly.
>
>>> regards,
>>> poma
>>>
>>
>> Regards,
>> Gianluca
>
> regards,
> poma
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-05 16:01 ` Thomas Mair
@ 2012-05-05 16:54 ` Hans-Frieder Vogt
2012-05-05 17:02 ` Antti Palosaari
1 sibling, 0 replies; 16+ messages in thread
From: Hans-Frieder Vogt @ 2012-05-05 16:54 UTC (permalink / raw)
To: Thomas Mair; +Cc: linux-media
Am Samstag, 5. Mai 2012 schrieben Sie:
> I am currently finishing up the work at the demod driver and will
> probably send a new version to the list tomorrow.
>
> As I don't own a device with a different tuner than the fc0012 I will
> include an error message about the unsupported tuner and print its
> type. So It is easier to get the information about the tuners.
>
> Right now I am writing the signal_strength callback and stumbled upon
> the following problem:
> The signal strength is read from the fc0012 tuner (only for fc0012).
> How should the driver implement this situation. Is there a callback I
> could implement within the tuner or should I just read the tuner
> registers from the demodulator?
I would recommend implementing the function into the demod driver. Please see an example implementation
attached. To be able to decide which tuner is in use, I had to move the definition of enum rtl28xxu_tuner out of
rtl28xxu.h into an own file. By the way, what is the sense behind naming the tuners after the demodulator? I
think a more appropriate naming would be TUNER_RTL28XX_...
p.s.: I have written a tuner driver for the fc0013, which I hope to be able to send to the mailing list later this
weekend.
Cheers,
Hans-Frieder
> [...]
and here is the patch:
--- a/drivers/media/dvb/frontends/rtl2832.c 2012-05-01 12:28:26.407776103 +0200
+++ b/drivers/media/dvb/frontends/rtl2832.c 2012-05-05 18:35:28.778377211 +0200
@@ -19,10 +19,11 @@
*/
#include "rtl2832_priv.h"
+#include "rtl28xxu_tuners.h"
-int rtl2832_debug = 1;
+int rtl2832_debug;
module_param_named(debug, rtl2832_debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
@@ -391,6 +392,58 @@ err:
}
+static int rtl2832_wr_i2c(struct rtl2832_priv *priv, u8 addr, u8 reg, u8 *val, int len)
+{
+ int ret;
+ u8 buf[1+len];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = 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;
+}
+
+static int rtl2832_rd_i2c(struct rtl2832_priv *priv, u8 addr, u8 reg, u8 *val, int len)
+{
+ int ret;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ®,
+ }, {
+ .addr = 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;
+}
static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
@@ -683,7 +736,9 @@ static int rtl2832_read_status(struct dv
*status = 0;
+#if 0
info("%s", __func__);
+#endif
if (priv->sleeping)
return 0;
@@ -707,32 +762,198 @@ err:
return ret;
}
+#define RTL2832_CE_EST_EVM_MAX_VALUE 65535
+#define RTL2832_SNR_FRAC_BIT_NUM 10
+#define RTL2832_SNR_DB_DEN 3402
+
static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- info("%s", __func__);
- *snr = 0;
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret;
+ u32 fsm_stage, ce_est_evm, constellation, hierarchy;
+ int num;
+ static const int snr_db_num_const[3][4] =
+ {
+ {122880, 122880, 122880, 122880, },
+ {146657, 146657, 156897, 171013, },
+ {167857, 167857, 173127, 181810, },
+ };
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &fsm_stage);
+ if (ret)
+ goto err;
+
+ if (fsm_stage < 10)
+ ce_est_evm = RTL2832_CE_EST_EVM_MAX_VALUE;
+ else {
+ ret = rtl2832_rd_demod_reg(priv, DVBT_CE_EST_EVM, &ce_est_evm);
+ if (ret)
+ goto err;
+ }
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_RX_CONSTEL, &constellation);
+ if (ret)
+ goto err;
+ if (constellation > 2)
+ goto err;
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_RX_HIER, &hierarchy);
+ if (ret)
+ goto err;
+ if (hierarchy > 3)
+ goto err;
+
+ num = snr_db_num_const[constellation][hierarchy] -
+ 10*ilog2(ce_est_evm*ce_est_evm)*0x200;
+ if (num < 0)
+ *snr = 0;
+ else
+ *snr = 256 * num / RTL2832_SNR_DB_DEN;
return 0;
+
+err:
+ info("%s: failed=%d", __func__, ret);
+ return ret;
}
static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- info("%s", __func__);
- *ber = 0;
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ u32 tmp;
+ int ret;
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_RSD_BER_EST, &tmp);
+ if (ret)
+ goto err;
+ *ber = tmp;
return 0;
+
+err:
+ info("%s: failed=%d", __func__, ret);
+ *ber = 0;
+ return ret;
}
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)
+#define INPUT_ADC_LEVEL -8
+
+const int fc001x_lna_gain_table[] = {
+ /* low gain */
+ -63, -58, -99, -73,
+ -63, -65, -54, -60,
+ /* middle gain */
+ 71, 70, 68, 67,
+ 65, 63, 61, 58,
+ /* high gain */
+ 197, 191, 188, 186,
+ 184, 182, 181, 179,
+};
+
+static int rtl2832_fc001x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
- info("%s", __func__);
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 val, reg;
+ int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+
+ if (priv->tuner == TUNER_RTL2832_FC0013)
+ reg = 0x13;
+ else
+ reg = 0x12;
+
+ ret = rtl2832_i2c_gate_ctrl(fe, true);
+ if (ret)
+ goto err;
+
+ val = 0x00;
+ ret = rtl2832_wr_i2c(priv, 0xc6 >> 1, reg, &val, 1);
+ if (ret) {
+ err("%s: rtl2832_wr_i2c failed, ret=%d", __func__, ret);
+ goto err_gate;
+ } else {
+ ret = rtl2832_rd_i2c(priv, 0xc6 >> 1, reg, &val, 1);
+ if (ret)
+ err("%s: rtl2832_rd_i2c failed, ret=%d", __func__, ret);
+// info("fc001x read 0x12: 0x%02x", val);
+ int_temp = val;
+
+ ret = rtl2832_rd_i2c(priv, 0xc6 >> 1, reg + 1, &val, 1);
+ if (ret)
+ err("%s: rtl2832_rd_i2c failed, ret=%d", __func__, ret);
+// info("fc001x read 0x13: 0x%02x", val);
+ lna_gain = val & 0x1f;
+ }
+
+ ret = rtl2832_i2c_gate_ctrl(fe, false);
+ if (ret)
+ goto err;
+
+ if (lna_gain < ARRAY_SIZE(fc001x_lna_gain_table)) {
+ int_lna = fc001x_lna_gain_table[lna_gain];
+ tot_agc_gain = (abs((int_temp >> 5) - 7) -2) * 2 +
+ (int_temp & 0x1f) * 2;
+ power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+ if (power >= 45)
+ *strength = 255; /* 100% */
+ else if (power < -95)
+ *strength = 0;
+ else
+ *strength = (power + 95) * 255 / 140;
+ *strength |= *strength << 8;
+ } else {
+ ret = -1;
+ goto err;
+ }
+
+ return 0;
+
+err_gate:
+ ret = rtl2832_i2c_gate_ctrl(fe, false);
+err:
*strength = 0;
+ return ret;
+}
+
+static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret, if_agc;
+ u32 fsm_stage, if_agc_raw;
+
+ if ((priv->tuner == TUNER_RTL2832_FC0012) ||
+ (priv->tuner == TUNER_RTL2832_FC0013))
+ return rtl2832_fc001x_read_signal_strength(fe, strength);
+
+ ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &fsm_stage);
+ if (ret)
+ goto err;
+ if (fsm_stage < 10)
+ *strength = 0;
+ else {
+ /* if_agc is read as a 10bit binary */
+ ret = rtl2832_rd_demod_reg(priv, DVBT_IF_AGC_VAL, &if_agc_raw);
+ if (ret)
+ goto err;
+ info("%s: if_agc_raw: 0x%04x", __func__, if_agc_raw);
+ if (if_agc_raw < (1 << 9))
+ if_agc = if_agc_raw;
+ else {
+ if_agc = -(~(if_agc_raw-1) & 0x1ff);
+ }
+ *strength = 55 - if_agc / 182;
+ *strength |= *strength << 8;
+ }
+
return 0;
+err:
+ info("%s: failed=%d", __func__, ret);
+ return ret;
}
static struct dvb_frontend_ops rtl2832_ops;
--- /dev/null 2012-05-05 09:43:48.063333275 +0200
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu_tuners.h 2012-05-02 22:43:24.446371878 +0200
@@ -0,0 +1,44 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL28XXU_TUNERS_H
+#define RTL28XXU_TUNERS_H
+
+enum rtl28xxu_tuner {
+ TUNER_NONE,
+
+ TUNER_RTL2830_QT1010,
+ TUNER_RTL2830_MT2060,
+ TUNER_RTL2830_MXL5005S,
+
+ TUNER_RTL2832_MT2266,
+ TUNER_RTL2832_FC2580,
+ TUNER_RTL2832_MT2063,
+ TUNER_RTL2832_MAX3543,
+ TUNER_RTL2832_TUA9001,
+ TUNER_RTL2832_MXL5007T,
+ TUNER_RTL2832_FC0012,
+ TUNER_RTL2832_E4000,
+ TUNER_RTL2832_TDA18272,
+ TUNER_RTL2832_FC0013,
+};
+
+#endif
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.h 2012-02-29 05:45:38.000000000 +0100
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.h 2012-05-02 22:43:53.002893237 +0200
@@ -84,25 +84,6 @@ enum rtl28xxu_chip_id {
CHIP_ID_RTL2832U,
};
-enum rtl28xxu_tuner {
- TUNER_NONE,
-
- TUNER_RTL2830_QT1010,
- TUNER_RTL2830_MT2060,
- TUNER_RTL2830_MXL5005S,
-
- TUNER_RTL2832_MT2266,
- TUNER_RTL2832_FC2580,
- TUNER_RTL2832_MT2063,
- TUNER_RTL2832_MAX3543,
- TUNER_RTL2832_TUA9001,
- TUNER_RTL2832_MXL5007T,
- TUNER_RTL2832_FC0012,
- TUNER_RTL2832_E4000,
- TUNER_RTL2832_TDA18272,
- TUNER_RTL2832_FC0013,
-};
-
struct rtl28xxu_req {
u16 value;
u16 index;
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c 2012-05-01 12:28:26.407776103 +0200
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c 2012-05-05 14:25:04.212866649 +0200
@@ -21,6 +21,7 @@
*/
#include "rtl28xxu.h"
+#include "rtl28xxu_tuners.h"
#include "rtl2830.h"
#include "rtl2832.h"
Hans-Frieder Vogt e-mail: hfvogt <at> gmx .dot. net
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
2012-05-05 16:01 ` Thomas Mair
2012-05-05 16:54 ` Hans-Frieder Vogt
@ 2012-05-05 17:02 ` Antti Palosaari
1 sibling, 0 replies; 16+ messages in thread
From: Antti Palosaari @ 2012-05-05 17:02 UTC (permalink / raw)
To: Thomas Mair; +Cc: poma, gennarone, linux-media, Antti Palosaari
la 5.5.2012 19:01 Thomas Mair kirjoitti:
> I am currently finishing up the work at the demod driver and will
> probably send a new version to the list tomorrow.
Nice! I will try to review it on Monday...
I looked quickly your old patch last week and tuner driver was done by
Hans-Frieder Vogt. I think he should send tuner patch first and then your
rtl2832 applied top of that.
> As I don't own a device with a different tuner than the fc0012 I will
> include an error message about the unsupported tuner and print its
> type. So It is easier to get the information about the tuners.
Sounds good.
> Right now I am writing the signal_strength callback and stumbled upon
> the following problem:
> The signal strength is read from the fc0012 tuner (only for fc0012).
> How should the driver implement this situation. Is there a callback I
> could implement within the tuner or should I just read the tuner
> registers from the demodulator?
Demod should report signal strength, normally based IF AGC. But that
estimation is very poor, tuner could report it more accurate.
On optimal situation you should implement demod callback for signal
strength and if there is tuner callback then override demod callback in
order to get better reports. IMHO that override should be done in DVB-USB
driver, in that case dvb-usb-rtl2832u. So when you attach rtl2832u just
after that override demod callback with tuner.
regards
Antti
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2012-05-05 17:02 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-29 21:42 [PATCH] Driver for RTL2832 demodulator chip Thomas Mair
2012-04-30 9:38 ` poma
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
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.