[linux-dvb] PATCH: New driver for Zarlink ZL10313 based Compro S350/S300
Jan D. Louw
jd.louw at mweb.co.za
Sat Dec 29 17:58:21 CET 2007
Hi List,
Attached is a new driver for the Zarlink ZL10313/ZL10039 based Compro
S350/S300 budget DVB-S cards. Everything except 2 way diseqc should work.
diff -r f637ac5a5898 linux/drivers/media/common/ir-keymaps.c
--- a/linux/drivers/media/common/ir-keymaps.c Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/common/ir-keymaps.c Fri Dec 28 15:51:25 2007 +0200
@@ -1898,3 +1898,40 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[I
};
EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
+
+IR_KEYTAB_TYPE ir_codes_videomate_s350[IR_KEYTAB_SIZE] = {
+ [ 0x00 ] = KEY_TV,
+ [ 0x01 ] = KEY_DVD,
+ [ 0x04 ] = KEY_RECORD,
+ [ 0x05 ] = KEY_VIDEO, /* TV/Video */
+ [ 0x07 ] = KEY_STOP,
+ [ 0x08 ] = KEY_PLAYPAUSE,
+ [ 0x0a ] = KEY_REWIND,
+ [ 0x0f ] = KEY_FASTFORWARD,
+ [ 0x10 ] = KEY_CHANNELUP,
+ [ 0x12 ] = KEY_VOLUMEUP,
+ [ 0x13 ] = KEY_CHANNELDOWN,
+ [ 0x14 ] = KEY_MUTE,
+ [ 0x15 ] = KEY_VOLUMEDOWN,
+ [ 0x16 ] = KEY_1,
+ [ 0x17 ] = KEY_2,
+ [ 0x18 ] = KEY_3,
+ [ 0x19 ] = KEY_4,
+ [ 0x1a ] = KEY_5,
+ [ 0x1b ] = KEY_6,
+ [ 0x1c ] = KEY_7,
+ [ 0x1d ] = KEY_8,
+ [ 0x1e ] = KEY_9,
+ [ 0x1f ] = KEY_0,
+ [ 0x21 ] = KEY_SLEEP,
+ [ 0x24 ] = KEY_ZOOM,
+ [ 0x25 ] = KEY_LAST, /* Recall */
+ [ 0x26 ] = KEY_SUBTITLE, /* CC */
+ [ 0x27 ] = KEY_LANGUAGE, /* MTS */
+ [ 0x29 ] = KEY_CHANNEL, /* SURF */
+ [ 0x2b ] = KEY_A,
+ [ 0x2c ] = KEY_B,
+ [ 0x2f ] = KEY_SHUFFLE, /* Snapshot */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_videomate_s350);
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/Kconfig
--- a/linux/drivers/media/dvb/frontends/Kconfig Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/Kconfig Sat Dec 29 16:34:08 2007 +0200
@@ -70,6 +70,13 @@ config DVB_TDA10086
default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_ZL10313
+ tristate "Zarlink ZL10313 DVB-S demodulator"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S demodulator module. Say Y when you want to support this frontend.
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@@ -369,6 +376,14 @@ config DVB_TUNER_XC5000
This device is only used inside a SiP called togther with a
demodulator for now.
+config DVB_ZL10039
+ tristate "Zarlink ZL10039 DVB-S tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the ZL10039 DVB-S tuner from Zarlink
+
+
comment "Miscellaneous devices"
depends on DVB_CORE
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/Makefile
--- a/linux/drivers/media/dvb/frontends/Makefile Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/dvb/frontends/Makefile Fri Dec 28 15:12:10 2007 +0200
@@ -51,3 +51,5 @@ obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131
obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_DVB_ZL10313) += zl10313.o
+obj-$(CONFIG_DVB_ZL10039) += zl10039.o
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/zl10039.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/zl10039.c Sat Dec 29 16:04:18 2007 +0200
@@ -0,0 +1,260 @@
+/*
+ * Driver for Zarlink ZL10039 DVB-S tuner
+ *
+ * Copyright 2007 Jan Daniël Louw <jd.louw at mweb.co.za>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/dvb/frontend.h>
+
+#include "dvb_frontend.h"
+#include "zl10039.h"
+#include "zl10039_priv.h"
+
+
+static int zl10039_read(const struct zl10039_state *state,
+ const enum zl10039_reg_addr reg, u8 *buf,
+ const size_t count)
+{
+ struct i2c_msg msg[2];
+ u8 regbuf[1] = { reg };
+ int i;
+
+ io_printk("%s\n", __FUNCTION__);
+ /* Write register address */
+ msg[0].addr = state->config.tuner_address;
+ msg[0].flags = 0;
+ msg[0].buf = regbuf;
+ msg[0].len = 1;
+ /* Read count bytes */
+ msg[1].addr = state->config.tuner_address;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ eprintk("%s: i2c read error\n", __FUNCTION__);
+ return -EREMOTEIO;
+ }
+ for (i = 0; i < count; i++) {
+ io_printk("R[%s] = 0x%x\n", zl10039_reg_names[reg + i], buf[i]);
+ }
+ return 0; /* Success */
+}
+
+static int zl10039_write(struct zl10039_state *state,
+ const enum zl10039_reg_addr reg, const u8 *src,
+ const size_t count)
+{
+ u8 buf[count + 1];
+ struct i2c_msg msg;
+ int i;
+
+ io_printk("%s\n", __FUNCTION__);
+ for (i = 0; i < count; i++) {
+ io_printk("W[%s] = 0x%x\n", zl10039_reg_names[reg + i], src[i]);
+ }
+ /* Write register address and data in one go */
+ buf[0] = reg;
+ memcpy(&buf[1], src, count);
+ msg.addr = state->config.tuner_address;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = count + 1;
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ eprintk("%s: i2c write error\n", __FUNCTION__);
+ return -EREMOTEIO;
+ }
+ return 0; /* Success */
+}
+
+static inline int zl10039_readreg(struct zl10039_state *state,
+ const enum zl10039_reg_addr reg, u8 *val)
+{
+ return zl10039_read(state, reg, val, 1);
+}
+
+static inline int zl10039_writereg(struct zl10039_state *state,
+ const enum zl10039_reg_addr reg,
+ const u8 val)
+{
+ return zl10039_write(state, reg, &val, 1);
+}
+
+static int zl10039_init(struct dvb_frontend *fe)
+{
+ struct zl10039_state *state = fe->tuner_priv;
+ int ret;
+
+ trace_printk("%s\n", __FUNCTION__);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+ /* Reset logic */
+ ret = zl10039_writereg(state, GENERAL, 0x40);
+ if (ret < 0) {
+ eprintk("Note: i2c write error normal when resetting the "
+ "tuner\n");
+ }
+ /* Wake up */
+ ret = zl10039_writereg(state, GENERAL, 0x01);
+ if (ret < 0) {
+ eprintk("Tuner power up failed\n");
+ return ret;
+ }
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ return 0;
+}
+
+static int zl10039_sleep(struct dvb_frontend *fe)
+{
+ struct zl10039_state *state = fe->tuner_priv;
+ int ret;
+
+ trace_printk("%s\n", __FUNCTION__);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+ ret = zl10039_writereg(state, GENERAL, 0x80);
+ if (ret < 0) {
+ eprintk("Tuner sleep failed\n");
+ return ret;
+ }
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ return 0;
+}
+
+static int zl10039_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct zl10039_state *state = fe->tuner_priv;
+ u8 buf[6];
+ u8 bf;
+ u32 fbw;
+ u32 div;
+ int ret;
+
+ trace_printk("%s\n", __FUNCTION__);
+ params_printk("Set frequency = %d, symbol rate = %d\n",
+ params->frequency, params->u.qpsk.symbol_rate);
+
+ /* Assumed 10.111 MHz crystal oscillator */
+ /* Cancelled num/den 80 to prevent overflow */
+ div = (params->frequency * 1000) / 126387;
+ fbw = (params->u.qpsk.symbol_rate * 27) / 32000;
+ /* Cancelled num/den 10 to prevent overflow */
+ bf = ((fbw * 5088) / 1011100) - 1;
+
+ /*PLL divider*/
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = (div >> 0) & 0xff;
+ /*Reference divider*/
+ /* Select reference ratio of 80 */
+ buf[2] = 0x1D;
+ /*PLL test modes*/
+ buf[3] = 0x40;
+ /*RF Control register*/
+ buf[4] = 0x6E; /* Bypass enable */
+ /*Baseband filter cutoff */
+ buf[5] = bf;
+
+ /* Open i2c gate */
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+ /* BR = 10, Enable filter adjustment */
+ ret = zl10039_writereg(state, BASE1, 0x0A);
+ if (ret < 0) goto error;
+ /* Write new config values */
+ ret = zl10039_write(state, PLL0, buf, sizeof(buf));
+ if (ret < 0) goto error;
+ /* BR = 10, Disable filter adjustment */
+ ret = zl10039_writereg(state, BASE1, 0x6A);
+ if (ret < 0) goto error;
+
+ zl10039_dump_registers(state);
+ /* Close i2c gate */
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ return 0;
+error:
+ eprintk("Error setting tuner\n");
+ return ret;
+}
+
+static struct dvb_tuner_ops zl10039_ops;
+
+struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
+ const struct zl10039_config *config, struct i2c_adapter *i2c)
+{
+ struct zl10039_state *state = NULL;
+
+ trace_printk("%s\n", __FUNCTION__);
+ state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ state->i2c = i2c;
+ state->config.tuner_address = config->tuner_address;
+
+ /* Open i2c gate */
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+ /* check if this is a valid tuner */
+ if (zl10039_readreg(state, GENERAL, &state->id) < 0) {
+ /* Close i2c gate */
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ goto error;
+ }
+ /* Close i2c gate */
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+
+ state->id = state->id & 0x0F;
+ switch (state->id) {
+ case ID_ZL10039:
+ strcpy(fe->ops.tuner_ops.info.name,
+ "Zarlink ZL10039 DVB-S tuner");
+ break;
+ default:
+ eprintk("Chip ID does not match a known type\n");
+ goto error;
+ }
+ memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = state;
+ iprintk("Tuner attached @ i2c address 0x%02x\n", config->tuner_address);
+ return fe;
+error:
+ kfree(state);
+ return NULL;
+}
+
+static int zl10039_release(struct dvb_frontend *fe)
+{
+ struct zl10039_state *state = fe->tuner_priv;
+
+ trace_printk("%s\n", __FUNCTION__);
+ kfree(state);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static struct dvb_tuner_ops zl10039_ops = {
+ .release = zl10039_release,
+ .init = zl10039_init,
+ .sleep = zl10039_sleep,
+ .set_params = zl10039_set_params,
+};
+
+EXPORT_SYMBOL(zl10039_attach);
+
+MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver");
+MODULE_AUTHOR("Jan Daniël Louw <jd.louw at mweb.co.za>");
+MODULE_LICENSE("GPL");
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/zl10039.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/zl10039.h Sat Dec 29 15:12:47 2007 +0200
@@ -0,0 +1,46 @@
+/*
+ Driver for Zarlink ZL10039 DVB-S tuner
+
+ Copyright (C) 2007 Jan Daniël Louw <jd.louw at mweb.co.za>
+
+ 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 ZL10039_H
+#define ZL10039_H
+
+struct zl10039_config
+{
+ /* tuner's i2c address */
+ u8 tuner_address;
+};
+
+#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \
+ && defined(MODULE))
+struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
+ const struct zl10039_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend * zl10039_attach(struct dvb_frontend *fe,
+ const struct zl10039_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_ZL10039 */
+
+#endif /* ZL10039_H */
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/zl10039_priv.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/zl10039_priv.h Sat Dec 29 16:09:49 2007 +0200
@@ -0,0 +1,121 @@
+/*
+ * Driver for Zarlink ZL10039 DVB-S tuner
+ *
+ * Copyright 2007 Jan Daniël Louw <jd.louw at mweb.co.za>
+ *
+ * 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 DVB_FRONTENDS_ZL10039_PRIV
+#define DVB_FRONTENDS_ZL10039_PRIV
+
+/* Trace function calls */
+#define DEBUG_CALL_TRACE 0
+/* Trace read/write function calls - information overload */
+#define DEBUG_IO_TRACE 0
+/* Print register values at critical points */
+#define DEBUG_DUMP_REGISTERS 0
+/* Print important params passed to functions */
+#define DEBUG_PRINT_PARAMS 0
+
+#if DEBUG_CALL_TRACE
+ #define trace_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " args)
+#else
+ #define trace_printk(args...)
+#endif
+
+#if DEBUG_IO_TRACE
+ #define io_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " args)
+#else
+ #define io_printk(args...)
+#endif
+
+#if DEBUG_PRINT_PARAMS
+ #define params_printk(args...) printk(KERN_DEBUG "tuner: zl10039: " \
+ args)
+#else
+ #define params_printk(args...)
+#endif
+
+#define eprintk(args...) printk(KERN_ERR "tuner: zl10039: " args)
+#define iprintk(args...) printk(KERN_INFO "tuner: zl10039: " args)
+
+enum zl10039_model_id {
+ ID_ZL10039 = 1
+};
+
+struct zl10039_state {
+ struct i2c_adapter *i2c;
+ struct zl10039_config config;
+ u8 id;
+};
+
+enum zl10039_reg_addr {
+ PLL0 = 0,
+ PLL1,
+ PLL2,
+ PLL3,
+ RFFE,
+ BASE0,
+ BASE1,
+ BASE2,
+ LO0,
+ LO1,
+ LO2,
+ LO3,
+ LO4,
+ LO5,
+ LO6,
+ GENERAL
+};
+
+#if DEBUG_DUMP_REGISTERS || DEBUG_IO_TRACE
+static const char *zl10039_reg_names[] = {
+ "PLL_0", "PLL_1", "PLL_2", "PLL_3",
+ "RF_FRONT_END", "BASE_BAND_0", "BASE_BAND_1", "BASE_BAND_2",
+ "LOCAL_OSC_0", "LOCAL_OSC_1", "LOCAL_OSC_2", "LOCAL_OSC_3",
+ "LOCAL_OSC_4", "LOCAL_OSC_5", "LOCAL_OSC_6", "GENERAL"
+};
+#endif
+
+#if DEBUG_DUMP_REGISTERS
+static int zl10039_read(const struct zl10039_state *state,
+ const enum zl10039_reg_addr reg, u8 *buf,
+ const size_t count);
+
+static void zl10039_dump_registers(const struct zl10039_state *state)
+{
+ u8 buf[16];
+ int ret;
+ u8 reg;
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10039_read(state, PLL0, buf, sizeof(buf));
+ if (ret < 0) return;
+ for (reg = PLL0; reg <= GENERAL; reg += 4) {
+ printk(KERN_DEBUG "%03x: [%02x %13s] [%02x %13s] [%02x %13s] "
+ "[%02x %13s]\n", reg, buf[reg], zl10039_reg_names[reg],
+ buf[reg+1], zl10039_reg_names[reg+1], buf[reg+2],
+ zl10039_reg_names[reg+2], buf[reg+3],
+ zl10039_reg_names[reg+3]);
+ }
+}
+#else
+static inline void zl10039_dump_registers(const struct zl10039_state *state) {}
+#endif /* DEBUG_DUMP_REGISTERS */
+
+#endif /* DVB_FRONTENDS_ZL10039_PRIV */
+
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/zl10313.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/zl10313.c Sat Dec 29 15:51:31 2007 +0200
@@ -0,0 +1,569 @@
+/*
+ * Driver for Zarlink ZL10313 DVB-S demodulator
+ *
+ * Copyright 2007 Jan Daniël Louw <jd.louw at mweb.co.za>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/dvb/frontend.h>
+
+#include "dvb_frontend.h"
+#include "zl10313.h"
+#include "zl10313_priv.h"
+
+
+static int zl10313_read(const struct zl10313_state *state,
+ const enum zl10313_reg_addr reg,
+ u8 *buf, const size_t count)
+{
+ struct i2c_msg msg[2];
+ u8 regbuf[1] = { reg };
+ int i;
+
+ io_printk("%s\n", __FUNCTION__);
+ /* Write address to read */
+ msg[0].addr = state->config->demod_address;
+ msg[0].flags = 0;
+ msg[0].buf = regbuf;
+ msg[0].len = 1;
+ /* Read count bytes */
+ msg[1].addr = state->config->demod_address;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ eprintk("%s: i2c read error\n", __FUNCTION__);
+ return -EREMOTEIO;
+ }
+ for (i = 0; i < count; i++) {
+ io_printk("R[%s] = 0x%x\n", zl10313_reg_names[reg + i], buf[i]);
+ }
+ return 0;
+}
+
+static int zl10313_write(struct zl10313_state *state,
+ const enum zl10313_reg_addr reg, const void *src,
+ const size_t count)
+{
+ u8 buf[count + 1];
+ struct i2c_msg msg;
+ int i;
+
+ io_printk("%s\n", __FUNCTION__);
+ for (i = 0; i < count; i++) {
+ io_printk("R[%s] = 0x%x\n", zl10313_reg_names[reg + i], buf[i]);
+ }
+ buf[0] = reg;
+ memcpy(&buf[1], src, count);
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = count + 1;
+
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ eprintk("%s: i2c write error\n", __FUNCTION__);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static inline int zl10313_readreg(struct zl10313_state *state,
+ const enum zl10313_reg_addr reg, u8 *val)
+{
+ return zl10313_read(state, reg, val, 1);
+}
+
+static inline int zl10313_writereg(struct zl10313_state *state,
+ const enum zl10313_reg_addr reg, const u8 val)
+{
+ return zl10313_write(state, reg, &val, 1);
+}
+
+static inline u32 zl10313_div(u32 a, u32 b)
+{
+ return (a + (b / 2)) / b;
+}
+
+static int zl10313_read_status(struct dvb_frontend *fe, fe_status_t *s)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 status[3];
+
+ trace_printk("%s\n", __FUNCTION__);
+ *s = 0;
+ ret = zl10313_read(state, QPSK_STAT_H, status, sizeof(status));
+ if (ret < 0) return ret;
+ if (status[0] & 0xc0)
+ *s |= FE_HAS_SIGNAL; /* signal noise ratio */
+ if (status[0] & 0x04)
+ *s |= FE_HAS_CARRIER; /* qpsk carrier lock */
+ if (status[2] & 0x02)
+ *s |= FE_HAS_VITERBI; /* viterbi lock */
+ if (status[2] & 0x04)
+ *s |= FE_HAS_SYNC; /* byte align lock */
+ if (status[0] & 0x01)
+ *s |= FE_HAS_LOCK; /* qpsk lock */
+
+ return 0;
+}
+
+/* Reports only Reed-Solomon error count (Viterbi BER) */
+/* IMPROVEMENT: Implement Viterbi error count (QPSK BER), a bit of a problem
+ without IRQs? */
+/* Viterbi BER = RS_BERCNT / (dt * CR * 2 * SR) */
+static int zl10313_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 buf[3];
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_read(state, RS_BERCNT_H, buf, 3);
+ if (ret < 0) return ret;
+ *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]);
+ return 0;
+}
+
+/* Signal strength a number out of 1024 */
+static int zl10313_read_signal_strength(struct dvb_frontend *fe,
+ u16 * signal_strength)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 buf[3];
+ u16 agc;
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_read(state, AGC_H, buf, sizeof(buf));
+ if (ret < 0) return ret;
+ agc = (buf[0] << 2) | (buf[1] >> 6);
+ *signal_strength = agc;
+ return 0;
+}
+
+/* Holds for Eb/No between 0 and 12 dB */
+static int zl10313_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_read(state, M_SNR_H, buf, sizeof(buf));
+ if (ret < 0) return ret;
+ *snr = (13312 - (((buf[0] & 0x7f) << 8) | buf[1])) / 683;
+ return 0;
+}
+
+/* Block error rate = (ucblocks * 1632) / (dt * SR * 2 * CR) */
+static int zl10313_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_read(state, RS_UBC_H, buf, sizeof(buf));
+ if (ret < 0) return ret;
+ *ucblocks = (buf[0] << 8) | buf[1];
+ return 0;
+}
+
+static int zl10313_get_inversion(struct zl10313_state *state,
+ fe_spectral_inversion_t *i)
+{
+ int ret;
+ u8 vit_mode;
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_readreg(state, VIT_MODE, &vit_mode);
+ if (ret < 0) return ret;
+ *i = (vit_mode & 0x40) ? INVERSION_ON : INVERSION_OFF;
+ return 0;
+}
+
+static int zl10313_get_symbol_rate(struct zl10313_state *state, u32 *sr)
+{
+ int ret;
+ u16 monitor;
+ u8 buf[2];
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_writereg(state, MON_CTRL, 0x03);
+ if (ret < 0) return ret;
+ ret = zl10313_read(state, MONITOR_H, buf, sizeof(buf));
+ if (ret < 0) return ret;
+ monitor = (buf[0] << 8) | buf[1];
+ /* SR = monitor * 1000000 / 1024 */
+ *sr = zl10313_div(monitor * 15625, 16);
+ return 0;
+}
+
+static int zl10313_get_code_rate(struct zl10313_state *state,
+ fe_code_rate_t *cr)
+{
+ const fe_code_rate_t fec_tab[8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6,
+ FEC_6_7, FEC_7_8, FEC_AUTO, FEC_AUTO };
+ int ret;
+ u8 fec_status;
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_readreg(state, FEC_STATUS, &fec_status);
+ if (ret < 0) return ret;
+ *cr = fec_tab[(fec_status >> 4) & 0x07];
+ return 0;
+}
+
+static int zl10313_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_get_inversion(state, &p->inversion);
+ if (ret < 0) return ret;
+ ret = zl10313_get_symbol_rate(state, &p->u.qpsk.symbol_rate);
+ if (ret < 0) return ret;
+ ret = zl10313_get_code_rate(state, &p->u.qpsk.fec_inner);
+ if (ret < 0) return ret;
+ p->frequency = state->prev_frequency;
+ return 0;
+}
+
+static int zl10313_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 buf[5];
+ u16 sr;
+ const u8 fec_tab[10] = { 0x00, 0x01, 0x02, 0x04, 0x3f, 0x08, 0x10,
+ 0x20, 0x3f, 0x3f };
+ const u8 inv_tab[3] = { 0x00, 0x40, 0x80 };
+
+ trace_printk("%s\n", __FUNCTION__);
+ params_printk("Setting freq: %d, fec: %s, inversion: %s\n",
+ p->frequency, fec_str[p->u.qpsk.fec_inner],
+ inv_str[p->inversion]);
+
+ if ((p->frequency < fe->ops.info.frequency_min) ||
+ (p->frequency > fe->ops.info.frequency_max)) return -EINVAL;
+
+ if ((p->inversion < INVERSION_OFF) || (p->inversion > INVERSION_AUTO))
+ return -EINVAL;
+
+ if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+ (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
+ return -EINVAL;
+
+ if ((p->u.qpsk.fec_inner < FEC_NONE) ||
+ (p->u.qpsk.fec_inner > FEC_AUTO)) return -EINVAL;
+
+ if ((p->u.qpsk.fec_inner == FEC_4_5) ||
+ (p->u.qpsk.fec_inner == FEC_8_9)) return -EINVAL;
+
+ /* Set the tuner up first */
+ fe->ops.tuner_ops.set_params(fe, p);
+
+ /* sr = SR * 256 / 1000000 */
+ sr = zl10313_div(p->u.qpsk.symbol_rate * 4, 15625);
+ /* SYM_RATE */
+ buf[0] = (sr >> 8) & 0x3f;
+ buf[1] = (sr >> 0) & 0xff;
+ /* VIT_MODE */
+ buf[2] = inv_tab[p->inversion] | fec_tab[p->u.qpsk.fec_inner];
+ /* QPSK_CTRL */
+ buf[3] = 0x40; /* swap I and Q before QPSK demodulation */
+ if (p->u.qpsk.symbol_rate < 10000000)
+ buf[3] |= 0x04; /* use afc mode */
+ /* GO */
+ buf[4] = 0x01;
+
+ ret = zl10313_write(state, SYM_RATE_H, buf, sizeof(buf));
+ if (ret < 0) {
+ eprintk("Demodulator failed setup\n");
+ return ret;
+ }
+ state->prev_frequency = p->frequency;
+ zl10313_dump_registers(state);
+
+ return 0;
+}
+
+static int zl10313_sleep(struct dvb_frontend *fe)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 config;
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_readreg(state, CONFIG, &config);
+ if (ret < 0) return ret;
+ /* enter standby */
+ ret = zl10313_writereg(state, CONFIG, config & 0x7f);
+ if (ret < 0) return ret;
+ return 0;
+}
+
+static int zl10313_init(struct dvb_frontend *fe)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+
+ trace_printk("%s\n", __FUNCTION__);
+ /* Set up for QPSK DVB-S with 10MHz crystal ref */
+ ret = zl10313_writereg(state, CONFIG, 0x8c);
+ if (ret < 0) return ret;
+ /* Wait 150 us to settle */
+ udelay(150);
+ /* Full reset */
+ ret = zl10313_writereg(state, RESET, 0x80);
+ if (ret < 0) return ret;
+ /* Crucial for correct operation - differs from mt312 datasheet */
+ ret = zl10313_writereg(state, GPP_CTRL, 0x80);
+ if (ret < 0) return ret;
+ /* Crucial for correct operation - unknown register in zl10313 */
+ /* Don't know what this register is for in the zl10313 */
+ ret = zl10313_writereg(state, VIT_ERRPER_M, 0x00);
+ if (ret < 0) return ret;
+ buf[0] = 182;
+ buf[1] = zl10313_div(10111000, 88000);
+ /*Set DISECQ ratio for 22KHz tone */
+ ret = zl10313_write(state, SYS_CLK, buf, sizeof(buf));
+ if (ret < 0) return ret;
+ /* Supposed to set register 49 to value 50 - can't see any difference */
+ ret = zl10313_writereg(state, SNR_THS_HIGH, 50);
+ if (ret < 0) return ret;
+
+ zl10313_dump_registers(state);
+
+ return 0;
+}
+
+static int zl10313_send_master_cmd(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *c)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ int ret;
+ u8 diseqc_mode;
+
+ trace_printk("%s\n", __FUNCTION__);
+ if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) return -EINVAL;
+
+ ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+ if (ret < 0) return ret;
+
+ ret = zl10313_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len);
+ if (ret < 0) return ret;
+
+ ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) |
+ ((c->msg_len - 1) << 3) | 0x04);
+ if (ret < 0) return ret;
+
+ msleep(100);
+
+ /* set DISEQC_MODE[2:0] to zero if a return message is expected */
+ if (c->msg[0] & 0x02) {
+ ret = zl10313_writereg(state, DISEQC_MODE, diseqc_mode & 0x40);
+ if (ret < 0) return ret;
+ }
+ return 0;
+}
+
+static int zl10313_send_burst(struct dvb_frontend *fe,
+ const fe_sec_mini_cmd_t c)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ const u8 mini_tab[2] = { 0x02, 0x03 };
+ int ret;
+ u8 diseqc_mode;
+
+ trace_printk("%s\n", __FUNCTION__);
+ params_printk("Set mini burst %s (enum %d)\n", mini_cmd_name[c], c);
+ if (c > SEC_MINI_B) return -EINVAL;
+ ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+ if (ret < 0) return ret;
+ ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) |
+ mini_tab[c]);
+ if (ret < 0) return ret;
+ return 0;
+}
+
+static int zl10313_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ const u8 tone_tab[2] = { 0x01, 0x00 };
+ int ret;
+ u8 diseqc_mode;
+
+ trace_printk("%s\n", __FUNCTION__);
+ params_printk("Set tone %s (enum %d)\n", tone_name[tone], tone);
+ if (tone > SEC_TONE_OFF) return -EINVAL;
+ ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+ if (ret < 0) return ret;
+ ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40) |
+ tone_tab[tone]);
+ if (ret < 0) return ret;
+ return 0;
+}
+
+static int zl10313_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
+ int ret;
+ u8 diseqc_mode;
+
+ trace_printk("%s\n", __FUNCTION__);
+ params_printk("Set voltage %s (enum %d)\n", volt_name[voltage],
+ voltage);
+ if (voltage > SEC_VOLTAGE_OFF) return -EINVAL;
+ ret = zl10313_readreg(state, DISEQC_MODE, &diseqc_mode);
+ if (ret < 0) return ret;
+ ret = zl10313_writereg(state, DISEQC_MODE, (diseqc_mode & 0x07) |
+ volt_tab[voltage]);
+ if (ret < 0) return ret;
+ return 0;
+}
+
+static void zl10313_release(struct dvb_frontend *fe)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+
+ trace_printk("%s\n", __FUNCTION__);
+ kfree(state);
+}
+
+static int zl10313_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *fesettings)
+{
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+ return 0;
+}
+
+static int zl10313_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct zl10313_state *state = fe->demodulator_priv;
+ u8 gpp_ctrl;
+ int ret;
+
+ trace_printk("%s,\n", __FUNCTION__);
+ params_printk("Switching %d\n", enable);
+ ret = zl10313_readreg(state, GPP_CTRL, &gpp_ctrl);
+ if (ret < 0) return ret;
+ if (enable) {
+ return zl10313_writereg(state, GPP_CTRL, gpp_ctrl | 0x40);
+ } else {
+ return zl10313_writereg(state, GPP_CTRL, gpp_ctrl & ~0x40);
+ }
+}
+
+
+static struct dvb_frontend_ops zl10313_ops;
+
+struct dvb_frontend * zl10313_attach(const struct zl10313_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct zl10313_state *state = NULL;
+
+ trace_printk("%s\n", __FUNCTION__);
+
+ state = kmalloc(sizeof(struct zl10313_state), GFP_KERNEL);
+ if (state == NULL) goto error;
+
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->frontend.ops, &zl10313_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ /* check if this is a valid demodulator */
+ if (zl10313_readreg(state, ID, &state->id) < 0) goto error;
+
+ switch (state->id) {
+ case ID_ZL10313:
+ strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
+ break;
+ default:
+ eprintk("Chip ID does not match a known type\n");
+ goto error;
+ }
+ state->frontend.demodulator_priv = state;
+ iprintk("Demodulator attached @ i2c address 0x%02x\n",
+ config->demod_address);
+
+ zl10313_dump_registers(state);
+ return &state->frontend;
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops zl10313_ops = {
+
+ .info = {
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 |
+ FE_CAN_QPSK | FE_CAN_FEC_AUTO | FE_CAN_INVERSION_AUTO |
+ FE_CAN_RECOVER
+ },
+
+ .release = zl10313_release,
+
+ .init = zl10313_init,
+ .sleep = zl10313_sleep,
+
+ .set_frontend = zl10313_set_frontend,
+ .get_frontend = zl10313_get_frontend,
+ .get_tune_settings = zl10313_get_tune_settings,
+
+ .read_status = zl10313_read_status,
+ .read_ber = zl10313_read_ber,
+ .read_signal_strength = zl10313_read_signal_strength,
+ .read_snr = zl10313_read_snr,
+ .read_ucblocks = zl10313_read_ucblocks,
+
+ .diseqc_send_master_cmd = zl10313_send_master_cmd,
+ .diseqc_send_burst = zl10313_send_burst,
+ .set_voltage = zl10313_set_voltage,
+ .set_tone = zl10313_set_tone,
+ .i2c_gate_ctrl = zl10313_i2c_gate_ctrl,
+
+};
+
+MODULE_DESCRIPTION("Zarlink ZL10313 DVB-S demodulator driver");
+MODULE_AUTHOR("Jan Daniël Louw <jd.louw at mweb.co.za>");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(zl10313_attach);
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/zl10313.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/zl10313.h Sat Dec 29 14:12:24 2007 +0200
@@ -0,0 +1,47 @@
+/*
+ Driver for Zarlink ZL10313 DVB-S demodulator
+
+ Copyright (C) 2007 Jan Daniël Louw <jd.louw at mweb.co.za>
+
+ 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 ZL10313_H
+#define ZL10313_H
+
+
+struct zl10313_config
+{
+ /* demodulator's i2c address */
+ u8 demod_address;
+};
+
+
+#if defined(CONFIG_DVB_ZL10313) || (defined(CONFIG_DVB_ZL10313_MODULE) && \
+defined(MODULE))
+struct dvb_frontend * zl10313_attach(const struct zl10313_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend * zl10313_attach(
+ const struct zl10313_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_ZL10313 */
+
+#endif /* ZL10313_H */
diff -r f637ac5a5898 linux/drivers/media/dvb/frontends/zl10313_priv.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/drivers/media/dvb/frontends/zl10313_priv.h Sat Dec 29 16:09:33 2007 +0200
@@ -0,0 +1,274 @@
+/*
+ Driver for Zarlink ZL10313 DVB-S Frontend
+
+ Copyright (C) 2007 Jan Daniël Louw <jd.louw at mweb.co.za>
+
+ 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 DVB_FRONTENDS_ZL10313_PRIV
+#define DVB_FRONTENDS_ZL10313_PRIV
+
+/* Trace function calls */
+#define DEBUG_CALL_TRACE 0
+/* Trace read/write function calls - information overload */
+#define DEBUG_IO_TRACE 0
+/* Print register values at critical points */
+#define DEBUG_DUMP_REGISTERS 0
+/* Print important params passed to functions */
+#define DEBUG_PRINT_PARAMS 0
+
+#if DEBUG_CALL_TRACE
+ #define trace_printk(args...) printk(KERN_DEBUG "demodulator: " \
+ "zl10313: " args)
+#else
+ #define trace_printk(args...)
+#endif
+
+#if DEBUG_IO_TRACE
+ #define io_printk(args...) printk(KERN_DEBUG "demodulator: zl10313: " \
+ args)
+#else
+ #define io_printk(args...)
+#endif
+
+#if DEBUG_PRINT_PARAMS
+ #define params_printk(args...) printk(KERN_DEBUG \
+ "demodulator: zl10313: " args)
+#else
+ #define params_printk(args...)
+#endif
+
+#define eprintk(args...) printk(KERN_ERR "demodulator: zl10313: " args)
+#define iprintk(args...) printk(KERN_INFO "demodulator: zl10313: " args)
+
+enum zl10313_model_id {
+ ID_VP310 = 1,
+ ID_MT312 = 3,
+ ID_ZL10313 = 5
+};
+
+struct zl10313_state
+{
+ struct i2c_adapter *i2c;
+ const struct zl10313_config *config;
+ u8 id;
+ u32 prev_frequency; /* Store previously set frequency */
+ struct dvb_frontend frontend;
+};
+
+enum zl10313_reg_addr {
+ QPSK_INT_H = 0,
+ QPSK_INT_M = 1,
+ QPSK_INT_L = 2,
+ FEC_INT = 3,
+ QPSK_STAT_H = 4,
+ QPSK_STAT_L = 5,
+ FEC_STATUS = 6,
+ LNB_FREQ_H = 7,
+ LNB_FREQ_L = 8,
+ M_SNR_H = 9,
+ M_SNR_L = 10,
+ VIT_ERRCNT_H = 11,
+ VIT_ERRCNT_M = 12,
+ VIT_ERRCNT_L = 13,
+ RS_BERCNT_H = 14,
+ RS_BERCNT_M = 15,
+ RS_BERCNT_L = 16,
+ RS_UBC_H = 17,
+ RS_UBC_L = 18,
+ SIG_LEVEL = 19,
+ GPP_CTRL = 20,
+ RESET = 21,
+ DISEQC_MODE = 22,
+ SYM_RATE_H = 23,
+ SYM_RATE_L = 24,
+ VIT_MODE = 25,
+ QPSK_CTRL = 26,
+ GO = 27,
+ IE_QPSK_H = 28,
+ IE_QPSK_M = 29,
+ IE_QPSK_L = 30,
+ IE_FEC = 31,
+ QPSK_STAT_EN = 32,
+ FEC_STAT_EN = 33,
+ SYS_CLK = 34,
+ DISEQC_RATIO = 35,
+ DISEQC_INSTR = 36,
+ FR_LIM = 37,
+ FR_OFF = 38,
+ AGC_CTRL = 39,
+ AGC_INIT = 40,
+ AGC_REF = 41,
+ AGC_MAX = 42,
+ AGC_MIN = 43,
+ AGC_LK_TH = 44,
+ TS_AGC_LK_TH = 45,
+ AGC_PWR_SET = 46,
+ QPSK_MISC = 47,
+ SNR_THS_LOW = 48,
+ SNR_THS_HIGH = 49,
+ TS_SW_RATE = 50,
+ TS_SW_LIM_L = 51,
+ TS_SW_LIM_H = 52,
+ CS_SW_RATE_1 = 53,
+ CS_SW_RATE_2 = 54,
+ CS_SW_RATE_3 = 55,
+ CS_SW_RATE_4 = 56,
+ CS_SW_LIM = 57,
+ TS_LPK = 58,
+ TS_LPK_M = 59,
+ TS_LPK_L = 60,
+ CS_KPROP_H = 61,
+ CS_KPROP_L = 62,
+ CS_KINT_H = 63,
+ CS_KINT_L = 64,
+ QPSK_SCALE = 65,
+ TLD_OUTCLK_TH = 66,
+ TLD_INCLK_TH = 67,
+ FLD_TH = 68,
+ PLD_OUTLK3 = 69,
+ PLD_OUTLK2 = 70,
+ PLD_OUTLK1 = 71,
+ PLD_OUTLK0 = 72,
+ PLD_INLK3 = 73,
+ PLD_INLK2 = 74,
+ PLD_INLK1 = 75,
+ PLD_INLK0 = 76,
+ PLD_ACC_TIME = 77,
+ SWEEP_PAR = 78,
+ STARTUP_TIME = 79,
+ LOSSLOCK_TH = 80,
+ FEC_LOCK_TM = 81,
+ LOSSLOCK_TM = 82,
+ VIT_ERRPER_H = 83,
+ VIT_ERRPER_M = 84,
+ VIT_ERRPER_L = 85,
+ VIT_SETUP = 86,
+ VIT_REF0 = 87,
+ VIT_REF1 = 88,
+ VIT_REF2 = 89,
+ VIT_REF3 = 90,
+ VIT_REF4 = 91,
+ VIT_REF5 = 92,
+ VIT_REF6 = 93,
+ VIT_MAXERR = 94,
+ BA_SETUPT = 95,
+ OP_CTRL = 96,
+ FEC_SETUP = 97,
+ PROG_SYNC = 98,
+ AFC_SEAR_TH = 99,
+ CSACC_DIF_TH = 100,
+ QPSK_LK_CT = 101,
+ QPSK_ST_CT = 102,
+ MON_CTRL = 103,
+ QPSK_RESET = 104,
+ QPSK_TST_CT = 105,
+ QPSK_TST_ST = 106,
+ TEST_R = 107,
+ AGC_H = 108,
+ AGC_M = 109,
+ AGC_L = 110,
+ FREQ_ERR1_H = 111,
+ FREQ_ERR1_M = 112,
+ FREQ_ERR1_L = 113,
+ FREQ_ERR2_H = 114,
+ FREQ_ERR2_L = 115,
+ SYM_RAT_OP_H = 116,
+ SYM_RAT_OP_L = 117,
+ DESEQC2_INT = 118,
+ DISEQC2_STAT = 119,
+ DISEQC2_FIFO = 120,
+ DISEQC2_CTRL1 = 121,
+ DISEQC2_CTRL2 = 122,
+ MONITOR_H = 123,
+ MONITOR_L = 124,
+ TEST_MODE = 125,
+ ID = 126,
+ CONFIG = 127
+};
+
+
+#if DEBUG_PRINT_PARAMS
+ static const char *inv_str[] = {"OFF", "ON", "AUTO"};
+ static const char *fec_str[] = {"NONE", "1/2", "2/3", "3/4", "4/5",
+ "5/6", "6/7", "7/8", "8/9", "AUTO"};
+ static const char *mini_cmd_name[] = {"SEC_MINI_A", "SEC_MINI_B"};
+ static const char *tone_name[] = {"SEC_TONE_ON", "SEC_TONE_OFF"};
+ static const char *volt_name[] = {"SEC_VOLTAGE_13", "SEC_VOLTAGE_18",
+ "SEC_VOLTAGE_OFF"};
+#endif
+
+#if DEBUG_DUMP_REGISTERS || DEBUG_IO_TRACE
+static const char *zl10313_reg_names[] = {
+ "QPSK_INT_H", "QPSK_INT_M", "QPSK_INT_L", "FEC_INT", "QPSK_STAT_H",
+ "QPSK_STAT_L", "FEC_STATUS", "LNB_FREQ_H", "LNB_FREQ_L", "M_SNR_H",
+ "M_SNR_L", "VIT_ERRCNT_H", "VIT_ERRCNT_M", "VIT_ERRCNT_L",
+ "RS_BERCNT_H", "RS_BERCNT_M", "RS_BERCNT_L", "RS_UBC_H", "RS_UBC_L",
+ "SIG_LEVEL", "GPP_CTRL", "RESET", "DISEQC_MODE", "SYM_RATE_H",
+ "SYM_RATE_L", "VIT_MODE", "QPSK_CTRL", "GO", "IE_QPSK_H", "IE_QPSK_M",
+ "IE_QPSK_L", "IE_FEC", "QPSK_STAT_EN", "FEC_STAT_EN", "SYS_CLK",
+ "DISEQC_RATIO", "DISEQC_INSTR", "FR_LIM", "FR_OFF", "AGC_CTRL",
+ "AGC_INIT", "AGC_REF", "AGC_MAX", "AGC_MIN", "AGC_LK_TH",
+ "TS_AGC_LK_TH", "AGC_PWR_SET", "QPSK_MISC", "SNR_THS_LOW",
+ "SNR_THS_HIGH", "TS_SW_RATE", "TS_SW_LIM_L", "TS_SW_LIM_H",
+ "CS_SW_RATE_1", "CS_SW_RATE_2", "CS_SW_RATE_3", "CS_SW_RATE_4",
+ "CS_SW_LIM", "TS_LPK", "TS_LPK_M", "TS_LPK_L", "CS_KPROP_H",
+ "CS_KPROP_L", "CS_KINT_H", "CS_KINT_L", "QPSK_SCALE", "TLD_OUTCLK_TH",
+ "TLD_INCLK_TH", "FLD_TH", "PLD_OUTLK3", "PLD_OUTLK2", "PLD_OUTLK1",
+ "PLD_OUTLK0", "PLD_INLK3", "PLD_INLK2", "PLD_INLK1", "PLD_INLK0",
+ "PLD_ACC_TIME", "SWEEP_PAR", "STARTUP_TIME", "LOSSLOCK_TH",
+ "FEC_LOCK_TM", "LOSSLOCK_TM", "VIT_ERRPER_H", "VIT_ERRPER_M",
+ "VIT_ERRPER_L", "VIT_SETUP", "VIT_REF0", "VIT_REF1", "VIT_REF2",
+ "VIT_REF3", "VIT_REF4", "VIT_REF5", "VIT_REF6", "VIT_MAXERR",
+ "BA_SETUPT", "OP_CTRL", "FEC_SETUP", "PROG_SYNC", "AFC_SEAR_TH",
+ "CSACC_DIF_TH", "QPSK_LK_CT", "QPSK_ST_CT", "MON_CTRL", "QPSK_RESET",
+ "QPSK_TST_CT", "QPSK_TST_ST", "TEST_R", "AGC_H", "AGC_M", "AGC_L",
+ "FREQ_ERR1_H", "FREQ_ERR1_M", "FREQ_ERR1_L", "FREQ_ERR2_H",
+ "FREQ_ERR2_L", "SYM_RAT_OP_H", "SYM_RAT_OP_L", "DESEQC2_INT",
+ "DISEQC2_STAT", "DISEQC2_FIFO", "DISEQC2_CTRL1", "DISEQC2_CTRL2",
+ "MONITOR_H", "MONITOR_L", "TEST_MODE", "ID", "CONFIG", ""
+};
+#endif
+
+#if DEBUG_DUMP_REGISTERS
+static int zl10313_read(const struct zl10313_state *state,
+ const enum zl10313_reg_addr reg, u8 *buf,
+ const size_t count);
+
+static void zl10313_dump_registers(const struct zl10313_state *state)
+{
+ int ret;
+ u8 buf[128];
+ u8 reg ;
+
+ trace_printk("%s\n", __FUNCTION__);
+ ret = zl10313_read(state, QPSK_INT_H, buf, sizeof(buf));
+ if (ret < 0) return;
+ for (reg = QPSK_INT_H; reg <= CONFIG; reg += 4) {
+ printk(KERN_DEBUG "%03x: [%02x %13s] [%02x %13s] [%02x %13s] "
+ "[%02x %13s]\n", reg, buf[reg], zl10313_reg_names[reg],
+ buf[reg+1], zl10313_reg_names[reg+1], buf[reg+2],
+ zl10313_reg_names[reg+2], buf[reg+3],
+ zl10313_reg_names[reg+3]);
+ }
+}
+#else
+static inline void zl10313_dump_registers(const struct zl10313_state *state) {}
+#endif /* DEBUG_DUMP_REGISTERS */
+
+#endif /* DVB_FRONTENDS_ZL10313_PRIV */
diff -r f637ac5a5898 linux/drivers/media/video/saa7134/Kconfig
--- a/linux/drivers/media/video/saa7134/Kconfig Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/video/saa7134/Kconfig Fri Dec 28 17:41:56 2007 +0200
@@ -37,6 +37,8 @@ config VIDEO_SAA7134_DVB
select DVB_TDA826X if !DVB_FE_CUSTOMISE
select DVB_TDA827X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10313 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10039 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff -r f637ac5a5898 linux/drivers/media/video/saa7134/saa7134-cards.c
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c Fri Dec 28 15:34:49 2007 +0200
@@ -3601,6 +3601,26 @@ struct saa7134_board saa7134_boards[] =
.tv = 1,
}},
},
+ [SAA7134_BOARD_VIDEOMATE_S350] = {
+ /* Jan Daniël Louw <jd.louw at mweb.co.za */
+ .name = "Compro VideoMate S350/S300",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8, /* Not tested */
+ .amux = LINE1
+ }},
+ },
+
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4371,6 +4391,12 @@ struct pci_device_id saa7134_pci_tbl[] =
.subvendor = 0x4e42,
.subdevice = 0x3502,
.driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_S350,
},{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
@@ -4624,6 +4650,11 @@ int saa7134_board_init1(struct saa7134_d
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00008000, 0x00008000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00008000, 0x00008000);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
}
return 0;
}
diff -r f637ac5a5898 linux/drivers/media/video/saa7134/saa7134-dvb.c
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c Sat Dec 29 15:58:59 2007 +0200
@@ -38,6 +38,8 @@
#include "mt352_priv.h" /* FIXME */
#include "tda1004x.h"
#include "nxt200x.h"
+#include "zl10313.h"
+#include "zl10039.h"
#include "tda10086.h"
#include "tda826x.h"
@@ -841,6 +843,17 @@ static struct nxt200x_config kworldatsc1
};
/* ==================================================================
+ * ZL10313 based DVB-S cards
+ */
+static struct zl10313_config zl10313_compro_s350_config = {
+ .demod_address = 0x0E,
+};
+
+static struct zl10039_config zl10039_compro_s350_config = {
+ .tuner_address = 0x60
+};
+
+/* ==================================================================
* Core code
*/
@@ -1044,6 +1057,15 @@ static int dvb_init(struct saa7134_dev *
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
configure_tda827x_fe(dev, &avermedia_super_007_config);
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ dev->dvb.frontend = dvb_attach(zl10313_attach,
+ &zl10313_compro_s350_config, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend = dvb_attach(zl10039_attach,
+ dev->dvb.frontend, &zl10039_compro_s350_config,
+ &dev->i2c_adap);
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff -r f637ac5a5898 linux/drivers/media/video/saa7134/saa7134-input.c
--- a/linux/drivers/media/video/saa7134/saa7134-input.c Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c Fri Dec 28 15:44:52 2007 +0200
@@ -352,6 +352,11 @@ int saa7134_input_init1(struct saa7134_d
mask_keyup = 0x8000000;
polling = 50; //ms
break;
+ case SAA7134_BOARD_VIDEOMATE_S350:
+ ir_codes = ir_codes_videomate_s350;
+ mask_keycode = 0x003F00;
+ mask_keydown = 0x040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff -r f637ac5a5898 linux/drivers/media/video/saa7134/saa7134.h
--- a/linux/drivers/media/video/saa7134/saa7134.h Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/drivers/media/video/saa7134/saa7134.h Fri Dec 28 15:48:46 2007 +0200
@@ -247,6 +247,7 @@ struct saa7134_format {
#define SAA7134_BOARD_SABRENT_TV_PCB05 115
#define SAA7134_BOARD_10MOONSTVMASTER3 116
#define SAA7134_BOARD_AVERMEDIA_SUPER_007 117
+#define SAA7134_BOARD_VIDEOMATE_S350 118
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
diff -r f637ac5a5898 linux/include/media/ir-common.h
--- a/linux/include/media/ir-common.h Fri Dec 28 00:32:41 2007 -0200
+++ b/linux/include/media/ir-common.h Fri Dec 28 15:55:36 2007 +0200
@@ -140,6 +140,7 @@ extern IR_KEYTAB_TYPE ir_codes_encore_en
extern IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_videomate_s350[IR_KEYTAB_SIZE];
#endif
More information about the linux-dvb
mailing list