summaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/frontends
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/frontends')
-rw-r--r--drivers/media/dvb/frontends/Kconfig37
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/au8522.c48
-rw-r--r--drivers/media/dvb/frontends/au8522.h11
-rw-r--r--drivers/media/dvb/frontends/cx22702.c2
-rw-r--r--drivers/media/dvb/frontends/cx22702.h2
-rw-r--r--drivers/media/dvb/frontends/cx24123.c6
-rw-r--r--drivers/media/dvb/frontends/cx24123.h2
-rw-r--r--drivers/media/dvb/frontends/drx397xD.c1504
-rw-r--r--drivers/media/dvb/frontends/drx397xD.h130
-rw-r--r--drivers/media/dvb/frontends/drx397xD_fw.h40
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c47
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h1
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c24
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c4
-rw-r--r--drivers/media/dvb/frontends/s5h1409.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1411.c4
-rw-r--r--drivers/media/dvb/frontends/s5h1411.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c3
-rw-r--r--drivers/media/dvb/frontends/tda10023.c197
-rw-r--r--drivers/media/dvb/frontends/tda1002x.h41
-rw-r--r--drivers/media/dvb/frontends/tda10048.c4
-rw-r--r--drivers/media/dvb/frontends/tda10048.h2
-rw-r--r--drivers/media/dvb/frontends/z0194a.h97
24 files changed, 2077 insertions, 134 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index c20553c4da1..7dbb4a223c9 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -97,9 +97,8 @@ comment "DVB-T (terrestrial) frontends"
config DVB_SP8870
tristate "Spase sp8870 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -110,9 +109,8 @@ config DVB_SP8870
config DVB_SP887X
tristate "Spase sp887x based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -135,6 +133,19 @@ config DVB_CX22702
help
A DVB-T tuner module. Say Y when you want to support this frontend.
+config DVB_DRX397XD
+ tristate "Micronas DRX3975D/DRX3977D based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ TODO:
+ This driver needs external firmware. Please use the command
+ "<kerneldir>/Documentation/dvb/get_dvb_firmware drx397xD" to
+ download/extract them, and then copy them to /usr/lib/hotplug/firmware
+ or /lib/firmware (depending on configuration of firmware hotplug).
+
config DVB_L64781
tristate "LSI L64781"
depends on DVB_CORE && I2C
@@ -144,9 +155,8 @@ config DVB_L64781
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -211,9 +221,8 @@ config DVB_DIB7000P
config DVB_TDA10048
tristate "Philips TDA10048HN based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -253,9 +262,8 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
config DVB_NXT200X
tristate "NxtWave Communications NXT2002/NXT2004 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
@@ -268,9 +276,8 @@ config DVB_NXT200X
config DVB_OR51211
tristate "Oren OR51211 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
@@ -281,9 +288,8 @@ config DVB_OR51211
config DVB_OR51132
tristate "Oren OR51132 based"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
@@ -297,9 +303,8 @@ config DVB_OR51132
config DVB_BCM3510
tristate "Broadcom BCM3510"
- depends on DVB_CORE && I2C && HOTPLUG
+ depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
- select FW_LOADER
help
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
support this frontend.
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index a89dc0fc4c6..028da55611c 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_DVB_NXT6000) += nxt6000.o
obj-$(CONFIG_DVB_MT352) += mt352.o
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
obj-$(CONFIG_DVB_CX22702) += cx22702.o
+obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
diff --git a/drivers/media/dvb/frontends/au8522.c b/drivers/media/dvb/frontends/au8522.c
index 03900d241a7..0b82cc2a1e1 100644
--- a/drivers/media/dvb/frontends/au8522.c
+++ b/drivers/media/dvb/frontends/au8522.c
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "au8522.h"
struct au8522_state {
@@ -305,6 +304,43 @@ static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
return ret;
}
+static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ u8 r0b5, r0b6, r0b7;
+ char *ifmhz;
+
+ switch (if_freq) {
+ case AU8522_IF_3_25MHZ:
+ ifmhz = "3.25";
+ r0b5 = 0x00;
+ r0b6 = 0x3d;
+ r0b7 = 0xa0;
+ break;
+ case AU8522_IF_4MHZ:
+ ifmhz = "4.00";
+ r0b5 = 0x00;
+ r0b6 = 0x4b;
+ r0b7 = 0xd9;
+ break;
+ case AU8522_IF_6MHZ:
+ ifmhz = "6.00";
+ r0b5 = 0xfb;
+ r0b6 = 0x8e;
+ r0b7 = 0x39;
+ break;
+ default:
+ dprintk("%s() IF Frequency not supported\n", __func__);
+ return -EINVAL;
+ }
+ dprintk("%s() %s MHz\n", __func__, ifmhz);
+ au8522_writereg(state, 0x80b5, r0b5);
+ au8522_writereg(state, 0x80b6, r0b6);
+ au8522_writereg(state, 0x80b7, r0b7);
+
+ return 0;
+}
+
/* VSB Modulation table */
static struct {
u16 reg;
@@ -335,9 +371,6 @@ static struct {
{ 0x80af, 0x66 },
{ 0x821b, 0xcc },
{ 0x821d, 0x80 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80a4, 0xe8 },
{ 0x8231, 0x13 },
};
@@ -351,9 +384,6 @@ static struct {
{ 0x80a4, 0x00 },
{ 0x8081, 0xc4 },
{ 0x80a5, 0x40 },
- { 0x80b5, 0xfb },
- { 0x80b6, 0x8e },
- { 0x80b7, 0x39 },
{ 0x80aa, 0x77 },
{ 0x80ad, 0x77 },
{ 0x80a6, 0x67 },
@@ -439,6 +469,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
VSB_mod_tab[i].reg,
VSB_mod_tab[i].data);
+ au8522_set_if(fe, state->config->vsb_if);
break;
case QAM_64:
case QAM_256:
@@ -447,6 +478,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
QAM_mod_tab[i].reg,
QAM_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
break;
default:
dprintk("%s() Invalid modulation\n", __func__);
diff --git a/drivers/media/dvb/frontends/au8522.h b/drivers/media/dvb/frontends/au8522.h
index d7affa3cdb2..595915ade8c 100644
--- a/drivers/media/dvb/frontends/au8522.h
+++ b/drivers/media/dvb/frontends/au8522.h
@@ -1,7 +1,7 @@
/*
Auvitek AU8522 QAM/8VSB demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -24,6 +24,12 @@
#include <linux/dvb/frontend.h>
+enum au8522_if_freq {
+ AU8522_IF_6MHZ = 0,
+ AU8522_IF_4MHZ,
+ AU8522_IF_3_25MHZ,
+};
+
struct au8522_config {
/* the demodulator's i2c address */
u8 demod_address;
@@ -32,6 +38,9 @@ struct au8522_config {
#define AU8522_TUNERLOCKING 0
#define AU8522_DEMODLOCKING 1
u8 status_mode;
+
+ enum au8522_if_freq vsb_if;
+ enum au8522_if_freq qam_if;
};
#if defined(CONFIG_DVB_AU8522) || \
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index cc1db4e371c..9430e03dba6 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 8af766a3155..b1e465c6c2c 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -7,7 +7,7 @@
Copyright (C) 2001-2002 Convergence Integrated Media GmbH
Holger Waechtler <holger@convergence.de>
- Copyright (C) 2004 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2004 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 7f68d78c655..7156157cb34 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1,7 +1,7 @@
/*
* Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
*
- * Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ * Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
*
* Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
*
@@ -1072,8 +1072,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
if (config->dont_use_pll)
cx24123_repeater_mode(state, 1, 0);
- strncpy(state->tuner_i2c_adapter.name,
- "CX24123 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 81ebc3d2f19..cc6b411d6d2 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -1,7 +1,7 @@
/*
Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
- Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2005 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
new file mode 100644
index 00000000000..3cbed874a6f
--- /dev/null
+++ b/drivers/media/dvb/frontends/drx397xD.c
@@ -0,0 +1,1504 @@
+/*
+ * Driver for Micronas drx397xD demodulator
+ *
+ * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DEBUG /* uncomment if you want debugging output */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/firmware.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drx397xD.h"
+
+static const char mod_name[] = "drx397xD";
+
+#define MAX_CLOCK_DRIFT 200 /* maximal 200 PPM allowed */
+
+#define F_SET_0D0h 1
+#define F_SET_0D4h 2
+
+typedef enum fw_ix {
+#define _FW_ENTRY(a, b) b
+#include "drx397xD_fw.h"
+} fw_ix_t;
+
+/* chip specifics */
+struct drx397xD_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend frontend;
+ struct drx397xD_config config;
+ fw_ix_t chip_rev;
+ int flags;
+ u32 bandwidth_parm; /* internal bandwidth conversions */
+ u32 f_osc; /* w90: actual osc frequency [Hz] */
+};
+
+/*******************************************************************************
+ * Firmware
+ ******************************************************************************/
+
+static const char *blob_name[] = {
+#define _BLOB_ENTRY(a, b) a
+#include "drx397xD_fw.h"
+};
+
+typedef enum blob_ix {
+#define _BLOB_ENTRY(a, b) b
+#include "drx397xD_fw.h"
+} blob_ix_t;
+
+static struct {
+ const char *name;
+ const struct firmware *file;
+ rwlock_t lock;
+ int refcnt;
+ const u8 *data[ARRAY_SIZE(blob_name)];
+} fw[] = {
+#define _FW_ENTRY(a, b) { \
+ .name = a, \
+ .file = 0, \
+ .lock = RW_LOCK_UNLOCKED, \
+ .refcnt = 0, \
+ .data = { } }
+#include "drx397xD_fw.h"
+};
+
+/* use only with writer lock aquired */
+static void _drx_release_fw(struct drx397xD_state *s, fw_ix_t ix)
+{
+ memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
+ if (fw[ix].file)
+ release_firmware(fw[ix].file);
+}
+
+static void drx_release_fw(struct drx397xD_state *s)
+{
+ fw_ix_t ix = s->chip_rev;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ write_lock(&fw[ix].lock);
+ if (fw[ix].refcnt) {
+ fw[ix].refcnt--;
+ if (fw[ix].refcnt == 0)
+ _drx_release_fw(s, ix);
+ }
+ write_unlock(&fw[ix].lock);
+}
+
+static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix)
+{
+ const u8 *data;
+ size_t size, len;
+ int i = 0, j, rc = -EINVAL;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if (ix < 0 || ix >= ARRAY_SIZE(fw))
+ return -EINVAL;
+ s->chip_rev = ix;
+
+ write_lock(&fw[ix].lock);
+ if (fw[ix].file) {
+ rc = 0;
+ goto exit_ok;
+ }
+ memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
+
+ if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) {
+ printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
+ mod_name, fw[ix].name);
+ rc = -ENOENT;
+ goto exit_err;
+ }
+
+ if (!fw[ix].file->data || fw[ix].file->size < 10)
+ goto exit_corrupt;
+
+ data = fw[ix].file->data;
+ size = fw[ix].file->size;
+
+ if (data[i++] != 2) /* check firmware version */
+ goto exit_corrupt;
+
+ do {
+ switch (data[i++]) {
+ case 0x00: /* bytecode */
+ if (i >= size)
+ break;
+ i += data[i];
+ case 0x01: /* reset */
+ case 0x02: /* sleep */
+ i++;
+ break;
+ case 0xfe: /* name */
+ len = strnlen(&data[i], size - i);
+ if (i + len + 1 >= size)
+ goto exit_corrupt;
+ if (data[i + len + 1] != 0)
+ goto exit_corrupt;
+ for (j = 0; j < ARRAY_SIZE(blob_name); j++) {
+ if (strcmp(blob_name[j], &data[i]) == 0) {
+ fw[ix].data[j] = &data[i + len + 1];
+ pr_debug("Loading %s\n", blob_name[j]);
+ }
+ }
+ i += len + 1;
+ break;
+ case 0xff: /* file terminator */
+ if (i == size) {
+ rc = 0;
+ goto exit_ok;
+ }
+ default:
+ goto exit_corrupt;
+ }
+ } while (i < size);
+ exit_corrupt:
+ printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
+ exit_err:
+ _drx_release_fw(s, ix);
+ fw[ix].refcnt--;
+ exit_ok:
+ fw[ix].refcnt++;
+ write_unlock(&fw[ix].lock);
+ return rc;
+}
+
+/*******************************************************************************
+ * i2c bus IO
+ ******************************************************************************/
+
+static int write_fw(struct drx397xD_state *s, blob_ix_t ix)
+{
+ struct i2c_msg msg = {.addr = s->config.demod_address,.flags = 0 };
+ const u8 *data;
+ int len, rc = 0, i = 0;
+
+ if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
+ pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]);
+
+ read_lock(&fw[s->chip_rev].lock);
+ data = fw[s->chip_rev].data[ix];
+ if (!data) {
+ rc = -EINVAL;
+ goto exit_rc;
+ }
+
+ for (;;) {
+ switch (data[i++]) {
+ case 0: /* bytecode */
+ len = data[i++];
+ msg.len = len;
+ msg.buf = (__u8 *) &data[i];
+ if (i2c_transfer(s->i2c, &msg, 1) != 1) {
+ rc = -EIO;
+ goto exit_rc;
+ }
+ i += len;
+ break;
+ case 1: /* reset */
+ case 2: /* sleep */
+ i++;
+ break;
+ default:
+ goto exit_rc;
+ }
+ }
+ exit_rc:
+ read_unlock(&fw[s->chip_rev].lock);
+ return 0;
+}
+
+/* Function is not endian safe, use the RD16 wrapper below */
+static int _read16(struct drx397xD_state *s, u32 i2c_adr)
+{
+ int rc;
+ u8 a[4];
+ u16 v;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = s->config.demod_address,
+ .flags = 0,
+ .buf = a,
+ .len = sizeof(a)
+ }
+ , {
+ .addr = s->config.demod_address,
+ .flags = I2C_M_RD,
+ .buf = (u8 *) & v,
+ .len = sizeof(v)
+ }
+ };
+
+ *(u32 *) a = i2c_adr;
+
+ rc = i2c_transfer(s->i2c, msg, 2);
+ if (rc != 2)
+ return -EIO;
+
+ return le16_to_cpu(v);
+}
+
+/* Function is not endian safe, use the WR16.. wrappers below */
+static int _write16(struct drx397xD_state *s, u32 i2c_adr, u16 val)
+{
+ u8 a[6];
+ int rc;
+ struct i2c_msg msg = {
+ .addr = s->config.demod_address,
+ .flags = 0,
+ .buf = a,
+ .len = sizeof(a)
+ };
+
+ *(u32 *) a = i2c_adr;
+ *(u16 *) & a[4] = val;
+
+ rc = i2c_transfer(s->i2c, &msg, 1);
+ if (rc != 1)
+ return -EIO;
+ return 0;
+}
+
+#define WR16(ss,adr, val) \
+ _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
+#define WR16_E0(ss,adr, val) \
+ _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
+#define RD16(ss,adr) \
+ _read16(ss, I2C_ADR_C0(adr))
+
+#define EXIT_RC( cmd ) if ( (rc = (cmd)) < 0) goto exit_rc
+
+/*******************************************************************************
+ * Tuner callback
+ ******************************************************************************/
+
+static int PLL_Set(struct drx397xD_state *s,
+ struct dvb_frontend_parameters *fep, int *df_tuner)
+{
+ struct dvb_frontend *fe = &s->frontend;
+ u32 f_tuner, f = fep->frequency;
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
+ (f < s->frontend.ops.tuner_ops.info.frequency_min))
+ return -EINVAL;
+
+ *df_tuner = 0;
+ if (!s->frontend.ops.tuner_ops.set_params ||
+ !s->frontend.ops.tuner_ops.get_frequency)
+ return -ENOSYS;
+
+ rc = s->frontend.ops.tuner_ops.set_params(fe, fep);
+ if (rc < 0)
+ return rc;
+
+ rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner);
+ if (rc < 0)
+ return rc;
+
+ *df_tuner = f_tuner - f;
+ pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f,
+ f_tuner);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Demodulator helper functions
+ ******************************************************************************/
+
+static int SC_WaitForReady(struct drx397xD_state *s)
+{
+ int cnt = 1000;
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ while (cnt--) {
+ rc = RD16(s, 0x820043);
+ if (rc == 0)
+ return 0;
+ }
+ return -1;
+}
+
+static int SC_SendCommand(struct drx397xD_state *s, int cmd)
+{
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ WR16(s, 0x820043, cmd);
+ SC_WaitForReady(s);
+ rc = RD16(s, 0x820042);
+ if ((rc & 0xffff) == 0xffff)
+ return -1;
+ return 0;
+}
+
+static int HI_Command(struct drx397xD_state *s, u16 cmd)
+{
+ int rc, cnt = 1000;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ rc = WR16(s, 0x420032, cmd);
+ if (rc < 0)
+ return rc;
+
+ do {
+ rc = RD16(s, 0x420032);
+ if (rc == 0) {
+ rc = RD16(s, 0x420031);
+ return rc;
+ }
+ if (rc < 0)
+ return rc;
+ } while (--cnt);
+ return rc;
+}
+
+static int HI_CfgCommand(struct drx397xD_state *s)
+{
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ WR16(s, 0x420033, 0x3973);
+ WR16(s, 0x420034, s->config.w50); // code 4, log 4
+ WR16(s, 0x420035, s->config.w52); // code 15, log 9
+ WR16(s, 0x420036, s->config.demod_address << 1);
+ WR16(s, 0x420037, s->config.w56); // code (set_i2c ?? initX 1 ), log 1
+// WR16(s, 0x420033, 0x3973);
+ if ((s->config.w56 & 8) == 0)
+ return HI_Command(s, 3);
+ return WR16(s, 0x420032, 0x3);
+}
+
+static const u8 fastIncrDecLUT_15273[] = {
+ 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f
+};
+
+static const u8 slowIncrDecLUT_15272[] = {
+ 3, 4, 4, 5, 6
+};
+
+static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
+{
+ u16 w06 = agc->w06;
+ u16 w08 = agc->w08;
+ u16 w0A = agc->w0A;
+ u16 w0C = agc->w0C;
+ int quot, rem, i, rc = -EINVAL;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if (agc->w04 > 0x3ff)
+ goto exit_rc;
+
+ if (agc->d00 == 1) {
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= ~0x10;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+ return WR16(s, 0x0c20030, agc->w04 & 0x7ff);
+ }
+
+ if (agc->d00 != 0)
+ goto exit_rc;
+ if (w0A < w08)
+ goto exit_rc;
+ if (w0A > 0x3ff)
+ goto exit_rc;
+ if (w0C > 0x3ff)
+ goto exit_rc;
+ if (w06 > 0x3ff)
+ goto exit_rc;
+
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc |= 0x10;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+
+ EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff));
+ EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1));
+ EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff));
+
+ quot = w0C / 113;
+ rem = w0C % 113;
+ if (quot <= 8) {
+ quot = 8 - quot;
+ } else {
+ quot = 0;
+ rem += 113;
+ }
+
+ EXIT_RC(WR16(s, 0x0c20024, quot));
+
+ i = fastIncrDecLUT_15273[rem / 8];
+ EXIT_RC(WR16(s, 0x0c2002d, i));
+ EXIT_RC(WR16(s, 0x0c2002e, i));
+
+ i = slowIncrDecLUT_15272[rem / 28];
+ EXIT_RC(WR16(s, 0x0c2002b, i));
+ rc = WR16(s, 0x0c2002c, i);
+ exit_rc:
+ return rc;
+}
+
+static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
+{
+ u16 w04 = agc->w04;
+ u16 w06 = agc->w06;
+ int rc = -1;
+
+ pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06);
+
+ if (w04 > 0x3ff)
+ goto exit_rc;
+
+ switch (agc->d00) {
+ case 1:
+ if (w04 == 0x3ff)
+ w04 = 0x400;
+
+ EXIT_RC(WR16(s, 0x0c20036, w04));
+ s->config.w9C &= ~2;
+ EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= 0xbfdf;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+ EXIT_RC(RD16(s, 0x0c20013));
+ rc &= ~2;
+ break;
+ case 0:
+ // loc_8000659
+ s->config.w9C &= ~2;
+ EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= 0xbfdf;
+ rc |= 0x4000;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+ EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f));
+ EXIT_RC(RD16(s, 0x0c20013));
+ rc &= ~2;
+ break;
+ default:
+ s->config.w9C |= 2;
+ EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
+ EXIT_RC(RD16(s, 0x0c20010));
+ rc &= 0xbfdf;
+ EXIT_RC(WR16(s, 0x0c20010, rc));
+
+ EXIT_RC(WR16(s, 0x0c20036, 0));
+
+ EXIT_RC(RD16(s, 0x0c20013));
+ rc |= 2;
+ }
+ rc = WR16(s, 0x0c20013, rc);
+ exit_rc:
+ return rc;
+}
+
+static int GetLockStatus(struct drx397xD_state *s, int *lockstat)
+{
+ int rc;
+
+ *lockstat = 0;
+
+ rc = RD16(s, 0x082004b);
+ if (rc < 0)
+ return rc;
+
+ if (s->config.d60 != 2)
+ return 0;
+
+ if ((rc & 7) == 7)
+ *lockstat |= 1;
+ if ((rc & 3) == 3)
+ *lockstat |= 2;
+ if (rc & 1)
+ *lockstat |= 4;
+ return 0;
+}
+
+static int CorrectSysClockDeviation(struct drx397xD_state *s)
+{
+ int rc = -EINVAL;
+ int lockstat;
+ u32 clk, clk_limit;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ if (s->config.d5C == 0) {
+ EXIT_RC(WR16(s, 0x08200e8, 0x010));
+ EXIT_RC(WR16(s, 0x08200e9, 0x113));
+ s->config.d5C = 1;
+ return rc;
+ }
+ if (s->config.d5C != 1)
+ goto exit_rc;
+
+ rc = RD16(s, 0x0820048);
+
+ rc = GetLockStatus(s, &lockstat);
+ if (rc < 0)
+ goto exit_rc;
+ if ((lockstat & 1) == 0)
+ goto exit_rc;
+
+ EXIT_RC(WR16(s, 0x0420033, 0x200));
+ EXIT_RC(WR16(s, 0x0420034, 0xc5));
+ EXIT_RC(WR16(s, 0x0420035, 0x10));
+ EXIT_RC(WR16(s, 0x0420036, 0x1));
+ EXIT_RC(WR16(s, 0x0420037, 0xa));
+ EXIT_RC(HI_Command(s, 6));
+ EXIT_RC(RD16(s, 0x0420040));
+ clk = rc;
+ EXIT_RC(RD16(s, 0x0420041));
+ clk |= rc << 16;
+
+ if (clk <= 0x26ffff)
+ goto exit_rc;
+ if (clk > 0x610000)
+ goto exit_rc;
+
+ if (!s->bandwidth_parm)
+ return -EINVAL;
+
+ /* round & convert to Hz */
+ clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21;
+ clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000;
+
+ if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
+ s->f_osc = clk;
+ pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__,
+ s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
+ }
+ rc = WR16(s, 0x08200e8, 0);
+ exit_rc:
+ return rc;
+}
+
+static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
+{
+ int rc, si, bp;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ si = s->config.wA0;
+ if (s->config.w98 == 0) {
+ si |= 1;
+ bp = 0;
+ } else {
+ si &= ~1;
+ bp = 0x200;
+ }
+ if (s->config.w9A == 0) {
+ si |= 0x80;
+ } else {
+ si &= ~0x80;
+ }
+
+ EXIT_RC(WR16(s, 0x2150045, 0));
+ EXIT_RC(WR16(s, 0x2150010, si));
+ EXIT_RC(WR16(s, 0x2150011, bp));
+ rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
+ exit_rc:
+ return rc;
+}
+
+static int drx_tune(struct drx397xD_state *s,
+ struct dvb_frontend_parameters *fep)
+{
+ u16 v22 = 0;
+ u16 v1C = 0;
+ u16 v1A = 0;
+ u16 v18 = 0;
+ u32 edi = 0, ebx = 0, ebp = 0, edx = 0;
+ u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0;
+
+ int rc, df_tuner;
+ int a, b, c, d;
+ pr_debug("%s %d\n", __FUNCTION__, s->config.d60);
+
+ if (s->config.d60 != 2)
+ goto set_tuner;
+ rc = CorrectSysClockDeviation(s);
+ if (rc < 0)
+ goto set_tuner;
+
+ s->config.d60 = 1;
+ rc = ConfigureMPEGOutput(s, 0);
+ if (rc < 0)
+ goto set_tuner;
+ set_tuner:
+
+ rc = PLL_Set(s, fep, &df_tuner);
+ if (rc < 0) {
+ printk(KERN_ERR "Error in pll_set\n");
+ goto exit_rc;
+ }
+ msleep(200);
+
+ a = rc = RD16(s, 0x2150016);
+ if (rc < 0)
+ goto exit_rc;
+ b = rc = RD16(s, 0x2150010);
+ if (rc < 0)
+ goto exit_rc;
+ c = rc = RD16(s, 0x2150034);
+ if (rc < 0)
+ goto exit_rc;
+ d = rc = RD16(s, 0x2150035);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2150014, c);
+ rc = WR16(s, 0x2150015, d);
+ rc = WR16(s, 0x2150010, 0);
+ rc = WR16(s, 0x2150000, 2);
+ rc = WR16(s, 0x2150036, 0x0fff);
+ rc = WR16(s, 0x2150016, a);
+
+ rc = WR16(s, 0x2150010, 2);
+ rc = WR16(s, 0x2150007, 0);
+ rc = WR16(s, 0x2150000, 1);
+ rc = WR16(s, 0x2110000, 0);
+ rc = WR16(s, 0x0800000, 0);
+ rc = WR16(s, 0x2800000, 0);
+ rc = WR16(s, 0x2110010, 0x664);
+
+ rc = write_fw(s, DRXD_ResetECRAM);
+ rc = WR16(s, 0x2110000, 1);
+
+ rc = write_fw(s, DRXD_InitSC);
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = SetCfgIfAgc(s, &s->config.ifagc);
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = SetCfgRfAgc(s, &s->config.rfagc);
+ if (rc < 0)
+ goto exit_rc;
+
+ if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K)
+ v22 = 1;
+ switch (fep->u.ofdm.transmission_mode) {
+ case TRANSMISSION_MODE_8K:
+ edi = 1;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x2010010, 0);
+ if (rc < 0)
+ break;
+ v1C = 0x63;
+ v1A = 0x53;
+ v18 = 0x43;
+ break;
+ default:
+ edi = 0;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x2010010, 1);
+ if (rc < 0)
+ break;
+
+ v1C = 0x61;
+ v1A = 0x47;
+ v18 = 0x41;
+ }
+
+ switch (fep->u.ofdm.guard_interval) {
+ case GUARD_INTERVAL_1_4:
+ edi |= 0x0c;
+ break;
+ case GUARD_INTERVAL_1_8:
+ edi |= 0x08;
+ break;
+ case GUARD_INTERVAL_1_16:
+ edi |= 0x04;
+ break;
+ case GUARD_INTERVAL_1_32:
+ break;
+ default:
+ v22 |= 2;
+ }
+
+ ebx = 0;
+ ebp = 0;
+ v20 = 0;
+ v1E = 0;
+ v16 = 0;
+ v14 = 0;
+ v12 = 0;
+ v10 = 0;
+ v0E = 0;
+
+ switch (fep->u.ofdm.hierarchy_information) {
+ case HIERARCHY_1:
+ edi |= 0x40;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 1);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 1);
+ if (rc < 0)
+ goto exit_rc;
+ ebx = 0x19f;
+ ebp = 0x1fb;
+ v20 = 0x0c0;
+ v1E = 0x195;
+ v16 = 0x1d6;
+ v14 = 0x1ef;
+ v12 = 4;
+ v10 = 5;
+ v0E = 5;
+ break;
+ case HIERARCHY_2:
+ edi |= 0x80;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 2);
+ if (rc < 0)
+ goto exit_rc;
+ ebx = 0x08f;
+ ebp = 0x12f;
+ v20 = 0x0c0;
+ v1E = 0x11e;
+ v16 = 0x1d6;
+ v14 = 0x15e;
+ v12 = 4;
+ v10 = 5;
+ v0E = 5;
+ break;
+ case HIERARCHY_4:
+ edi |= 0xc0;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 3);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 3);
+ if (rc < 0)
+ goto exit_rc;
+ ebx = 0x14d;
+ ebp = 0x197;
+ v20 = 0x0c0;
+ v1E = 0x1ce;
+ v16 = 0x1d6;
+ v14 = 0x11a;
+ v12 = 4;
+ v10 = 6;
+ v0E = 5;
+ break;
+ default:
+ v22 |= 8;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x1c10047, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010012, 0);
+ if (rc < 0)
+ goto exit_rc;
+ // QPSK QAM16 QAM64
+ ebx = 0x19f; // 62
+ ebp = 0x1fb; // 15
+ v20 = 0x16a; // 62
+ v1E = 0x195; // 62
+ v16 = 0x1bb; // 15
+ v14 = 0x1ef; // 15
+ v12 = 5; // 16
+ v10 = 5; // 16
+ v0E = 5; // 16
+ }
+
+ switch (fep->u.ofdm.constellation) {
+ default:
+ v22 |= 4;
+ case QPSK:
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x1c10046, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010011, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001a, 0x10);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001b, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001c, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10062, v20);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c1002a, v1C);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10015, v16);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10016, v12);
+ if (rc < 0)
+ goto exit_rc;
+ break;
+ case QAM_16:
+ edi |= 0x10;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+
+ rc = WR16(s, 0x1c10046, 1);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010011, 1);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001a, 0x10);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001b, 4);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001c, 0);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10062, v1E);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c1002a, v1A);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10015, v14);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10016, v10);
+ if (rc < 0)
+ goto exit_rc;
+ break;
+ case QAM_64:
+ edi |= 0x20;
+ rc = WR16(s, 0x1c10046, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x2010011, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001a, 0x20);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001b, 8);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x201001c, 2);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10062, ebx);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c1002a, v18);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10015, ebp);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x1c10016, v0E);
+ if (rc < 0)
+ goto exit_rc;
+ break;
+ }
+
+ if (s->config.s20d24 == 1) {
+ rc = WR16(s, 0x2010013, 0);
+ } else {
+ rc = WR16(s, 0x2010013, 1);
+ edi |= 0x1000;
+ }
+
+ switch (fep->u.ofdm.code_rate_HP) {
+ default:
+ v22 |= 0x10;
+ case FEC_1_2:
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 0);
+ break;
+ case FEC_2_3:
+ edi |= 0x200;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 1);
+ break;
+ case FEC_3_4:
+ edi |= 0x400;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 2);
+ break;
+ case FEC_5_6: /* 5 */
+ edi |= 0x600;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 3);
+ break;
+ case FEC_7_8: /* 7 */
+ edi |= 0x800;
+ if (s->chip_rev == DRXD_FW_B1)
+ break;
+ rc = WR16(s, 0x2090011, 4);
+ break;
+ };
+ if (rc < 0)
+ goto exit_rc;
+
+ switch (fep->u.ofdm.bandwidth) {
+ default:
+ rc = -EINVAL;
+ goto exit_rc;
+ case BANDWIDTH_8_MHZ: /* 0 */
+ case BANDWIDTH_AUTO:
+ rc = WR16(s, 0x0c2003f, 0x32);
+ s->bandwidth_parm = ebx = 0x8b8249; // 9142857
+ edx = 0;
+ break;
+ case BANDWIDTH_7_MHZ:
+ rc = WR16(s, 0x0c2003f, 0x3b);
+ s->bandwidth_parm = ebx = 0x7a1200; // 8000000
+ edx = 0x4807;
+ break;
+ case BANDWIDTH_6_MHZ:
+ rc = WR16(s, 0x0c2003f, 0x47);
+ s->bandwidth_parm = ebx = 0x68a1b6; // 6857142
+ edx = 0x0f07;
+ break;
+ };
+
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = WR16(s, 0x08200ec, edx);
+ if (rc < 0)
+ goto exit_rc;
+
+ rc = RD16(s, 0x0820050);
+ if (rc < 0)
+ goto exit_rc;
+ rc = WR16(s, 0x0820050, rc);
+
+ {
+ /* Configure bandwidth specific factor */
+ ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1),
+ (u64)ebx) - 0x800000;
+ EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff));
+ EXIT_RC(WR16(s, 0x0c50011, ebx >> 16));
+
+ /* drx397xD oscillator calibration */
+ ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) +
+ (s->f_osc >> 1), (u64)s->f_osc);
+ }
+ ebx &= 0xfffffff;
+ if (fep->inversion == INVERSION_ON)
+ ebx = 0x10000000 - ebx;
+
+ EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff));
+ EXIT_RC(WR16(s, 0x0c30011, ebx >> 16));
+
+ EXIT_RC(WR16(s, 0x0800000, 1));
+ EXIT_RC(RD16(s, 0x0800000));
+
+
+ EXIT_RC(SC_WaitForReady(s));
+ EXIT_RC(WR16(s, 0x0820042, 0));
+ EXIT_RC(WR16(s, 0x0820041, v22));
+ EXIT_RC(WR16(s, 0x0820040, edi));
+ EXIT_RC(SC_SendCommand(s, 3));
+
+ rc = RD16(s, 0x0800000);
+
+ SC_WaitForReady(s);
+ WR16(s, 0x0820042, 0);
+ WR16(s, 0x0820041, 1);
+ WR16(s, 0x0820040, 1);
+ SC_SendCommand(s, 1);
+
+// rc = WR16(s, 0x2150000, 1);
+// if (rc < 0) goto exit_rc;
+
+ rc = WR16(s, 0x2150000, 2);
+ rc = WR16(s, 0x2150016, a);
+ rc = WR16(s, 0x2150010, 4);
+ rc = WR16(s, 0x2150036, 0);
+ rc = WR16(s, 0x2150000, 1);
+ s->config.d60 = 2;
+ exit_rc:
+ return rc;
+}
+
+/*******************************************************************************
+ * DVB interface
+ ******************************************************************************/
+
+static int drx397x_init(struct dvb_frontend *fe)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ int rc;
+
+ pr_debug("%s\n", __FUNCTION__);
+
+ s->config.rfagc.d00 = 2; /* 0x7c */
+ s->config.rfagc.w04 = 0;
+ s->config.rfagc.w06 = 0x3ff;
+
+ s->config.ifagc.d00 = 0; /* 0x68 */
+ s->config.ifagc.w04 = 0;
+ s->config.ifagc.w06 = 140;
+ s->config.ifagc.w08 = 0;
+ s->config.ifagc.w0A = 0x3ff;
+ s->config.ifagc.w0C = 0x388;
+
+ /* for signal strenght calculations */
+ s->config.ss76 = 820;
+ s->config.ss78 = 2200;
+ s->config.ss7A = 150;
+
+ /* HI_CfgCommand */
+ s->config.w50 = 4;
+ s->config.w52 = 9; // 0xf;
+
+ s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */
+ s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */
+ s->config.w92 = 12000; // 20000;
+
+ s->config.w9C = 0x000e;
+ s->config.w9E = 0x0000;
+
+ /* ConfigureMPEGOutput params */
+ s->config.wA0 = 4;
+ s->config.w98 = 1; // 0;
+ s->config.w9A = 1;
+
+ /* get chip revision */
+ rc = RD16(s, 0x2410019);
+ if (rc < 0)
+ return -ENODEV;
+
+ if (rc == 0) {
+ printk(KERN_INFO "%s: chip revision A2\n", mod_name);
+ rc = drx_load_fw(s, DRXD_FW_A2);
+ } else {
+
+ rc = (rc >> 12) - 3;
+ switch (rc) {
+ case 1:
+ s->flags |= F_SET_0D4h;
+ case 0:
+ case 4:
+ s->flags |= F_SET_0D0h;
+ break;
+ case 2:
+ case 5:
+ break;
+ case 3:
+ s->flags |= F_SET_0D4h;
+ break;
+ default:
+ return -ENODEV;
+ };
+ printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc);
+ rc = drx_load_fw(s, DRXD_FW_B1);
+ }
+ if (rc < 0)
+ goto error;
+
+ rc = WR16(s, 0x0420033, 0x3973);
+ if (rc < 0)
+ goto error;
+
+ rc = HI_Command(s, 2);
+
+ msleep(1);
+
+ if (s->chip_rev == DRXD_FW_A2) {
+ rc = WR16(s, 0x043012d, 0x47F);
+ if (rc < 0)
+ goto error;
+ }
+ rc = WR16_E0(s, 0x0400000, 0);
+ if (rc < 0)
+ goto error;
+
+ if (s->config.w92 > 20000 || s->config.w92 % 4000) {
+ printk(KERN_ERR "%s: invalid osc frequency\n", mod_name);
+ rc = -1;
+ goto error;
+ }
+
+ rc = WR16(s, 0x2410010, 1);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x2410011, 0x15);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x2410012, s->config.w92 / 4000);
+ if (rc < 0)
+ goto error;
+#ifdef ORIG_FW
+ rc = WR16(s, 0x2410015, 2);
+ if (rc < 0)
+ goto error;
+#endif
+ rc = WR16(s, 0x2410017, 0x3973);
+ if (rc < 0)
+ goto error;
+
+ s->f_osc = s->config.f_osc * 1000; /* initial estimator */
+
+ s->config.w56 = 1;
+
+ rc = HI_CfgCommand(s);
+ if (rc < 0)
+ goto error;
+
+ rc = write_fw(s, DRXD_InitAtomicRead);
+ if (rc < 0)
+ goto error;
+
+ if (s->chip_rev == DRXD_FW_A2) {
+ rc = WR16(s, 0x2150013, 0);
+ if (rc < 0)
+ goto error;
+ }
+
+ rc = WR16_E0(s, 0x0400002, 0);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x0400002, 0);
+ if (rc < 0)
+ goto error;
+
+ if (s->chip_rev == DRXD_FW_A2) {
+ rc = write_fw(s, DRXD_ResetCEFR);
+ if (rc < 0)
+ goto error;
+ }
+ rc = write_fw(s, DRXD_microcode);
+ if (rc < 0)
+ goto error;
+
+ s->config.w9C = 0x0e;
+ if (s->flags & F_SET_0D0h) {
+ s->config.w9C = 0;
+ rc = RD16(s, 0x0c20010);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc &= ~0x1000;
+ rc = WR16(s, 0x0c20010, rc);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc = RD16(s, 0x0c20011);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc &= ~0x8;
+ rc = WR16(s, 0x0c20011, rc);
+ if (rc < 0)
+ goto write_DRXD_InitFE_1;
+
+ rc = WR16(s, 0x0c20012, 1);
+ }
+
+ write_DRXD_InitFE_1:
+
+ rc = write_fw(s, DRXD_InitFE_1);
+ if (rc < 0)
+ goto error;
+
+ rc = 1;
+ if (s->chip_rev == DRXD_FW_B1) {
+ if (s->flags & F_SET_0D0h)
+ rc = 0;
+ } else {
+ if (s->flags & F_SET_0D0h)
+ rc = 4;
+ }
+
+ rc = WR16(s, 0x0C20012, rc);
+ if (rc < 0)
+ goto error;
+
+ rc = WR16(s, 0x0C20013, s->config.w9E);
+ if (rc < 0)
+ goto error;
+ rc = WR16(s, 0x0C20015, s->config.w9C);
+ if (rc < 0)
+ goto error;
+
+ rc = write_fw(s, DRXD_InitFE_2);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitFT);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitCP);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitCE);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitEQ);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitEC);
+ if (rc < 0)
+ goto error;
+ rc = write_fw(s, DRXD_InitSC);
+ if (rc < 0)
+ goto error;
+
+ rc = SetCfgIfAgc(s, &s->config.ifagc);
+ if (rc < 0)
+ goto error;
+
+ rc = SetCfgRfAgc(s, &s->config.rfagc);
+ if (rc < 0)
+ goto error;
+
+ rc = ConfigureMPEGOutput(s, 1);
+ rc = WR16(s, 0x08201fe, 0x0017);
+ rc = WR16(s, 0x08201ff, 0x0101);
+
+ s->config.d5C = 0;
+ s->config.d60 = 1;
+ s->config.d48 = 1;
+ error:
+ return rc;
+}
+
+static int drx397x_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ return 0;
+}
+
+static int drx397x_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+
+ s->config.s20d24 = 1; // 0;
+ return drx_tune(s, params);
+}
+
+static int drx397x_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings
+ *fe_tune_settings)
+{
+ fe_tune_settings->min_delay_ms = 10000;
+ fe_tune_settings->step_size = 0;
+ fe_tune_settings->max_drift = 0;
+ return 0;
+}
+
+static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t * status)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ int lockstat;
+
+ GetLockStatus(s, &lockstat);
+ /* TODO */
+// if (lockstat & 1)
+// CorrectSysClockDeviation(s);
+
+ *status = 0;
+ if (lockstat & 2) {
+ CorrectSysClockDeviation(s);
+ ConfigureMPEGOutput(s, 1);
+ *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
+ }
+ if (lockstat & 4) {
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ }
+
+ return 0;
+}
+
+static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
+{
+ *ber = 0;
+ return 0;
+}
+
+static int drx397x_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+ *snr = 0;
+ return 0;
+}
+
+static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ int rc;
+
+ if (s->config.ifagc.d00 == 2) {
+ *strength = 0xffff;
+ return 0;
+ }
+ rc = RD16(s, 0x0c20035);
+ if (rc < 0) {
+ *strength = 0;
+ return 0;
+ }
+ rc &= 0x3ff;
+ /* Signal strength is calculated using the following formula:
+ *
+ * a = 2200 * 150 / (2200 + 150);
+ * a = a * 3300 / (a + 820);
+ * b = 2200 * 3300 / (2200 + 820);
+ * c = (((b-a) * rc) >> 10 + a) << 4;
+ * strength = ~c & 0xffff;
+ *
+ * The following does the same but with less rounding errors:
+ */
+ *strength = ~(7720 + (rc * 30744 >> 10));
+ return 0;
+}
+
+static int drx397x_read_ucblocks(struct dvb_frontend *fe,
+ unsigned int *ucblocks)
+{
+ *ucblocks = 0;
+ return 0;
+}
+
+static int drx397x_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static void drx397x_release(struct dvb_frontend *fe)
+{
+ struct drx397xD_state *s = fe->demodulator_priv;
+ printk(KERN_INFO "%s: release demodulator\n", mod_name);
+ if (s) {
+ drx_release_fw(s);
+ kfree(s);
+ }
+
+}
+
+static struct dvb_frontend_ops drx397x_ops = {
+
+ .info = {
+ .name = "Micronas DRX397xD DVB-T Frontend",
+ .type = FE_OFDM,
+ .frequency_min = 47125000,
+ .frequency_max = 855250000,
+ .frequency_stepsize = 166667,
+ .frequency_tolerance = 0,
+ .caps = /* 0x0C01B2EAE */
+ FE_CAN_FEC_1_2 | // = 0x2,
+ FE_CAN_FEC_2_3 | // = 0x4,
+ FE_CAN_FEC_3_4 | // = 0x8,
+ FE_CAN_FEC_5_6 | // = 0x20,
+ FE_CAN_FEC_7_8 | // = 0x80,
+ FE_CAN_FEC_AUTO | // = 0x200,
+ FE_CAN_QPSK | // = 0x400,
+ FE_CAN_QAM_16 | // = 0x800,
+ FE_CAN_QAM_64 | // = 0x2000,
+ FE_CAN_QAM_AUTO | // = 0x10000,
+ FE_CAN_TRANSMISSION_MODE_AUTO | // = 0x20000,
+ FE_CAN_GUARD_INTERVAL_AUTO | // = 0x80000,
+ FE_CAN_HIERARCHY_AUTO | // = 0x100000,
+ FE_CAN_RECOVER | // = 0x40000000,
+ FE_CAN_MUTE_TS // = 0x80000000
+ },
+
+ .release = drx397x_release,
+ .init = drx397x_init,
+ .sleep = drx397x_sleep,
+
+ .set_frontend = drx397x_set_frontend,
+ .get_tune_settings = drx397x_get_tune_settings,
+ .get_frontend = drx397x_get_frontend,
+
+ .read_status = drx397x_read_status,
+ .read_snr = drx397x_read_snr,
+ .read_signal_strength = drx397x_read_signal_strength,
+ .read_ber = drx397x_read_ber,
+ .read_ucblocks = drx397x_read_ucblocks,
+};
+
+struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct drx397xD_state *s = NULL;
+
+ /* allocate memory for the internal state */
+ s = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
+ if (s == NULL)
+ goto error;
+
+ /* setup the state */
+ s->i2c = i2c;
+ memcpy(&s->config, config, sizeof(struct drx397xD_config));
+
+ /* check if the demod is there */
+ if (RD16(s, 0x2410019) < 0)
+ goto error;
+
+ /* create dvb_frontend */
+ memcpy(&s->frontend.ops, &drx397x_ops, sizeof(struct dvb_frontend_ops));
+ s->frontend.demodulator_priv = s;
+
+ return &s->frontend;
+ error:
+ kfree(s);
+ return NULL;
+}
+
+MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
+MODULE_AUTHOR("Henk Vergonet");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(drx397xD_attach);
diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h
new file mode 100644
index 00000000000..ddc7a07971b
--- /dev/null
+++ b/drivers/media/dvb/frontends/drx397xD.h
@@ -0,0 +1,130 @@
+/*
+ * Driver for Micronas DVB-T drx397xD demodulator
+ *
+ * Copyright (C) 2007 Henk vergonet <Henk.Vergonet@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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef _DRX397XD_H_INCLUDED
+#define _DRX397XD_H_INCLUDED
+
+#include <linux/dvb/frontend.h>
+
+#define DRX_F_STEPSIZE 166667
+#define DRX_F_OFFSET 36000000
+
+#define I2C_ADR_C0(x) \
+( (u32)cpu_to_le32( \
+ (u32)( \
+ (((u32)(x) & (u32)0x000000ffUL) ) | \
+ (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
+ (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
+ ( (u32)0x00c00000UL) \
+ )) \
+)
+
+#define I2C_ADR_E0(x) \
+( (u32)cpu_to_le32( \
+ (u32)( \
+ (((u32)(x) & (u32)0x000000ffUL) ) | \
+ (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
+ (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
+ ( (u32)0x00e00000UL) \
+ )) \
+)
+
+struct drx397xD_CfgRfAgc /* 0x7c */
+{
+ int d00; /* 2 */
+ u16 w04;
+ u16 w06;
+};
+
+struct drx397xD_CfgIfAgc /* 0x68 */
+{
+ int d00; /* 0 */
+ u16 w04; /* 0 */
+ u16 w06;
+ u16 w08;
+ u16 w0A;
+ u16 w0C;
+};
+
+struct drx397xD_s20 {
+ int d04;
+ u32 d18;
+ u32 d1C;
+ u32 d20;
+ u32 d14;
+ u32 d24;
+ u32 d0C;
+ u32 d08;
+};
+
+struct drx397xD_config
+{
+ /* demodulator's I2C address */
+ u8 demod_address; /* 0x0f */
+
+ struct drx397xD_CfgIfAgc ifagc; /* 0x68 */
+ struct drx397xD_CfgRfAgc rfagc; /* 0x7c */
+ u32 s20d24;
+
+ /* HI_CfgCommand parameters */
+ u16 w50, w52, /* w54, */ w56;
+
+ int d5C;
+ int d60;
+ int d48;
+ int d28;
+
+ u32 f_if; /* d14: intermediate frequency [Hz] */
+ /* 36000000 on Cinergy 2400i DT */
+ /* 42800000 on Pinnacle Hybrid PRO 330e */
+
+ u16 f_osc; /* s66: 48000 oscillator frequency [kHz] */
+
+ u16 w92; /* 20000 */
+
+ u16 wA0;
+ u16 w98;
+ u16 w9A;
+
+ u16 w9C; /* 0xe0 */
+ u16 w9E; /* 0x00 */
+
+ /* used for signal strength calculations in
+ drx397x_read_signal_strength
+ */
+ u16 ss78; // 2200
+ u16 ss7A; // 150
+ u16 ss76; // 820
+};
+
+#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE))
+extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_DRX397XD */
+
+#endif /* _DRX397XD_H_INCLUDED */
diff --git a/drivers/media/dvb/frontends/drx397xD_fw.h b/drivers/media/dvb/frontends/drx397xD_fw.h
new file mode 100644
index 00000000000..01de02a81cd
--- /dev/null
+++ b/drivers/media/dvb/frontends/drx397xD_fw.h
@@ -0,0 +1,40 @@
+/*
+ * Firmware definitions for Micronas drx397xD
+ *
+ * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef _FW_ENTRY
+ _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0 ),
+ _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1 ),
+#undef _FW_ENTRY
+#endif /* _FW_ENTRY */
+
+#ifdef _BLOB_ENTRY
+ _BLOB_ENTRY("InitAtomicRead", DRXD_InitAtomicRead = 0 ),
+ _BLOB_ENTRY("InitCE", DRXD_InitCE ),
+ _BLOB_ENTRY("InitCP", DRXD_InitCP ),
+ _BLOB_ENTRY("InitEC", DRXD_InitEC ),
+ _BLOB_ENTRY("InitEQ", DRXD_InitEQ ),
+ _BLOB_ENTRY("InitFE_1", DRXD_InitFE_1 ),
+ _BLOB_ENTRY("InitFE_2", DRXD_InitFE_2 ),
+ _BLOB_ENTRY("InitFT", DRXD_InitFT ),
+ _BLOB_ENTRY("InitSC", DRXD_InitSC ),
+ _BLOB_ENTRY("ResetCEFR", DRXD_ResetCEFR ),
+ _BLOB_ENTRY("ResetECRAM", DRXD_ResetECRAM ),
+ _BLOB_ENTRY("microcode", DRXD_microcode ),
+#undef _BLOB_ENTRY
+#endif /* _BLOB_ENTRY */
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index a054894ff48..ea058153ebf 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -343,6 +343,52 @@ static struct dvb_pll_desc dvb_pll_opera1 = {
}
};
+static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ struct i2c_msg msg = {
+ .addr = priv->pll_i2c_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 4
+ };
+ int result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ result = i2c_transfer(priv->i2c, &msg, 1);
+ if (result != 1)
+ printk(KERN_ERR "%s: i2c_transfer failed:%d",
+ __func__, result);
+
+ buf[2] = 0x9e;
+ buf[3] = 0x90;
+
+ return;
+}
+
+/* unknown pll used in Samsung DTOS403IH102A DVB-C tuner */
+static struct dvb_pll_desc dvb_pll_samsung_dtos403ih102a = {
+ .name = "Samsung DTOS403IH102A",
+ .min = 44250000,
+ .max = 858000000,
+ .iffreq = 36125000,
+ .count = 8,
+ .set = samsung_dtos403ih102a_set,
+ .entries = {
+ { 135000000, 62500, 0xbe, 0x01 },
+ { 177000000, 62500, 0xf6, 0x01 },
+ { 370000000, 62500, 0xbe, 0x02 },
+ { 450000000, 62500, 0xf6, 0x02 },
+ { 466000000, 62500, 0xfe, 0x02 },
+ { 538000000, 62500, 0xbe, 0x08 },
+ { 826000000, 62500, 0xf6, 0x08 },
+ { 999999999, 62500, 0xfe, 0x08 },
+ }
+};
+
/* ----------------------------------------------------------- */
static struct dvb_pll_desc *pll_list[] = {
@@ -360,6 +406,7 @@ static struct dvb_pll_desc *pll_list[] = {
[DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
[DVB_PLL_OPERA1] = &dvb_pll_opera1,
+ [DVB_PLL_SAMSUNG_DTOS403IH102A] = &dvb_pll_samsung_dtos403ih102a,
};
/* ----------------------------------------------------------- */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 872ca29e7cf..05239f579cc 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -22,6 +22,7 @@
#define DVB_PLL_SAMSUNG_TBMV 11
#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
#define DVB_PLL_OPERA1 13
+#define DVB_PLL_SAMSUNG_DTOS403IH102A 14
/**
* Attach a dvb-pll to the supplied frontend structure.
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index f0195c8272f..056387b41a8 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -226,11 +226,16 @@ static int lgdt330x_init(struct dvb_frontend* fe)
0x4c, 0x14
};
- static u8 flip_lgdt3303_init_data[] = {
+ static u8 flip_1_lgdt3303_init_data[] = {
0x4c, 0x14,
0x87, 0xf3
};
+ static u8 flip_2_lgdt3303_init_data[] = {
+ 0x4c, 0x14,
+ 0x87, 0xda
+ };
+
struct lgdt330x_state* state = fe->demodulator_priv;
char *chip_name;
int err;
@@ -243,10 +248,19 @@ static int lgdt330x_init(struct dvb_frontend* fe)
break;
case LGDT3303:
chip_name = "LGDT3303";
- if (state->config->clock_polarity_flip) {
- err = i2c_write_demod_bytes(state, flip_lgdt3303_init_data,
- sizeof(flip_lgdt3303_init_data));
- } else {
+ switch (state->config->clock_polarity_flip) {
+ case 2:
+ err = i2c_write_demod_bytes(state,
+ flip_2_lgdt3303_init_data,
+ sizeof(flip_2_lgdt3303_init_data));
+ break;
+ case 1:
+ err = i2c_write_demod_bytes(state,
+ flip_1_lgdt3303_init_data,
+ sizeof(flip_1_lgdt3303_init_data));
+ break;
+ case 0:
+ default:
err = i2c_write_demod_bytes(state, lgdt3303_init_data,
sizeof(lgdt3303_init_data));
}
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index b999ec424ff..7500a1c53e6 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
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
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "s5h1409.h"
struct s5h1409_state {
@@ -405,6 +404,7 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
if (state->if_freq != S5H1409_QAM_IF_FREQ)
s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
index 59f4335964c..d1a1d2eb8e1 100644
--- a/drivers/media/dvb/frontends/s5h1409.h
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1409 VSB/QAM demodulator driver
- Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/s5h1411.c b/drivers/media/dvb/frontends/s5h1411.c
index eb5bfc99d4e..2da1a3763de 100644
--- a/drivers/media/dvb/frontends/s5h1411.c
+++ b/drivers/media/dvb/frontends/s5h1411.c
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "s5h1411.h"
struct s5h1411_state {
@@ -489,6 +488,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe,
break;
case QAM_64:
case QAM_256:
+ case QAM_AUTO:
dprintk("%s() QAM_AUTO (64/256)\n", __func__);
s5h1411_set_if_freq(fe, state->config->qam_if);
s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171);
diff --git a/drivers/media/dvb/frontends/s5h1411.h b/drivers/media/dvb/frontends/s5h1411.h
index 1855f64ed4d..7d542bc00c4 100644
--- a/drivers/media/dvb/frontends/s5h1411.h
+++ b/drivers/media/dvb/frontends/s5h1411.h
@@ -1,7 +1,7 @@
/*
Samsung S5H1411 VSB/QAM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 720ed9ff7c5..747d3fa2e5e 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -915,7 +915,8 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
state->frontend.demodulator_priv = state;
/* create tuner i2c adapter */
- strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+ strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
+ sizeof(state->tuner_i2c_adapter.name));
state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index c6ff5b82ff8..a3c34eecdee 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -38,75 +38,29 @@
#include "dvb_frontend.h"
#include "tda1002x.h"
+#define REG0_INIT_VAL 0x23
struct tda10023_state {
struct i2c_adapter* i2c;
/* configuration settings */
- const struct tda1002x_config* config;
+ const struct tda10023_config *config;
struct dvb_frontend frontend;
u8 pwm;
u8 reg0;
-};
+ /* clock settings */
+ u32 xtal;
+ u8 pll_m;
+ u8 pll_p;
+ u8 pll_n;
+ u32 sysclk;
+};
#define dprintk(x...)
static int verbose;
-#define XTAL 28920000UL
-#define PLL_M 8UL
-#define PLL_P 4UL
-#define PLL_N 1UL
-#define SYSCLK (XTAL*PLL_M/(PLL_N*PLL_P)) // -> 57840000
-
-static u8 tda10023_inittab[]={
- // reg mask val
- 0x2a,0xff,0x02, // PLL3, Bypass, Power Down
- 0xff,0x64,0x00, // Sleep 100ms
- 0x2a,0xff,0x03, // PLL3, Bypass, Power Down
- 0xff,0x64,0x00, // Sleep 100ms
- 0x28,0xff,PLL_M-1, // PLL1 M=8
- 0x29,0xff,((PLL_P-1)<<6)|(PLL_N-1), // PLL2
- 0x00,0xff,0x23, // GPR FSAMPLING=1
- 0x2a,0xff,0x08, // PLL3 PSACLK=1
- 0xff,0x64,0x00, // Sleep 100ms
- 0x1f,0xff,0x00, // RESET
- 0xff,0x64,0x00, // Sleep 100ms
- 0xe6,0x0c,0x04, // RSCFG_IND
- 0x10,0xc0,0x80, // DECDVBCFG1 PBER=1
-
- 0x0e,0xff,0x82, // GAIN1
- 0x03,0x08,0x08, // CLKCONF DYN=1
- 0x2e,0xbf,0x30, // AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1 PPWMTUN=0 PPWMIF=0
- 0x01,0xff,0x30, // AGCREF
- 0x1e,0x84,0x84, // CONTROL SACLK_ON=1
- 0x1b,0xff,0xc8, // ADC TWOS=1
- 0x3b,0xff,0xff, // IFMAX
- 0x3c,0xff,0x00, // IFMIN
- 0x34,0xff,0x00, // PWMREF
- 0x35,0xff,0xff, // TUNMAX
- 0x36,0xff,0x00, // TUNMIN
- 0x06,0xff,0x7f, // EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 // 0x77
- 0x1c,0x30,0x30, // EQCONF2 STEPALGO=SGNALGO=1
- 0x37,0xff,0xf6, // DELTAF_LSB
- 0x38,0xff,0xff, // DELTAF_MSB
- 0x02,0xff,0x93, // AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3
- 0x2d,0xff,0xf6, // SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2
- 0x04,0x10,0x00, // SWRAMP=1
- 0x12,0xff,0xa1, // INTP1 POCLKP=1 FEL=1 MFS=0
- 0x2b,0x01,0xa1, // INTS1
- 0x20,0xff,0x04, // INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=?
- 0x2c,0xff,0x0d, // INTP/S TRIP=0 TRIS=0
- 0xc4,0xff,0x00,
- 0xc3,0x30,0x00,
- 0xb5,0xff,0x19, // ERAGC_THD
- 0x00,0x03,0x01, // GPR, CLBS soft reset
- 0x00,0x03,0x03, // GPR, CLBS soft reset
- 0xff,0x64,0x00, // Sleep 100ms
- 0xff,0xff,0xff
-};
-
static u8 tda10023_readreg (struct tda10023_state* state, u8 reg)
{
u8 b0 [] = { reg };
@@ -219,30 +173,34 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
s16 SFIL=0;
u16 NDEC = 0;
- if (sr < (u32)(SYSCLK/98.40)) {
+ /* avoid floating point operations multiplying syscloc and divider
+ by 10 */
+ u32 sysclk_x_10 = state->sysclk * 10;
+
+ if (sr < (u32)(sysclk_x_10/984)) {
NDEC=3;
SFIL=1;
- } else if (sr<(u32)(SYSCLK/64.0)) {
+ } else if (sr < (u32)(sysclk_x_10/640)) {
NDEC=3;
SFIL=0;
- } else if (sr<(u32)(SYSCLK/49.2)) {
+ } else if (sr < (u32)(sysclk_x_10/492)) {
NDEC=2;
SFIL=1;
- } else if (sr<(u32)(SYSCLK/32.0)) {
+ } else if (sr < (u32)(sysclk_x_10/320)) {
NDEC=2;
SFIL=0;
- } else if (sr<(u32)(SYSCLK/24.6)) {
+ } else if (sr < (u32)(sysclk_x_10/246)) {
NDEC=1;
SFIL=1;
- } else if (sr<(u32)(SYSCLK/16.0)) {
+ } else if (sr < (u32)(sysclk_x_10/160)) {
NDEC=1;
SFIL=0;
- } else if (sr<(u32)(SYSCLK/12.3)) {
+ } else if (sr < (u32)(sysclk_x_10/123)) {
NDEC=0;
SFIL=1;
}
- BDRI=SYSCLK*16;
+ BDRI = (state->sysclk)*16;
BDRI>>=NDEC;
BDRI +=sr/2;
BDRI /=sr;
@@ -255,11 +213,12 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
BDRX=1<<(24+NDEC);
BDRX*=sr;
- do_div(BDRX,SYSCLK); // BDRX/=SYSCLK;
+ do_div(BDRX, state->sysclk); /* BDRX/=SYSCLK; */
BDR=(s32)BDRX;
}
-// printk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",sr,BDR,BDRI,NDEC);
+ dprintk("Symbolrate %i, BDR %i BDRI %i, NDEC %i\n",
+ sr, BDR, BDRI, NDEC);
tda10023_writebit (state, 0x03, 0xc0, NDEC<<6);
tda10023_writereg (state, 0x0a, BDR&255);
tda10023_writereg (state, 0x0b, (BDR>>8)&255);
@@ -272,8 +231,67 @@ static int tda10023_set_symbolrate (struct tda10023_state* state, u32 sr)
static int tda10023_init (struct dvb_frontend *fe)
{
struct tda10023_state* state = fe->demodulator_priv;
+ u8 tda10023_inittab[] = {
+/* reg mask val */
+/* 000 */ 0x2a, 0xff, 0x02, /* PLL3, Bypass, Power Down */
+/* 003 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 006 */ 0x2a, 0xff, 0x03, /* PLL3, Bypass, Power Down */
+/* 009 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+ /* PLL1 */
+/* 012 */ 0x28, 0xff, (state->pll_m-1),
+ /* PLL2 */
+/* 015 */ 0x29, 0xff, ((state->pll_p-1)<<6)|(state->pll_n-1),
+ /* GPR FSAMPLING=1 */
+/* 018 */ 0x00, 0xff, REG0_INIT_VAL,
+/* 021 */ 0x2a, 0xff, 0x08, /* PLL3 PSACLK=1 */
+/* 024 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 027 */ 0x1f, 0xff, 0x00, /* RESET */
+/* 030 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 033 */ 0xe6, 0x0c, 0x04, /* RSCFG_IND */
+/* 036 */ 0x10, 0xc0, 0x80, /* DECDVBCFG1 PBER=1 */
+
+/* 039 */ 0x0e, 0xff, 0x82, /* GAIN1 */
+/* 042 */ 0x03, 0x08, 0x08, /* CLKCONF DYN=1 */
+/* 045 */ 0x2e, 0xbf, 0x30, /* AGCCONF2 TRIAGC=0,POSAGC=ENAGCIF=1
+ PPWMTUN=0 PPWMIF=0 */
+/* 048 */ 0x01, 0xff, 0x30, /* AGCREF */
+/* 051 */ 0x1e, 0x84, 0x84, /* CONTROL SACLK_ON=1 */
+/* 054 */ 0x1b, 0xff, 0xc8, /* ADC TWOS=1 */
+/* 057 */ 0x3b, 0xff, 0xff, /* IFMAX */
+/* 060 */ 0x3c, 0xff, 0x00, /* IFMIN */
+/* 063 */ 0x34, 0xff, 0x00, /* PWMREF */
+/* 066 */ 0x35, 0xff, 0xff, /* TUNMAX */
+/* 069 */ 0x36, 0xff, 0x00, /* TUNMIN */
+/* 072 */ 0x06, 0xff, 0x7f, /* EQCONF1 POSI=7 ENADAPT=ENEQUAL=DFE=1 */
+/* 075 */ 0x1c, 0x30, 0x30, /* EQCONF2 STEPALGO=SGNALGO=1 */
+/* 078 */ 0x37, 0xff, 0xf6, /* DELTAF_LSB */
+/* 081 */ 0x38, 0xff, 0xff, /* DELTAF_MSB */
+/* 084 */ 0x02, 0xff, 0x93, /* AGCCONF1 IFS=1 KAGCIF=2 KAGCTUN=3 */
+/* 087 */ 0x2d, 0xff, 0xf6, /* SWEEP SWPOS=1 SWDYN=7 SWSTEP=1 SWLEN=2 */
+/* 090 */ 0x04, 0x10, 0x00, /* SWRAMP=1 */
+/* 093 */ 0x12, 0xff, TDA10023_OUTPUT_MODE_PARALLEL_B, /*
+ INTP1 POCLKP=1 FEL=1 MFS=0 */
+/* 096 */ 0x2b, 0x01, 0xa1, /* INTS1 */
+/* 099 */ 0x20, 0xff, 0x04, /* INTP2 SWAPP=? MSBFIRSTP=? INTPSEL=? */
+/* 102 */ 0x2c, 0xff, 0x0d, /* INTP/S TRIP=0 TRIS=0 */
+/* 105 */ 0xc4, 0xff, 0x00,
+/* 108 */ 0xc3, 0x30, 0x00,
+/* 111 */ 0xb5, 0xff, 0x19, /* ERAGC_THD */
+/* 114 */ 0x00, 0x03, 0x01, /* GPR, CLBS soft reset */
+/* 117 */ 0x00, 0x03, 0x03, /* GPR, CLBS soft reset */
+/* 120 */ 0xff, 0x64, 0x00, /* Sleep 100ms */
+/* 123 */ 0xff, 0xff, 0xff
+};
+ dprintk("DVB: TDA10023(%d): init chip\n", fe->dvb->num);
+
+ /* override default values if set in config */
+ if (state->config->deltaf) {
+ tda10023_inittab[80] = (state->config->deltaf & 0xff);
+ tda10023_inittab[83] = (state->config->deltaf >> 8);
+ }
- dprintk("DVB: TDA10023(%d): init chip\n", fe->adapter->num);
+ if (state->config->output_mode)
+ tda10023_inittab[95] = state->config->output_mode;
tda10023_writetab(state, tda10023_inittab);
@@ -460,12 +478,11 @@ static void tda10023_release(struct dvb_frontend* fe)
static struct dvb_frontend_ops tda10023_ops;
-struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
- struct i2c_adapter* i2c,
+struct dvb_frontend *tda10023_attach(const struct tda10023_config *config,
+ struct i2c_adapter *i2c,
u8 pwm)
{
struct tda10023_state* state = NULL;
- int i;
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct tda10023_state), GFP_KERNEL);
@@ -474,22 +491,40 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
- state->pwm = pwm;
- for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
- if (tda10023_inittab[i] == 0x00) {
- state->reg0 = tda10023_inittab[i+2];
- break;
- }
- }
- // Wakeup if in standby
+ /* wakeup if in standby */
tda10023_writereg (state, 0x00, 0x33);
/* check if the demod is there */
if ((tda10023_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
/* create dvb_frontend */
memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
+ state->pwm = pwm;
+ state->reg0 = REG0_INIT_VAL;
+ if (state->config->xtal) {
+ state->xtal = state->config->xtal;
+ state->pll_m = state->config->pll_m;
+ state->pll_p = state->config->pll_p;
+ state->pll_n = state->config->pll_n;
+ } else {
+ /* set default values if not defined in config */
+ state->xtal = 28920000;
+ state->pll_m = 8;
+ state->pll_p = 4;
+ state->pll_n = 1;
+ }
+
+ /* calc sysclk */
+ state->sysclk = (state->xtal * state->pll_m / \
+ (state->pll_n * state->pll_p));
+
+ state->frontend.ops.info.symbol_rate_min = (state->sysclk/2)/64;
+ state->frontend.ops.info.symbol_rate_max = (state->sysclk/2)/4;
+
+ dprintk("DVB: TDA10023 %s: xtal:%d pll_m:%d pll_p:%d pll_n:%d\n",
+ __func__, state->xtal, state->pll_m, state->pll_p,
+ state->pll_n);
+
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -504,10 +539,10 @@ static struct dvb_frontend_ops tda10023_ops = {
.name = "Philips TDA10023 DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
- .frequency_min = 47000000,
+ .frequency_min = 47000000,
.frequency_max = 862000000,
- .symbol_rate_min = (SYSCLK/2)/64, /* SACLK/64 == (SYSCLK/2)/64 */
- .symbol_rate_max = (SYSCLK/2)/4, /* SACLK/4 */
+ .symbol_rate_min = 0, /* set in tda10023_attach */
+ .symbol_rate_max = 0, /* set in tda10023_attach */
.caps = 0x400 | //FE_CAN_QAM_4
FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
FE_CAN_QAM_128 | FE_CAN_QAM_256 |
diff --git a/drivers/media/dvb/frontends/tda1002x.h b/drivers/media/dvb/frontends/tda1002x.h
index 1bcc0d44b90..04d19418bf2 100644
--- a/drivers/media/dvb/frontends/tda1002x.h
+++ b/drivers/media/dvb/frontends/tda1002x.h
@@ -26,13 +26,37 @@
#include <linux/dvb/frontend.h>
-struct tda1002x_config
-{
+struct tda1002x_config {
/* the demodulator's i2c address */
u8 demod_address;
u8 invert;
};
+enum tda10023_output_mode {
+ TDA10023_OUTPUT_MODE_PARALLEL_A = 0xe0,
+ TDA10023_OUTPUT_MODE_PARALLEL_B = 0xa1,
+ TDA10023_OUTPUT_MODE_PARALLEL_C = 0xa0,
+ TDA10023_OUTPUT_MODE_SERIAL, /* TODO: not implemented */
+};
+
+struct tda10023_config {
+ /* the demodulator's i2c address */
+ u8 demod_address;
+ u8 invert;
+
+ /* clock settings */
+ u32 xtal; /* defaults: 28920000 */
+ u8 pll_m; /* defaults: 8 */
+ u8 pll_p; /* defaults: 4 */
+ u8 pll_n; /* defaults: 1 */
+
+ /* MPEG2 TS output mode */
+ u8 output_mode;
+
+ /* input freq offset + baseband conversion type */
+ u16 deltaf;
+};
+
#if defined(CONFIG_DVB_TDA10021) || (defined(CONFIG_DVB_TDA10021_MODULE) && defined(MODULE))
extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
struct i2c_adapter* i2c, u8 pwm);
@@ -45,12 +69,15 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config*
}
#endif // CONFIG_DVB_TDA10021
-#if defined(CONFIG_DVB_TDA10023) || (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
-extern struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
- struct i2c_adapter* i2c, u8 pwm);
+#if defined(CONFIG_DVB_TDA10023) || \
+ (defined(CONFIG_DVB_TDA10023_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10023_attach(
+ const struct tda10023_config *config,
+ struct i2c_adapter *i2c, u8 pwm);
#else
-static inline struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
- struct i2c_adapter* i2c, u8 pwm)
+static inline struct dvb_frontend *tda10023_attach(
+ const struct tda10023_config *config,
+ struct i2c_adapter *i2c, u8 pwm)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 0ab8d86b3ae..04e7f1cc140 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
@@ -303,7 +303,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
- return -EIO;
+ ret = -EIO;
} else {
printk(KERN_INFO "%s: firmware uploading\n", __func__);
diff --git a/drivers/media/dvb/frontends/tda10048.h b/drivers/media/dvb/frontends/tda10048.h
index 2b5c78e62c8..0457b24601f 100644
--- a/drivers/media/dvb/frontends/tda10048.h
+++ b/drivers/media/dvb/frontends/tda10048.h
@@ -1,7 +1,7 @@
/*
NXP TDA10048HN DVB OFDM demodulator driver
- Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
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
diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb/frontends/z0194a.h
new file mode 100644
index 00000000000..d2876d2e176
--- /dev/null
+++ b/drivers/media/dvb/frontends/z0194a.h
@@ -0,0 +1,97 @@
+/* z0194a.h Sharp z0194a tuner support
+*
+* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation, version 2.
+*
+* see Documentation/dvb/README.dvb-usb for more information
+*/
+
+#ifndef Z0194A
+#define Z0194A
+
+static int sharp_z0194a__set_symbol_rate(struct dvb_frontend *fe,
+ u32 srate, u32 ratio)
+{
+ u8 aclk = 0;
+ u8 bclk = 0;
+
+ if (srate < 1500000) {
+ aclk = 0xb7; bclk = 0x47; }
+ else if (srate < 3000000) {
+ aclk = 0xb7; bclk = 0x4b; }
+ else if (srate < 7000000) {
+ aclk = 0xb7; bclk = 0x4f; }
+ else if (srate < 14000000) {
+ aclk = 0xb7; bclk = 0x53; }
+ else if (srate < 30000000) {
+ aclk = 0xb6; bclk = 0x53; }
+ else if (srate < 45000000) {
+ aclk = 0xb4; bclk = 0x51; }
+
+ stv0299_writereg(fe, 0x13, aclk);
+ stv0299_writereg(fe, 0x14, bclk);
+ stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+ stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
+ stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
+
+ return 0;
+}
+
+static u8 sharp_z0194a__inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x00,
+ 0x03, 0x00,
+ 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
+ 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
+ 0x06, 0x40, /* DAC not used, set to high impendance mode */
+ 0x07, 0x00, /* DAC LSB */
+ 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
+ 0x09, 0x00, /* FIFO */
+ 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
+ 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
+ 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
+ 0x10, 0x3f, /* AGC2 0x3d */
+ 0x11, 0x84,
+ 0x12, 0xb9,
+ 0x15, 0xc9, /* lock detector threshold */
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1f, 0x50,
+ 0x20, 0x00,
+ 0x21, 0x00,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x28, 0x00, /* out imp: normal out type: parallel FEC mode:0 */
+ 0x29, 0x1e, /* 1/2 threshold */
+ 0x2a, 0x14, /* 2/3 threshold */
+ 0x2b, 0x0f, /* 3/4 threshold */
+ 0x2c, 0x09, /* 5/6 threshold */
+ 0x2d, 0x05, /* 7/8 threshold */
+ 0x2e, 0x01,
+ 0x31, 0x1f, /* test all FECs */
+ 0x32, 0x19, /* viterbi and synchro search */
+ 0x33, 0xfc, /* rs control */
+ 0x34, 0x93, /* error control */
+ 0x0f, 0x52,
+ 0xff, 0xff
+};
+
+static struct stv0299_config sharp_z0194a_config = {
+ .demod_address = 0x68,
+ .inittab = sharp_z0194a__inittab,
+ .mclk = 88000000UL,
+ .invert = 1,
+ .skip_reinit = 0,
+ .lock_output = STV0299_LOCKOUTPUT_1,
+ .volt13_op0_op1 = STV0299_VOLT13_OP1,
+ .min_delay_ms = 100,
+ .set_symbol_rate = sharp_z0194a__set_symbol_rate,
+};
+
+#endif