summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb
diff options
context:
space:
mode:
authorHolger Waechtler <devnull@localhost>2002-10-21 14:31:17 +0000
committerHolger Waechtler <devnull@localhost>2002-10-21 14:31:17 +0000
commit386ceb89ed54b591dbc72e00c55d9a0b0c0b23a1 (patch)
tree22560fdcea18137cd507634a61835fea43c04b6f /linux/drivers/media/dvb
parenteb07eea33bdf36d2f94c939b06a20cdda7e64e29 (diff)
downloadmediapointer-dvb-s2-386ceb89ed54b591dbc72e00c55d9a0b0c0b23a1.tar.gz
mediapointer-dvb-s2-386ceb89ed54b591dbc72e00c55d9a0b0c0b23a1.tar.bz2
another frontend
Diffstat (limited to 'linux/drivers/media/dvb')
-rw-r--r--linux/drivers/media/dvb/frontends/Config.help7
-rw-r--r--linux/drivers/media/dvb/frontends/Config.in1
-rw-r--r--linux/drivers/media/dvb/frontends/Makefile1
-rw-r--r--linux/drivers/media/dvb/frontends/alps_tdmb7.c467
4 files changed, 476 insertions, 0 deletions
diff --git a/linux/drivers/media/dvb/frontends/Config.help b/linux/drivers/media/dvb/frontends/Config.help
index dd7cdc2d8..b4e0fbb8f 100644
--- a/linux/drivers/media/dvb/frontends/Config.help
+++ b/linux/drivers/media/dvb/frontends/Config.help
@@ -14,6 +14,13 @@ CONFIG_DVB_ALPS_BSRV2
DVB adapter simply enable all supported frontends, the
right one will get autodetected.
+CONFIG_DVB_ALPS_TDMB7
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
+ If you don't know what tuner module is soldered on your
+ DVB adapter simply enable all supported frontends, the
+ right one will get autodetected.
+
CONFIG_DVB_GRUNDIG_29504_491
A DVB-S tuner module. Say Y when you want to support this frontend.
diff --git a/linux/drivers/media/dvb/frontends/Config.in b/linux/drivers/media/dvb/frontends/Config.in
index 638a9462c..d44894a0b 100644
--- a/linux/drivers/media/dvb/frontends/Config.in
+++ b/linux/drivers/media/dvb/frontends/Config.in
@@ -3,6 +3,7 @@ comment 'Supported Frontend Modules'
dep_tristate ' Alps BSRU6 (QPSK)' CONFIG_DVB_ALPS_BSRU6 $CONFIG_DVB_CORE
dep_tristate ' Alps BSRV2 (QPSK)' CONFIG_DVB_ALPS_BSRV2 $CONFIG_DVB_CORE
+dep_tristate ' Alps TDMB7 (OFDM)' CONFIG_DVB_ALPS_TDMB7 $CONFIG_DVB_CORE
dep_tristate ' Grundig 29504-491 (QPSK)' CONFIG_DVB_GRUNDIG_29504_491 $CONFIG_DVB_CORE
dep_tristate ' Grundig 29504-401 (OFDM)' CONFIG_DVB_GRUNDIG_29504_401 $CONFIG_DVB_CORE
dep_tristate ' Frontends with external VES1820 demodulator (QAM)' CONFIG_DVB_VES1820 $CONFIG_DVB_CORE
diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile
index 3ee94a40a..5fd14508f 100644
--- a/linux/drivers/media/dvb/frontends/Makefile
+++ b/linux/drivers/media/dvb/frontends/Makefile
@@ -6,6 +6,7 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
obj-$(CONFIG_DVB_ALPS_BSRU6) += alps_bsru6.o
obj-$(CONFIG_DVB_ALPS_BSRV2) += alps_bsrv2.o
+obj-$(CONFIG_DVB_ALPS_TDMB7) += alps_tdmb7.o
obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o
obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
diff --git a/linux/drivers/media/dvb/frontends/alps_tdmb7.c b/linux/drivers/media/dvb/frontends/alps_tdmb7.c
new file mode 100644
index 000000000..b17f5a0c9
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/alps_tdmb7.c
@@ -0,0 +1,467 @@
+/*
+ Alps TDMB7 DVB OFDM frontend driver
+
+ Copyright (C) 2001-2002 Convergence Integrated Media GmbH
+ Holger Waechtler <holger@convergence.de>
+
+ 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 <linux/init.h>
+#include <linux/module.h>
+
+#include "../compat.h"
+#include "../dvb_frontend.h"
+
+
+static int debug = 0;
+#define dprintk if (debug) printk
+
+
+static
+struct dvb_frontend_info tdmb7_info = {
+ name: "Alps TDMB7",
+ type: FE_OFDM,
+ frequency_min: 470000000,
+ frequency_max: 860000000,
+ frequency_stepsize: 166667,
+#if 0
+ frequency_tolerance: ???,
+ symbol_rate_min: ???,
+ symbol_rate_max: ???,
+ symbol_rate_tolerance: 500, /* ppm */
+ notifier_delay: 0,
+#endif
+ 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
+};
+
+
+static
+inline void ddelay (int timeout)
+{
+ current->state=TASK_INTERRUPTIBLE;
+ schedule_timeout(timeout);
+}
+
+
+static
+u8 init_tab [] = {
+ 0x04, 0x10,
+ 0x05, 0x09,
+ 0x06, 0x00,
+ 0x08, 0x04,
+ 0x09, 0x00,
+ 0x0a, 0x01,
+ 0x15, 0x40,
+ 0x16, 0x10,
+ 0x17, 0x87,
+ 0x18, 0x17,
+ 0x1a, 0x10,
+ 0x25, 0x04,
+ 0x2e, 0x00,
+ 0x39, 0x00,
+ 0x3a, 0x04,
+ 0x45, 0x08,
+ 0x46, 0x02,
+ 0x47, 0x05,
+};
+
+
+static
+int cx22700_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = { addr: 0x43, flags: 0, buf: buf, len: 2 };
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ ret = i2c->xfer (i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
+ __FUNCTION__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+
+static
+u8 cx22700_readreg (struct dvb_i2c_bus *i2c, u8 reg)
+{
+ int ret;
+ u8 b0 [] = { reg };
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg [] = { { addr: 0x43, flags: 0, buf: b0, len: 1 },
+ { addr: 0x43, flags: I2C_M_RD, buf: b1, len: 1 } };
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ ret = i2c->xfer (i2c, msg, 2);
+
+ if (ret != 2)
+ printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+
+ return b1[0];
+}
+
+
+static
+int pll_write (struct dvb_i2c_bus *i2c, u8 data [4])
+{
+ struct i2c_msg msg = { addr: 0x61, flags: 0, buf: data, len: 4 };
+ int ret;
+printk ("%s: [%02x %02x %02x %02x]\n", __FUNCTION__, data[0]&0xff, data[1]&0xff, data[2]&0xff, data[3]&0xff);
+ cx22700_writereg (i2c, 0x0a, 0x00); /* open i2c bus switch */
+ ret = i2c->xfer (i2c, &msg, 1);
+ cx22700_writereg (i2c, 0x0a, 0x01); /* close i2c bus switch */
+
+ if (ret != 1)
+ printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", __FUNCTION__, msg.addr, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+
+/**
+ * set up the downconverter frequency divisor for a
+ * reference clock comparision frequency of 125 kHz.
+ */
+static
+int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
+{
+ u32 div = (freq + 36166667) / 166667;
+#if 1 //ALPS_SETTINGS
+ u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85,
+ freq < 592000000 ? 0x40 : 0x80 };
+#else
+ u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85,
+ freq < 470000000 ? 0x42 : freq < 862000000 ? 0x41 : 0x81 };
+#endif
+
+ dprintk ("%s: freq == %i, div == %i\n", __FUNCTION__, freq, div);
+
+ return pll_write (i2c, buf);
+}
+
+
+static
+int cx22700_init (struct dvb_i2c_bus *i2c)
+{
+ int i;
+
+ dprintk("cx22700_init: init chip\n");
+
+ cx22700_writereg (i2c, 0x00, 0x02); /* soft reset */
+ cx22700_writereg (i2c, 0x00, 0x00);
+
+ ddelay (HZ/100);
+
+ for (i=0; i<sizeof(init_tab); i+=2)
+ cx22700_writereg (i2c, init_tab[i], init_tab[i+1]);
+
+ cx22700_writereg (i2c, 0x00, 0x01);
+
+ return 0;
+}
+
+
+static
+int cx22700_set_inversion (struct dvb_i2c_bus *i2c, int inversion)
+{
+ u8 val;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ switch (inversion) {
+ case INVERSION_AUTO:
+ return -EOPNOTSUPP;
+ case INVERSION_ON:
+ val = cx22700_readreg (i2c, 0x09);
+ return cx22700_writereg (i2c, 0x09, val | 0x01);
+ case INVERSION_OFF:
+ val = cx22700_readreg (i2c, 0x09);
+ return cx22700_writereg (i2c, 0x09, val & 0xfe);
+ default:
+ return -EINVAL;
+ }
+}
+
+
+static
+int cx22700_set_tps (struct dvb_i2c_bus *i2c, struct dvb_ofdm_parameters *p)
+{
+ static const u8 qam_tab [4] = { 0, 1, 0, 2 };
+ static const u8 fec_tab [6] = { 0, 1, 2, 0, 3, 4 };
+ u8 val;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (p->code_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8)
+ return -EINVAL;
+
+ if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
+
+ if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
+ return -EINVAL;
+
+ if (p->guard_interval < GUARD_INTERVAL_1_32 ||
+ p->guard_interval > GUARD_INTERVAL_1_4)
+ return -EINVAL;
+
+ if (p->transmission_mode != TRANSMISSION_MODE_2K &&
+ p->transmission_mode != TRANSMISSION_MODE_8K)
+ return -EINVAL;
+
+ if (p->constellation != QPSK &&
+ p->constellation != QAM_16 &&
+ p->constellation != QAM_64)
+ return -EINVAL;
+
+ if (p->hierarchy_information < HIERARCHY_NONE ||
+ p->hierarchy_information > HIERARCHY_4)
+ return -EINVAL;
+
+ if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ)
+ return -EINVAL;
+
+ if (p->bandwidth == BANDWIDTH_7_MHZ)
+ cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 | 0x10));
+ else
+ cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 & ~0x10));
+printk ("start setting TPS...\n");
+ val = qam_tab[p->constellation - QPSK];
+ val |= p->hierarchy_information - HIERARCHY_NONE;
+
+ cx22700_writereg (i2c, 0x04, val);
+
+ val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
+ val |= fec_tab[p->code_rate_LP - FEC_1_2];
+
+ cx22700_writereg (i2c, 0x05, val);
+
+ val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2;
+ val |= p->transmission_mode - TRANSMISSION_MODE_2K;
+
+ cx22700_writereg (i2c, 0x06, val);
+
+ cx22700_writereg (i2c, 0x08, 0x04 | 0x02); /* use user tps parameters */
+ cx22700_writereg (i2c, 0x08, 0x04); /* restart aquisition */
+
+ return 0;
+}
+
+
+static
+int cx22700_get_tps (struct dvb_i2c_bus *i2c, struct dvb_ofdm_parameters *p)
+{
+ static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 };
+ static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4,
+ FEC_5_6, FEC_7_8 };
+ u8 val;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (!(cx22700_readreg(i2c, 0x07) & 0x20)) /* tps valid? */
+ return -EAGAIN;
+
+ val = cx22700_readreg (i2c, 0x01);
+
+ if ((val & 0x7) > 4)
+ p->hierarchy_information = HIERARCHY_AUTO;
+ else
+ p->hierarchy_information = HIERARCHY_NONE + (val & 0x7);
+
+ if (((val >> 3) & 0x3) > 2)
+ p->constellation = QAM_AUTO;
+ else
+ p->constellation = qam_tab[(val >> 3) & 0x3];
+
+
+ val = cx22700_readreg (i2c, 0x02);
+
+ if ((val >> 3) > 4)
+ p->code_rate_HP = FEC_AUTO;
+ else
+ p->code_rate_HP = fec_tab[val >> 3];
+
+ if ((val & 0x7) > 4)
+ p->code_rate_LP = FEC_AUTO;
+ else
+ p->code_rate_LP = fec_tab[val >> 3];
+
+
+ val = cx22700_readreg (i2c, 0x03);
+
+ p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3);
+ p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1);
+
+ return 0;
+}
+
+
+static
+int tdmb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
+{
+ struct dvb_i2c_bus *i2c = fe->i2c;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ switch (cmd) {
+ case FE_GET_INFO:
+ memcpy (arg, &tdmb7_info, sizeof(struct dvb_frontend_info));
+ break;
+
+ case FE_READ_STATUS:
+ {
+ fe_status_t *status = (fe_status_t *) arg;
+ u8 ber = 2 * (cx22700_readreg (i2c, 0x0c) & 0x7f);
+ u8 sync = cx22700_readreg (i2c, 0x07);
+
+ *status = 0;
+
+ if (ber < 40)
+ *status |= FE_HAS_SIGNAL;
+
+ if (sync & 0x20)
+ *status |= FE_HAS_CARRIER;
+
+ if (sync & 0x10)
+ *status |= FE_HAS_VITERBI;
+
+ if (sync & 0x10)
+ *status |= FE_HAS_SYNC;
+
+ if (sync & 0x10)
+ *status |= FE_HAS_LOCK;
+
+ break;
+ }
+
+ case FE_READ_BER:
+ *((uint32_t*) arg) = cx22700_readreg (i2c, 0x0c) & 0x7f;
+ break;
+
+ case FE_READ_SIGNAL_STRENGTH:
+ {
+ u8 ber = cx22700_readreg (i2c, 0x0c) & 0x7f;
+ ber *= 2;
+ *((uint16_t*) arg) = ~((ber << 8) | ber);
+ break;
+ }
+ case FE_READ_SNR:
+ {
+ u16 rs_ber = (cx22700_readreg (i2c, 0x0d) & 0x7f)
+ | cx22700_readreg (i2c, 0x0e);
+ *((uint16_t*) arg) = ~rs_ber;
+ break;
+ }
+ case FE_READ_UNCORRECTED_BLOCKS:
+ *((uint32_t*) arg) = cx22700_readreg (i2c, 0x0f);
+ break;
+
+ case FE_SET_FRONTEND:
+ {
+ struct dvb_frontend_parameters *p = arg;
+
+ cx22700_writereg (i2c, 0x00, 0x02); /* XXX CHECKME: soft reset*/
+ cx22700_writereg (i2c, 0x00, 0x00);
+
+ pll_set_tv_freq (i2c, p->frequency);
+ cx22700_set_inversion (i2c, p->inversion);
+ cx22700_set_tps (i2c, &p->u.ofdm);
+ cx22700_writereg (i2c, 0x37, 0x01); /* PAL loop filter off */
+ cx22700_writereg (i2c, 0x00, 0x01); /* restart aquire */
+ break;
+ }
+
+ case FE_GET_FRONTEND:
+ {
+ struct dvb_frontend_parameters *p = arg;
+ u8 reg09 = cx22700_readreg (i2c, 0x09);
+
+ p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF;
+ return cx22700_get_tps (i2c, &p->u.ofdm);
+ }
+
+ case FE_INIT:
+ return cx22700_init (i2c);
+
+ case FE_RESET:
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ };
+
+ return 0;
+}
+
+
+
+static
+int tdmb7_attach (struct dvb_i2c_bus *i2c)
+{
+ struct i2c_msg msg = { addr: 0x43, flags: 0, buf: NULL, len: 0 };
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (i2c->xfer (i2c, &msg, 1) != 1)
+ return -ENODEV;
+
+ dvb_register_frontend (tdmb7_ioctl, i2c, NULL, &tdmb7_info);
+
+ return 0;
+}
+
+
+static
+void tdmb7_detach (struct dvb_i2c_bus *i2c)
+{
+ dprintk ("%s\n", __FUNCTION__);
+
+ dvb_unregister_frontend (tdmb7_ioctl, i2c);
+}
+
+
+static
+int __init init_tdmb7 (void)
+{
+ dprintk ("%s\n", __FUNCTION__);
+
+ return dvb_register_i2c_device (THIS_MODULE, tdmb7_attach, tdmb7_detach);
+}
+
+
+static
+void __exit exit_tdmb7 (void)
+{
+ dprintk ("%s\n", __FUNCTION__);
+
+ dvb_unregister_i2c_device (tdmb7_attach);
+}
+
+module_init (init_tdmb7);
+module_exit (exit_tdmb7);
+
+MODULE_PARM(debug,"i");
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+MODULE_DESCRIPTION("TDMB7 DVB Frontend driver");
+MODULE_AUTHOR("Holger Waechtler");
+MODULE_LICENSE("GPL");
+