Hi List, Attached is a new driver for the Zarlink ZL10313/ZL10039 based ComproS350/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.odiff -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@xxxxxxxxxx>+ *+ * 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@xxxxxxxxxx>");+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@xxxxxxxxxx>++ 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@xxxxxxxxxx>+ *+ * 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@xxxxxxxxxx>+ *+ * 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@xxxxxxxxxx>");+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@xxxxxxxxxx>++ 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@xxxxxxxxxx>++ 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@xxxxxxxxxx */+ .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 8diff -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 _______________________________________________linux-dvb mailing listlinux-dvb@xxxxxxxxxxxxxxx://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb